Gim/motion.go
2026-02-08 23:24:46 -07:00

269 lines
4.6 KiB
Go

package main
import tea "github.com/charmbracelet/bubbletea"
// MoveDown implements Motion
type MoveDown struct {
count int
}
func (a MoveDown) Execute(m *model) tea.Cmd {
for i := 0; i < a.count && m.cursor.y < len(m.lines)-1; i++ {
m.cursor.y++
}
m.clampCursorX()
return nil
}
func (a MoveDown) WithCount(n int) Action {
return MoveDown{count: n}
}
// MoveUp implements Motion
type MoveUp struct {
count int
}
func (a MoveUp) Execute(m *model) tea.Cmd {
for i := 0; i < a.count && m.cursor.y > 0; i++ {
m.cursor.y--
}
m.clampCursorX()
return nil
}
func (a MoveUp) WithCount(n int) Action {
return MoveUp{count: n}
}
type MoveLeft struct {
count int
}
func (a MoveLeft) Execute(m *model) tea.Cmd {
for i := 0; i < a.count && m.cursor.x > 0; i++ {
m.cursor.x--
}
m.clampCursorX()
return nil
}
func (a MoveLeft) WithCount(n int) Action {
return MoveLeft{count: n}
}
type MoveRight struct {
count int
}
func (a MoveRight) Execute(m *model) tea.Cmd {
lineLen := len(m.lines[m.cursor.y])
for i := 0; i < a.count && m.cursor.x <= lineLen; i++ {
m.cursor.x++
}
m.clampCursorX()
return nil
}
func (a MoveRight) WithCount(n int) Action {
return MoveRight{count: n}
}
type EnterInsert struct {
count int
}
func (a EnterInsert) Execute(m *model) tea.Cmd {
// Start recording
m.insertCount = a.count
m.insertKeys = []string{}
m.insertAction = a
m.mode = InsertMode
return nil
}
func (a EnterInsert) WithCount(n int) Action {
return EnterInsert{count: n}
}
type EnterInsertAfter struct {
count int
}
func (a EnterInsertAfter) Execute(m *model) tea.Cmd {
m.cursor.x++
m.clampCursorX()
// Start recording
m.insertCount = a.count
m.insertKeys = []string{}
m.insertAction = a
m.mode = InsertMode
return nil
}
func (a EnterInsertAfter) WithCount(n int) Action {
return EnterInsertAfter{count: n}
}
type Quit struct{}
func (a Quit) Execute(m *model) tea.Cmd {
return tea.Quit
}
// MoveToTop implements Motion (gg)
type MoveToTop struct{}
func (a MoveToTop) Execute(m *model) tea.Cmd {
m.cursor.y = 0
m.clampCursorX()
return nil
}
// MoveToBottom implements Motion (G)
type MoveToBottom struct{}
func (a MoveToBottom) Execute(m *model) tea.Cmd {
m.cursor.y = len(m.lines) - 1
m.clampCursorX()
return nil
}
type EnterInsertLineStart struct {
count int
}
func (a EnterInsertLineStart) Execute(m *model) tea.Cmd {
m.cursor.x = 0
m.clampCursorX()
// Start recording
m.insertCount = a.count
m.insertKeys = []string{}
m.insertAction = a
m.mode = InsertMode
return nil
}
func (a EnterInsertLineStart) WithCount(n int) Action {
return EnterInsertLineStart{count: n}
}
type EnterInsertLineEnd struct {
count int
}
func (a EnterInsertLineEnd) Execute(m *model) tea.Cmd {
m.cursor.x = len(m.lines[m.cursor.y])
m.clampCursorX()
// Start recording
m.insertCount = a.count
m.insertKeys = []string{}
m.insertAction = a
m.mode = InsertMode
return nil
}
func (a EnterInsertLineEnd) WithCount(n int) Action {
return EnterInsertLineEnd{count: n}
}
type MoveToLineStart struct{}
func (a MoveToLineStart) Execute(m *model) tea.Cmd {
m.cursor.x = 0
m.clampCursorX()
return nil
}
type MoveToLineEnd struct{}
func (a MoveToLineEnd) Execute(m *model) tea.Cmd {
m.cursor.x = len(m.lines[m.cursor.y])
m.clampCursorX()
return nil
}
// TODO: Count
type OpenLineBelow struct {
count int
}
func (a OpenLineBelow) Execute(m *model) tea.Cmd {
pos := m.cursor.y
if pos >= len(m.lines) {
m.lines = append(m.lines, "")
} else {
m.lines = append(m.lines[:pos+1], append([]string{""}, m.lines[pos+1:]...)...)
}
m.cursor.y++
m.cursor.x = 0
// Start recording
m.insertCount = a.count
m.insertKeys = []string{}
m.insertAction = a
m.mode = InsertMode
return nil
}
func (a OpenLineBelow) WithCount(n int) Action {
return OpenLineBelow{count: n}
}
type OpenLineAbove struct {
count int
}
func (a OpenLineAbove) Execute(m *model) tea.Cmd {
pos := m.cursor.y
if pos <= 0 {
m.lines = append([]string{""}, m.lines...)
} else {
m.lines = append(m.lines[:pos], append([]string{""}, m.lines[pos:]...)...)
}
m.cursor.x = 0
// Start recording
m.insertCount = a.count
m.insertKeys = []string{}
m.insertAction = a
m.mode = InsertMode
return nil
}
func (a OpenLineAbove) WithCount(n int) Action {
return OpenLineAbove{count: n}
}
// TODO: Visual mode
type DeleteChar struct {
count int
}
func (a DeleteChar) Execute(m *model) tea.Cmd {
pos := m.cursor.x
for i := 0; i < a.count && m.cursor.x < len(m.lines[m.cursor.y]); i++ {
line := m.lines[m.cursor.y]
m.lines[m.cursor.y] = line[:pos] + line[pos+1:]
}
return nil
}
func (a DeleteChar) WithCount(n int) Action {
return DeleteChar{count: n}
}