Files
iris-context/root/config_cmd.go
T
Ashvin Singh dfaa051f31 fix: make Right Arrow configurable and correct overlay positioning (#110)
## Summary

Closes #108

This PR fixes two issues related to terminal interaction and rendering:

- Make Right Arrow ghost acceptance configurable instead of hard-coded.
- Correct overlay positioning when the shell prompt wraps across
terminal lines.

## Changes

### Right Arrow configuration

- Add a new `navigate-right` keybinding to the configuration.
- Add `navigate-right = "right"` to the default configuration to
preserve existing behavior.
- Update the wrapper to use the configured binding instead of a
hard-coded Right Arrow check.
- Forward the Right Arrow escape sequence to the PTY when
`navigate-right` is unset, allowing the shell or terminal to handle it
normally.

### Overlay positioning

- Compute the cursor's current column from the total visual width
instead of using the accumulated width directly.
- Correctly handle wrapped prompts by calculating the cursor column
modulo the terminal width.
- Clamp the overlay position so it never extends beyond the terminal
width.
- Extend debug logging with the computed cursor position to aid
troubleshooting.

## Why

Right Arrow ghost acceptance was previously implemented as a hard-coded
behavior, making it impossible to disable or remap through
configuration. This change makes it consistent with the existing
configurable keybindings while preserving the default behavior.

Overlay positioning assumed that the prompt length represented the
cursor's current column. When the prompt wrapped onto a new terminal
line, this assumption caused the suggestion overlay to be positioned
incorrectly. Computing the cursor column from the wrapped position
ensures the overlay is aligned with the actual cursor.

## Testing

- [x] Default configuration retains Right Arrow ghost acceptance.
- [x] Setting `navigate-right = ""` forwards Right Arrow to the shell.
- [x] Existing keybindings continue to function as before.
- [x] Overlay is correctly positioned for both short and wrapped
prompts.
- [x] Overlay remains within terminal bounds.
2026-08-03 18:48:53 +07:00

134 lines
2.8 KiB
Go

package root
import (
"fmt"
"os"
"path/filepath"
"github.com/BurntSushi/toml"
"github.com/spf13/cobra"
"github.com/versenilvis/iris/internal/config"
)
var ConfigCmd = &cobra.Command{
Use: "config",
Short: "manage iris configuration",
}
var ConfigInitCmd = &cobra.Command{
Use: "init",
Short: "initialize default configuration file with comments",
Run: func(cmd *cobra.Command, args []string) {
path, err := config.ConfigPath()
if err != nil {
fmt.Printf("failed to get config path: %v\n", err)
return
}
if _, statErr := os.Stat(path); statErr == nil {
fmt.Printf("config file already exists at %s\n", path)
return
}
_ = os.MkdirAll(filepath.Dir(path), 0755)
defaultContent := `# ~/.config/iris/config.toml
# iris configuration file
[core]
# schema version
# do not edit this field manually
version = 1
# override shell: "bash", "zsh", "fish", keep empty for auto detection
shell = ""
# run the selected shell as a login shell
shell-login = false
# startup mode: "last", "spec", "history"
# "last" = remember last mode used
mode = "last"
# enable debug logging
debug = false
# automatically expand aliases on space
expand-alias = true
# automatically execute command after accepting suggestion
auto-execute = false
[ui]
# visual style: "modern" (icons, category pills, shortcut footer) or "classic" (minimalist, centered number, no icons)
style = "modern"
# enable Nerd Fonts icons in overlay menu
nerd-fonts = true
# show hidden files with dot prefix
hidden-files = false
# enable inline ghost text
ghost-text = true
# maximum suggestions to display
max-suggestions = 100
# maximum height of the overlay
max-height = 15
# maximum width of the overlay (0 = responsive to terminal)
max-width = 0
[git]
# hide current branch in checkout/switch list
filter-active-branch = true
# merge remote and local branches with same name
deduplicate-branches = true
[updater]
# check for updates on startup
check-on-startup = true
# update channel: "stable", "nightly"
channel = "stable"
# interval between update checks, e.g. "24h", "6h", "30m"
check-interval = "24h"
[keybindings]
toggle-mode = "ctrl+r"
toggle-menu = "shift+tab"
select = "tab"
navigate-up = "up"
navigate-down = "down"
navigate-right = "right"
`
err = os.WriteFile(path, []byte(defaultContent), 0644)
if err != nil {
fmt.Printf("failed to write config file: %v\n", err)
return
}
fmt.Printf("initialized config file at %s\n", path)
},
}
var ConfigShowCmd = &cobra.Command{
Use: "show",
Short: "show the resolved configuration",
Run: func(cmd *cobra.Command, args []string) {
enc := toml.NewEncoder(cmd.OutOrStdout())
if err := enc.Encode(config.Get()); err != nil {
fmt.Fprintf(cmd.ErrOrStderr(), "failed to encode config: %v\n", err)
}
},
}
func init() {
ConfigCmd.AddCommand(ConfigInitCmd)
ConfigCmd.AddCommand(ConfigShowCmd)
rootCmd.AddCommand(ConfigCmd)
}