From 65ca7663c1cf434ba749268aaa4a794a173cb913 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Tue, 2 Dec 2025 13:13:13 +0000 Subject: [PATCH] wip: fiddle with inferring cursor position in text area --- internal/tui/components/chat/editor/editor.go | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/internal/tui/components/chat/editor/editor.go b/internal/tui/components/chat/editor/editor.go index 37d7ec1704734ef99962b735008c7bb28997e9f8..c51dc3beb76a9c65b3ab6a5f97d191cb438a2059 100644 --- a/internal/tui/components/chat/editor/editor.go +++ b/internal/tui/components/chat/editor/editor.go @@ -217,6 +217,7 @@ func (m *editorCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) { if m.inHistoryMode() { m.history.ScrollUp() m.textarea.SetValue(m.history.Value()) + m.textarea.CursorStart() } case ScrollHistoryDown: if m.inHistoryMode() { @@ -312,20 +313,18 @@ func (m *editorCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) { curIdx := m.textarea.Width()*cur.Y + cur.X // history - if m.inHistoryMode() { + if m.textarea.Focused() && m.inHistoryMode() { switch true { case key.Matches(msg, m.keyMap.Escape): return m, util.CmdHandler(CloseHistoryMsg{valueToSet: m.history.ExistingValue()}) - case key.Matches(msg, m.keyMap.Previous): - return m, util.CmdHandler(ScrollHistoryUp{}) - case key.Matches(msg, m.keyMap.Next): - return m, util.CmdHandler(ScrollHistoryDown{}) } // if any key other than history related controls we play it safe and close // the history and reset the text input field to be the current value - cmds = append(cmds, util.CmdHandler(CloseHistoryMsg{ - valueToSet: m.textarea.Value(), - })) + if !key.Matches(msg, m.keyMap.Previous) && !key.Matches(msg, m.keyMap.Next) { + cmds = append(cmds, util.CmdHandler(CloseHistoryMsg{ + valueToSet: m.textarea.Value(), + })) + } } switch { @@ -355,16 +354,27 @@ func (m *editorCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) { m.attachments = nil return m, nil } - if key.Matches(msg, m.keyMap.Previous) || key.Matches(msg, m.keyMap.Next) { - if !m.inHistoryMode() { - cmds = append(cmds, util.CmdHandler(LoadHistoryMsg{})) - } else { - if key.Matches(msg, m.keyMap.Previous) { - cmds = append(cmds, util.CmdHandler(ScrollHistoryUp{})) - } else if key.Matches(msg, m.keyMap.Next) { - cmds = append(cmds, util.CmdHandler(ScrollHistoryDown{})) - } + if m.textarea.Focused() && key.Matches(msg, m.keyMap.Previous) || key.Matches(msg, m.keyMap.Next) { + switch true { + case key.Matches(msg, m.keyMap.Previous): + cmds = append(cmds, m.handlePreviousKeypressSideEffect()...) + // if cursor is on top line move cursor to start of line + // if cursor is at start of line already, then scroll history up + case key.Matches(msg, m.keyMap.Next): + cmds = append(cmds, m.handleNextKeypressSideEffect()...) } + /* + if m.textarea.LineCount() + if !m.inHistoryMode() { + cmds = append(cmds, util.CmdHandler(LoadHistoryMsg{})) + } else { + if key.Matches(msg, m.keyMap.Previous) { + cmds = append(cmds, util.CmdHandler(ScrollHistoryUp{})) + } else if key.Matches(msg, m.keyMap.Next) { + cmds = append(cmds, util.CmdHandler(ScrollHistoryDown{})) + } + } + */ } rune := msg.Code if m.deleteMode && unicode.IsDigit(rune) { @@ -447,6 +457,33 @@ func (m *editorCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) { return m, tea.Batch(cmds...) } +func (m *editorCmp) handlePreviousKeypressSideEffect() []tea.Cmd { + cmds := []tea.Cmd{} + lineInfo := m.textarea.LineInfo() + + // Check if cursor is on the first row (actual line in the buffer) + if m.textarea.Line() == 0 { + // On the first row - check if we're at the start + if lineInfo.RowOffset == 0 && lineInfo.ColumnOffset == 0 { + // Already at the very start of the textarea - emit your event + if !m.inHistoryMode() { + cmds = append(cmds, util.CmdHandler(LoadHistoryMsg{})) + } + cmds = append(cmds, util.CmdHandler(ScrollHistoryUp{})) + } else { + // On first row but not at start - jump to start + m.textarea.CursorStart() + } + } + + return cmds +} + +func (m *editorCmp) handleNextKeypressSideEffect() []tea.Cmd { + cmds := []tea.Cmd{} + return cmds +} + func (m *editorCmp) setEditorPrompt() { if m.app.Permissions.SkipRequests() { m.textarea.SetPromptFunc(4, yoloPromptFunc)