From 673956eeefe0f91045651dc922b56b496f553e97 Mon Sep 17 00:00:00 2001 From: Erik Loualiche Date: Wed, 18 Mar 2026 21:07:01 -0500 Subject: [PATCH] feat: split config editor into e ($EDITOR) and E ($VISUAL) keybindings The TUI now uses $EDITOR (terminal editor) by default for 'e', so editors like Helix work correctly instead of falling through to $VISUAL (BBEdit). Shift-E opens the config in $VISUAL for GUI editing. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/tui/app.go | 17 +++++++++++------ internal/tui/dashboard.go | 4 +++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/internal/tui/app.go b/internal/tui/app.go index e2dbcf8..b660cb4 100644 --- a/internal/tui/app.go +++ b/internal/tui/app.go @@ -32,7 +32,8 @@ type OpenFileMsg struct{ Path string } type editorFinishedMsg struct{ err error } // EditConfigMsg signals that the user wants to edit the config file. -type EditConfigMsg struct{} +// Visual selects $VISUAL (GUI editor) instead of $EDITOR (terminal editor). +type EditConfigMsg struct{ Visual bool } // editorConfigFinishedMsg is sent when the config editor exits. type editorConfigFinishedMsg struct{ err error } @@ -197,7 +198,7 @@ func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { targetPath = tmpFile.Name() } - editor := resolveEditor() + editor := resolveEditor(msg.Visual) c := exec.Command(editor, targetPath) return m, tea.ExecProcess(c, func(err error) tea.Msg { return editorConfigFinishedMsg{err} @@ -338,10 +339,14 @@ func (m AppModel) listenLogEntries() tea.Cmd { // Helpers // --------------------------------------------------------------------------- -// resolveEditor returns the user's preferred editor: $VISUAL, $EDITOR, or "vi". -func resolveEditor() string { - if e := os.Getenv("VISUAL"); e != "" { - return e +// resolveEditor returns the user's preferred editor. +// When visual is true it checks $VISUAL first (GUI editor like BBEdit); +// otherwise it uses $EDITOR (terminal editor like Helix), falling back to "vi". +func resolveEditor(visual bool) string { + if visual { + if e := os.Getenv("VISUAL"); e != "" { + return e + } } if e := os.Getenv("EDITOR"); e != "" { return e diff --git a/internal/tui/dashboard.go b/internal/tui/dashboard.go index be62e4a..d6ad17e 100644 --- a/internal/tui/dashboard.go +++ b/internal/tui/dashboard.go @@ -207,6 +207,8 @@ func (m DashboardModel) updateNormal(msg tea.KeyMsg) (DashboardModel, tea.Cmd) { return m, func() tea.Msg { return OpenFileMsg{Path: path} } case "e": return m, func() tea.Msg { return EditConfigMsg{} } + case "E": + return m, func() tea.Msg { return EditConfigMsg{Visual: true} } case "/": m.filtering = true m.filter = "" @@ -376,7 +378,7 @@ func (m DashboardModel) View() string { helpKey("↑↓") + helpDesc("navigate") + helpKey("enter") + helpDesc("expand") + helpKey("v") + helpDesc("view") + - helpKey("e") + helpDesc("config") + + helpKey("e/E") + helpDesc("config") + helpKey("l") + helpDesc("logs") + helpKey("/") + helpDesc("filter") if m.filter != "" {