Gim/internal/action/change.go
Hayden Hargreaves e362c9f118
All checks were successful
Run Test Suite / test (push) Successful in 56s
feat: gap buffer is implemented, tested
Not sure if this is perfect, but it seems to be working
2026-04-02 12:39:30 -07:00

127 lines
3.1 KiB
Go

package action
import (
"git.gophernest.net/azpect/TextEditor/internal/core"
tea "github.com/charmbracelet/bubbletea"
)
// ChangeToEndOfLine implements Action (C) - changes from cursor to end of line
type ChangeToEndOfLine struct {
Count int
}
// ChangeToEndOfLine.Execute: Changes from cursor to end of line and enters insert mode (C key).
func (a ChangeToEndOfLine) Execute(m Model) tea.Cmd {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
pos := win.Cursor.Col
line := buf.Line(win.Cursor.Line)
// Save deleted text to register
if pos < len(line) {
m.UpdateDefaultRegister(core.CharwiseRegister, []string{line[pos:]})
}
// Delete to end of line
buf.SetLine(win.Cursor.Line, line[:pos])
// Enter insert mode
m.SetMode(core.InsertMode)
return nil
}
// Ensure ChangeToEndOfLine implements Repeatable
var _ Repeatable = ChangeToEndOfLine{}
// ChangeToEndOfLine.WithCount: Returns a new ChangeToEndOfLine with the given count.
func (a ChangeToEndOfLine) WithCount(n int) Action {
return ChangeToEndOfLine{Count: n}
}
// SubstituteChar implements Action (s) - deletes character and enters insert mode
type SubstituteChar struct {
Count int
}
// SubstituteChar.Execute: Deletes Count characters and enters insert mode (s key).
func (a SubstituteChar) Execute(m Model) tea.Cmd {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
pos := win.Cursor.Col
line := buf.Line(win.Cursor.Line)
// Calculate how many chars to delete (limited by line length)
count := min(a.Count, len(line)-pos)
if count > 0 {
// Save deleted text to register
m.UpdateDefaultRegister(core.CharwiseRegister, []string{line[pos : pos+count]})
// Delete the characters
buf.SetLine(win.Cursor.Line, line[:pos]+line[pos+count:])
}
// Enter insert mode
m.SetMode(core.InsertMode)
return nil
}
// Ensure SubstituteChar implements Repeatable
var _ Repeatable = SubstituteChar{}
// SubstituteChar.WithCount: Returns a new SubstituteChar with the given count.
func (a SubstituteChar) WithCount(n int) Action {
return SubstituteChar{Count: n}
}
// SubstituteLine implements Action (S) - clears line and enters insert mode
type SubstituteLine struct {
Count int
}
// SubstituteLine.Execute: Clears Count lines and enters insert mode (S key).
func (a SubstituteLine) Execute(m Model) tea.Cmd {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
y := win.Cursor.Line
// Calculate how many lines to substitute
count := min(a.Count, buf.LineCount()-y)
var lines []string
// Collect and delete lines
for range count {
lines = append(lines, buf.Line(y))
buf.DeleteLine(y)
}
// Save deleted lines to register
m.UpdateDefaultRegister(core.LinewiseRegister, lines)
// Insert empty line at original position
insertY := min(y, buf.LineCount())
buf.InsertLine(insertY, "")
// Position cursor
win.SetCursorPos(insertY, 0)
// Enter insert mode
m.SetMode(core.InsertMode)
return nil
}
// Ensure SubstituteLine implements Repeatable
var _ Repeatable = SubstituteLine{}
// SubstituteLine.WithCount: Returns a new SubstituteLine with the given count.
func (a SubstituteLine) WithCount(n int) Action {
return SubstituteLine{Count: n}
}