153 lines
3.1 KiB
Go
153 lines
3.1 KiB
Go
package action
|
|
|
|
import (
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
// Mode constants for editor mode
|
|
type Mode int
|
|
|
|
const (
|
|
NormalMode Mode = iota
|
|
InsertMode
|
|
CommandMode
|
|
VisualMode
|
|
VisualLineMode
|
|
VisualBlockMode
|
|
)
|
|
|
|
func (m Mode) ToString() string {
|
|
switch m {
|
|
case NormalMode:
|
|
return "NORMAL"
|
|
case InsertMode:
|
|
return "INSERT"
|
|
case CommandMode:
|
|
return "COMMAND"
|
|
case VisualMode:
|
|
return "VISUAL"
|
|
case VisualLineMode:
|
|
return "V-LINE"
|
|
case VisualBlockMode:
|
|
return "V-BLOCK"
|
|
default:
|
|
return "-----"
|
|
}
|
|
}
|
|
|
|
func (m Mode) IsVisualMode() bool {
|
|
return m == VisualMode ||
|
|
m == VisualLineMode ||
|
|
m == VisualBlockMode
|
|
}
|
|
|
|
// Model defines the interface for editor state that actions can modify
|
|
type Model interface {
|
|
// Text buffer
|
|
Lines() []string
|
|
Line(idx int) string
|
|
SetLine(idx int, content string)
|
|
InsertLine(idx int, content string)
|
|
DeleteLine(idx int)
|
|
LineCount() int
|
|
|
|
// Cursor
|
|
CursorX() int
|
|
CursorY() int
|
|
SetCursorX(x int)
|
|
SetCursorY(y int)
|
|
ClampCursorX()
|
|
|
|
// Window
|
|
ScrollY() int
|
|
SetScrollY(y int)
|
|
WinH() int
|
|
WinW() int
|
|
ViewPortH() int
|
|
|
|
// Anchor
|
|
AnchorX() int
|
|
AnchorY() int
|
|
SetAnchorX(x int)
|
|
SetAnchorY(y int)
|
|
|
|
// Insert
|
|
InsertKeys() []string
|
|
SetInsertKeys(keys []string)
|
|
|
|
// Command mode
|
|
Command() string
|
|
SetCommand(cmd string)
|
|
CommandCursor() int
|
|
SetCommandCursor(cur int)
|
|
CommandError() error
|
|
SetCommandError(err error)
|
|
CommandOutput() string
|
|
SetCommandOutput(out string)
|
|
|
|
// Settings
|
|
Settings() Settings
|
|
SetSettings(s Settings)
|
|
|
|
// Registers
|
|
Registers() map[rune]Register
|
|
GetRegister(name rune) (Register, bool)
|
|
SetRegister(name rune, t RegisterType, cnt []string) error
|
|
UpdateDefault(t RegisterType, cnt []string)
|
|
|
|
// Mode
|
|
Mode() Mode
|
|
SetMode(mode Mode)
|
|
|
|
// Insert recording (for count replay)
|
|
SetInsertRecording(count int, action Action)
|
|
|
|
// ExitInsertMode handles replay, cursor step-back, and mode transition on esc
|
|
ExitInsertMode()
|
|
}
|
|
|
|
// Position represents a location in the buffer
|
|
type Position struct {
|
|
Line, Col int
|
|
}
|
|
|
|
// MotionType indicates how a motion operates
|
|
type MotionType int
|
|
|
|
const (
|
|
CharwiseExclusive MotionType = iota // w, b, h, l, 0, ^ - end position not included
|
|
CharwiseInclusive // e, $, f - end position is included
|
|
Linewise // j, k, G, gg, {, } - operates on whole lines
|
|
)
|
|
|
|
// IsCharwise returns true if the motion type is character-based (not linewise)
|
|
func (mt MotionType) IsCharwise() bool {
|
|
return mt == CharwiseExclusive || mt == CharwiseInclusive
|
|
}
|
|
|
|
// 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() MotionType
|
|
}
|
|
|
|
// Operator acts on a range (delete, yank, change)
|
|
type Operator interface {
|
|
Operate(m Model, start, end Position, mtype 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
|
|
}
|