The tests are starting to get messy, lots of duplication. Going to resolve that. Lots of this is due to AI generation of tests.
111 lines
3.3 KiB
Go
111 lines
3.3 KiB
Go
package action
|
|
|
|
import (
|
|
"git.gophernest.net/azpect/TextEditor/internal/core"
|
|
"git.gophernest.net/azpect/TextEditor/internal/style"
|
|
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)
|
|
|
|
// ==================================================
|
|
// Editor-wide State
|
|
// ==================================================
|
|
Mode() core.Mode
|
|
SetMode(mode core.Mode)
|
|
|
|
Settings() core.EditorSettings
|
|
SetSettings(s core.EditorSettings)
|
|
Styles() style.Styles
|
|
SetStyles(s style.Styles)
|
|
|
|
// ==================================================
|
|
// 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)
|
|
}
|
|
|
|
// 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
|
|
}
|