feat: add command history navigation

bashbunni created

Change summary

internal/tui/components/chat/editor/editor.go | 48 +++++++++++++++++++++
internal/tui/components/chat/editor/keys.go   | 10 ++++
2 files changed, 58 insertions(+)

Detailed changes

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

@@ -67,6 +67,9 @@ type editorCmp struct {
 	currentQuery          string
 	completionsStartIndex int
 	isCompletionsOpen     bool
+
+	// History
+	promptHistoryIndex int
 }
 
 var DeleteKeyMaps = DeleteAttachmentKeyMaps{
@@ -314,6 +317,10 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			m.textarea.InsertRune('\n')
 			cmds = append(cmds, util.CmdHandler(completions.CloseCompletionsMsg{}))
 		}
+		// History
+		if key.Matches(msg, m.keyMap.Previous) || key.Matches(msg, m.keyMap.Next) {
+			m.textarea.SetValue(m.handleMessageHistory(msg))
+		}
 		// Handle Enter key
 		if m.textarea.Focused() && key.Matches(msg, m.keyMap.SendMessage) {
 			value := m.textarea.Value()
@@ -560,3 +567,44 @@ func New(app *app.App) Editor {
 
 	return e
 }
+
+func (m *editorCmp) getUserMessagesAsText(ctx context.Context) ([]string, error) {
+	allMessages, err := m.app.Messages.List(ctx, m.session.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	var userMessages []string
+	for _, msg := range allMessages {
+		if msg.Role == message.User {
+			userMessages = append(userMessages, msg.Content().Text)
+		}
+	}
+	return userMessages, nil
+}
+
+func (m *editorCmp) handleMessageHistory(msg tea.KeyMsg) string {
+	ctx := context.Background()
+	userMessages, err := m.getUserMessagesAsText(ctx)
+	if err != nil {
+		return "" // Do nothing.
+	}
+	userMessages = append(userMessages, "") // Give the user a reset option.
+	if len(userMessages) > 0 {
+		if key.Matches(msg, m.keyMap.Previous) {
+			if m.promptHistoryIndex == 0 {
+				m.promptHistoryIndex = len(userMessages) - 1
+			} else {
+				m.promptHistoryIndex -= 1
+			}
+		}
+		if key.Matches(msg, m.keyMap.Next) {
+			if m.promptHistoryIndex == len(userMessages)-1 {
+				m.promptHistoryIndex = 0
+			} else {
+				m.promptHistoryIndex += 1
+			}
+		}
+	}
+	return userMessages[m.promptHistoryIndex]
+}

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

@@ -9,6 +9,8 @@ type EditorKeyMap struct {
 	SendMessage key.Binding
 	OpenEditor  key.Binding
 	Newline     key.Binding
+	Next        key.Binding
+	Previous    key.Binding
 }
 
 func DefaultEditorKeyMap() EditorKeyMap {
@@ -32,6 +34,14 @@ func DefaultEditorKeyMap() EditorKeyMap {
 			// to reflect that.
 			key.WithHelp("ctrl+j", "newline"),
 		),
+		Next: key.NewBinding(
+			key.WithKeys("shift+down"),
+			key.WithHelp("shift+↓", "down"),
+		),
+		Previous: key.NewBinding(
+			key.WithKeys("shift+up"),
+			key.WithHelp("shift+↑", "up"),
+		),
 	}
 }