Gim/internal/action/action.go
2026-02-21 21:31:31 -07:00

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
}