package action import ( "git.gophernest.net/azpect/TextEditor/internal/core" tea "github.com/charmbracelet/bubbletea" ) // ExitCommandMode implements Action - exits command mode and returns to normal mode. type ExitCommandMode struct{} // ExitCommandMode.Execute: Exits command mode and returns to normal mode (Esc key). func (a ExitCommandMode) Execute(m Model) tea.Cmd { m.SetCommandCursor(0) m.SetCommandHistoryCursor(0) m.SetCommand("") m.SetCommandOutput(&core.CommandOutput{}) m.SetMode(core.NormalMode) return nil } // InsertCommandChar implements Action - inserts a character in command mode. type InsertCommandChar struct { Char string } // InsertCommandChar.Execute: Inserts a character at the command cursor position. func (a InsertCommandChar) Execute(m Model) tea.Cmd { cur := m.CommandCursor() cmd := m.Command() m.SetCommand(cmd[:cur] + a.Char + cmd[cur:]) m.SetCommandCursor(cur + 1) return nil } // CommandBackspace implements Action - deletes character before cursor in command mode. type CommandBackspace struct{} // CommandBackspace.Execute: Deletes the character before the command cursor (Backspace key). func (a CommandBackspace) Execute(m Model) tea.Cmd { cur := m.CommandCursor() cmd := m.Command() if cur > 0 { m.SetCommand(cmd[:cur-1] + cmd[cur:]) m.SetCommandCursor(cur - 1) } return nil } // CommandDelete implements Action - deletes character at cursor in command mode. type CommandDelete struct{} // CommandDelete.Execute: Deletes the character at the command cursor (Delete key). func (a CommandDelete) Execute(m Model) tea.Cmd { cur := m.CommandCursor() cmd := m.Command() if cur < len(cmd)-1 { m.SetCommand(cmd[:cur+1] + cmd[cur+2:]) } else if cur == len(cmd)-1 { // last text char, delete it m.SetCommand(cmd[:cur] + cmd[cur+1:]) } else if cur == len(cmd) && cur > 0 { // if at end, we do backspace op m.SetCommand(cmd[:cur-1] + cmd[cur:]) m.SetCommandCursor(cur - 1) } return nil } // CommandDeletePreviousWord implements Action - deletes word before cursor in command mode. type CommandDeletePreviousWord struct{} // CommandDeletePreviousWord.Execute: Deletes the word before the command cursor (Ctrl+W). func (a CommandDeletePreviousWord) Execute(m Model) tea.Cmd { cur := m.CommandCursor() cmd := m.Command() if cur > 0 { newCur := cur // If we are on puncuation, we should just skip them all and quit if isPunctuation(cmd[newCur-1]) { for newCur > 0 && isPunctuation(cmd[newCur-1]) { newCur-- } m.SetCommand(cmd[:newCur] + cmd[cur:]) m.SetCommandCursor(newCur) return nil } // Skip whitespace immediately before the cursor for newCur > 0 && (cmd[newCur-1] == ' ' || cmd[newCur-1] == '\t') { newCur-- } // Skip the word characters before the cursor for newCur > 0 && isWordChar(cmd[newCur-1]) { newCur-- } // Delete everything from newCur up to cur in one operation m.SetCommand(cmd[:newCur] + cmd[cur:]) m.SetCommandCursor(newCur) } return nil } // CommandExecute implements Action - executes the command line. type CommandExecute struct { Registry CommandRegistry } // CommandRegistry: Interface for executing commands. type CommandRegistry interface { Execute(m Model, cmdLine string) (tea.Cmd, error) } // CommandExecute.Execute: Executes the command line (Enter key). func (a CommandExecute) Execute(m Model) tea.Cmd { cmdLine := m.Command() // Clear command state and return to normal mode m.SetCommandCursor(0) m.SetCommandHistoryCursor(0) m.SetMode(core.NormalMode) if a.Registry == nil || cmdLine == "" { return nil } history := append([]string{cmdLine}, m.CommandHistory()...) // history = append([]string{cmdLine}, history...) m.SetCommandHistory(history) cmd, err := a.Registry.Execute(m, cmdLine) if err != nil { out := core.CommandOutput{ Lines: []string{err.Error()}, Inline: true, IsError: true, } m.SetCommandOutput(&out) return nil } return cmd }