package action import ( "git.gophernest.net/azpect/TextEditor/internal/core" "git.gophernest.net/azpect/TextEditor/internal/theme" tea "github.com/charmbracelet/bubbletea" ) // Model defines the interface for editor state that actions can modify type Model interface { // ================================================== // Core Data Access // ================================================== Windows() []*core.Window ActiveWindow() *core.Window Buffers() []*core.Buffer SetBuffers(bufs []*core.Buffer) ActiveBuffer() *core.Buffer // ================================================== // Insert Mode State // ================================================== InsertKeys() []string SetInsertKeys(keys []string) // Insert recording (for count replay) SetInsertRecording(count int, action Action) SetLastFind(char string, forward, inclusive bool) GetLastFind() *core.LastFindCommand // ExitInsertMode handles replay, cursor step-back, and mode transition on esc ExitInsertMode() // ================================================== // Command Mode State // ================================================== Command() string SetCommand(cmd string) CommandCursor() int SetCommandCursor(cur int) CommandOutput() *core.CommandOutput // DO NOT FORGET TO CALL SetMode() SetCommandOutput(out *core.CommandOutput) CommandHistory() []string SetCommandHistory(history []string) CommandHistoryCursor() int SetCommandHistoryCursor(cur int) // ================================================== // Search Mode State // ================================================== SearchState() core.SearchState SetSearchState(s core.SearchState) // ================================================== // Editor-wide State // ================================================== Mode() core.Mode SetMode(mode core.Mode) Settings() core.EditorSettings SetSettings(s core.EditorSettings) // ================================================== // Themes // ================================================== Theme() (string, theme.EditorTheme) SetTheme(name string) Themes() map[string]theme.EditorTheme SetThemes(t map[string]theme.EditorTheme) // ================================================== // Registers // ================================================== Registers() map[rune]core.Register GetRegister(name rune) (core.Register, bool) SetRegister(name rune, t core.RegisterType, cnt []string) error UpdateDefaultRegister(t core.RegisterType, cnt []string) // Dot operator - accumulate keys for repeat SetLastChangeKeys(keys []string) LastChangeKeys() []string ClearLastChangeKeys() HandleKey(key string) tea.Cmd } // Action is the base interface - anything executable type Action interface { Execute(m Model) tea.Cmd } // Motion moves the cursor and returns the range covered type Motion interface { Action Type() core.MotionType } // Operator acts on a range (delete, yank, change) type Operator interface { Operate(m Model, start, end core.Position, mtype core.MotionType) tea.Cmd } // DoublePresser is an optional interface for operators that support double-press (dd, yy, cc) type DoublePresser interface { DoublePress(m Model, count int) tea.Cmd } // Repeatable actions track count type Repeatable interface { WithCount(n int) Action } // CharMotion is a motion that requires a character argument (f/t/F/T) // The state machine will call WithChar to set the character before executing type CharMotion interface { Motion WithChar(char string) Motion } // Resolvable is an optional interface for motions that need to consult the // model to fully determine their behaviour (e.g. RepeatFind must look up the // last find to know whether it is inclusive or exclusive). The FSM calls // Resolve(m) first and uses the returned Motion in place of the original, so // that the subsequent Type() call returns the correct value. type Resolvable interface { Motion Resolve(m Model) Motion } type TextObject interface { // GetRange calculates both endpoints for the text object // modifier: "i" (inner) or "a" (around) GetRange(m Model, cursor core.Position, modifier string) (start, end core.Position, mtype core.MotionType) }