|
|
@@ -25,18 +25,23 @@ import (
|
|
|
)
|
|
|
|
|
|
type editorCmp struct {
|
|
|
- width int
|
|
|
- height int
|
|
|
- app *app.App
|
|
|
- textarea textarea.Model
|
|
|
- attachments []message.Attachment
|
|
|
- deleteMode bool
|
|
|
+ width int
|
|
|
+ height int
|
|
|
+ app *app.App
|
|
|
+ textarea textarea.Model
|
|
|
+ attachments []message.Attachment
|
|
|
+ deleteMode bool
|
|
|
+ history []string
|
|
|
+ historyIndex int
|
|
|
+ currentMessage string
|
|
|
}
|
|
|
|
|
|
type EditorKeyMaps struct {
|
|
|
Send key.Binding
|
|
|
OpenEditor key.Binding
|
|
|
Paste key.Binding
|
|
|
+ HistoryUp key.Binding
|
|
|
+ HistoryDown key.Binding
|
|
|
}
|
|
|
|
|
|
type bluredEditorKeyMaps struct {
|
|
|
@@ -63,6 +68,14 @@ var editorMaps = EditorKeyMaps{
|
|
|
key.WithKeys("ctrl+v"),
|
|
|
key.WithHelp("ctrl+v", "paste content"),
|
|
|
),
|
|
|
+ HistoryUp: key.NewBinding(
|
|
|
+ key.WithKeys("up"),
|
|
|
+ key.WithHelp("up", "previous message"),
|
|
|
+ ),
|
|
|
+ HistoryDown: key.NewBinding(
|
|
|
+ key.WithKeys("down"),
|
|
|
+ key.WithHelp("down", "next message"),
|
|
|
+ ),
|
|
|
}
|
|
|
|
|
|
var DeleteKeyMaps = DeleteAttachmentKeyMaps{
|
|
|
@@ -139,6 +152,15 @@ func (m *editorCmp) send() tea.Cmd {
|
|
|
m.textarea.Reset()
|
|
|
attachments := m.attachments
|
|
|
|
|
|
+ // Save to history if not empty and not a duplicate of the last entry
|
|
|
+ if value != "" {
|
|
|
+ if len(m.history) == 0 || m.history[len(m.history)-1] != value {
|
|
|
+ m.history = append(m.history, value)
|
|
|
+ }
|
|
|
+ m.historyIndex = len(m.history)
|
|
|
+ m.currentMessage = ""
|
|
|
+ }
|
|
|
+
|
|
|
m.attachments = nil
|
|
|
if value == "" {
|
|
|
return nil
|
|
|
@@ -223,6 +245,50 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
}
|
|
|
return m, cmd
|
|
|
}
|
|
|
+
|
|
|
+ // Handle history navigation with up/down arrow keys
|
|
|
+ if m.textarea.Focused() && key.Matches(msg, editorMaps.HistoryUp) {
|
|
|
+ // Get the current line number
|
|
|
+ currentLine := m.textarea.Line()
|
|
|
+
|
|
|
+ // Only navigate history if we're at the first line
|
|
|
+ if currentLine == 0 && len(m.history) > 0 {
|
|
|
+ // Save current message if we're just starting to navigate
|
|
|
+ if m.historyIndex == len(m.history) {
|
|
|
+ m.currentMessage = m.textarea.Value()
|
|
|
+ }
|
|
|
+
|
|
|
+ // Go to previous message in history
|
|
|
+ if m.historyIndex > 0 {
|
|
|
+ m.historyIndex--
|
|
|
+ m.textarea.SetValue(m.history[m.historyIndex])
|
|
|
+ }
|
|
|
+ return m, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if m.textarea.Focused() && key.Matches(msg, editorMaps.HistoryDown) {
|
|
|
+ // Get the current line number and total lines
|
|
|
+ currentLine := m.textarea.Line()
|
|
|
+ value := m.textarea.Value()
|
|
|
+ lines := strings.Split(value, "\n")
|
|
|
+ totalLines := len(lines)
|
|
|
+
|
|
|
+ // Only navigate history if we're at the last line
|
|
|
+ if currentLine == totalLines-1 {
|
|
|
+ if m.historyIndex < len(m.history)-1 {
|
|
|
+ // Go to next message in history
|
|
|
+ m.historyIndex++
|
|
|
+ m.textarea.SetValue(m.history[m.historyIndex])
|
|
|
+ } else if m.historyIndex == len(m.history)-1 {
|
|
|
+ // Return to the current message being composed
|
|
|
+ m.historyIndex = len(m.history)
|
|
|
+ m.textarea.SetValue(m.currentMessage)
|
|
|
+ }
|
|
|
+ return m, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Handle Enter key
|
|
|
if m.textarea.Focused() && key.Matches(msg, editorMaps.Send) {
|
|
|
value := m.textarea.Value()
|
|
|
@@ -336,7 +402,10 @@ func CreateTextArea(existing *textarea.Model) textarea.Model {
|
|
|
func NewEditorCmp(app *app.App) tea.Model {
|
|
|
ta := CreateTextArea(nil)
|
|
|
return &editorCmp{
|
|
|
- app: app,
|
|
|
- textarea: ta,
|
|
|
+ app: app,
|
|
|
+ textarea: ta,
|
|
|
+ history: []string{},
|
|
|
+ historyIndex: 0,
|
|
|
+ currentMessage: "",
|
|
|
}
|
|
|
}
|