chore: change open editor

Kujtim Hoxha created

Change summary

internal/tui/components/chat/editor/editor.go        | 12 ++++++++++
internal/tui/components/chat/editor/keys.go          |  4 +-
internal/tui/components/dialogs/commands/commands.go | 16 ++++++++++++++
internal/tui/page/chat/chat.go                       | 13 +++++++++-
internal/tui/tui.go                                  |  3 ++
5 files changed, 44 insertions(+), 4 deletions(-)

Detailed changes

internal/tui/components/chat/editor/editor.go 🔗

@@ -22,6 +22,7 @@ import (
 	"github.com/charmbracelet/crush/internal/tui/components/completions"
 	"github.com/charmbracelet/crush/internal/tui/components/core/layout"
 	"github.com/charmbracelet/crush/internal/tui/components/dialogs"
+	"github.com/charmbracelet/crush/internal/tui/components/dialogs/commands"
 	"github.com/charmbracelet/crush/internal/tui/components/dialogs/filepicker"
 	"github.com/charmbracelet/crush/internal/tui/components/dialogs/quit"
 	"github.com/charmbracelet/crush/internal/tui/styles"
@@ -38,6 +39,7 @@ type Editor interface {
 
 	SetSession(session session.Session) tea.Cmd
 	IsCompletionsOpen() bool
+	HasAttachments() bool
 	Cursor() *tea.Cursor
 }
 
@@ -206,6 +208,12 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 				m.completionsStartIndex = 0
 			}
 		}
+
+	case commands.OpenExternalEditorMsg:
+		if m.app.CoderAgent.IsSessionBusy(m.session.ID) {
+			return m, util.ReportWarn("Agent is working, please wait...")
+		}
+		return m, m.openEditor(m.textarea.Value())
 	case OpenEditorMsg:
 		m.textarea.SetValue(msg.Text)
 		m.textarea.MoveToEnd()
@@ -482,6 +490,10 @@ func (c *editorCmp) IsCompletionsOpen() bool {
 	return c.isCompletionsOpen
 }
 
+func (c *editorCmp) HasAttachments() bool {
+	return len(c.attachments) > 0
+}
+
 func New(app *app.App) Editor {
 	t := styles.CurrentTheme()
 	ta := textarea.New()

internal/tui/components/chat/editor/keys.go 🔗

@@ -22,8 +22,8 @@ func DefaultEditorKeyMap() EditorKeyMap {
 			key.WithHelp("enter", "send"),
 		),
 		OpenEditor: key.NewBinding(
-			key.WithKeys("ctrl+v"),
-			key.WithHelp("ctrl+v", "open editor"),
+			key.WithKeys("ctrl+o"),
+			key.WithHelp("ctrl+o", "open editor"),
 		),
 		Newline: key.NewBinding(
 			key.WithKeys("shift+enter", "ctrl+j"),

internal/tui/components/dialogs/commands/commands.go 🔗

@@ -1,6 +1,8 @@
 package commands
 
 import (
+	"os"
+
 	"github.com/charmbracelet/bubbles/v2/help"
 	"github.com/charmbracelet/bubbles/v2/key"
 	tea "github.com/charmbracelet/bubbletea/v2"
@@ -66,6 +68,7 @@ type (
 	ToggleHelpMsg        struct{}
 	ToggleCompactModeMsg struct{}
 	ToggleThinkingMsg    struct{}
+	OpenExternalEditorMsg struct{}
 	CompactMsg           struct {
 		SessionID string
 	}
@@ -343,6 +346,19 @@ func (c *commandDialogCmp) defaultCommands() []Command {
 		}
 	}
 
+	// Add external editor command if $EDITOR is available
+	if os.Getenv("EDITOR") != "" {
+		commands = append(commands, Command{
+			ID:          "open_external_editor",
+			Title:       "Open External Editor",
+			Shortcut:    "ctrl+o",
+			Description: "Open external editor to compose message",
+			Handler: func(cmd Command) tea.Cmd {
+				return util.CmdHandler(OpenExternalEditorMsg{})
+			},
+		})
+	}
+
 	return append(commands, []Command{
 		{
 			ID:          "toggle_help",

internal/tui/page/chat/chat.go 🔗

@@ -204,6 +204,10 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		return p, tea.Batch(p.SetSize(p.width, p.height), cmd)
 	case commands.ToggleThinkingMsg:
 		return p, p.toggleThinking()
+	case commands.OpenExternalEditorMsg:
+		u, cmd := p.editor.Update(msg)
+		p.editor = u.(editor.Editor)
+		return p, cmd
 	case pubsub.Event[session.Session]:
 		u, cmd := p.header.Update(msg)
 		p.header = u.(header.Header)
@@ -896,9 +900,13 @@ func (p *chatPage) Help() help.KeyMap {
 						key.WithHelp("/", "add file"),
 					),
 					key.NewBinding(
-						key.WithKeys("ctrl+v"),
-						key.WithHelp("ctrl+v", "open editor"),
+						key.WithKeys("ctrl+o"),
+						key.WithHelp("ctrl+o", "open editor"),
 					),
+				})
+
+			if p.editor.HasAttachments() {
+				fullList = append(fullList, []key.Binding{
 					key.NewBinding(
 						key.WithKeys("ctrl+r"),
 						key.WithHelp("ctrl+r+{i}", "delete attachment at index i"),
@@ -912,6 +920,7 @@ func (p *chatPage) Help() help.KeyMap {
 						key.WithHelp("esc", "cancel delete mode"),
 					),
 				})
+			}
 		}
 		shortList = append(shortList,
 			// Quit

internal/tui/tui.go 🔗

@@ -3,6 +3,7 @@ package tui
 import (
 	"context"
 	"fmt"
+	"log/slog"
 	"strings"
 	"time"
 
@@ -258,6 +259,8 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		return a, tea.Batch(cmds...)
 	// Key Press Messages
 	case tea.KeyPressMsg:
+
+		slog.Info("TUI Update", "msg", msg, "key", msg.String())
 		return a, a.handleKeyPressMsg(msg)
 
 	case tea.MouseWheelMsg: