Gim/internal/operator/delete.go
Hayden Hargreaves 77374ba447 feat: implemented 'dd' and other 'd' for visual mode.
Tested 'dd' but not visual mode.
2026-02-11 17:56:06 -07:00

109 lines
2.3 KiB
Go

package operator
import (
"git.gophernest.net/azpect/TextEditor/internal/action"
tea "github.com/charmbracelet/bubbletea"
)
// Implements Operator (x)
type DeleteOperator struct{}
func (o DeleteOperator) Operate(m action.Model, start, end action.Position) tea.Cmd {
switch m.Mode() {
case action.VisualMode:
deleteCharSelection(m, start, end)
case action.VisualLineMode:
deleteLineSelection(m, start, end)
case action.VisualBlockMode:
deleteBlockSelection(m, start, end)
}
return nil
}
// Double press handles dd - delete the entire line
func (o DeleteOperator) DoublePress(m action.Model, count int) tea.Cmd {
// If we have a higher value than lines remaining, we can only run so many times
opCount := min(count, m.LineCount()-m.CursorY())
for range opCount {
y := m.CursorY()
m.DeleteLine(y)
if m.LineCount() == 0 {
m.InsertLine(0, "")
}
if y >= m.LineCount() {
y = m.LineCount() - 1
}
m.SetCursorY(y)
m.ClampCursorX()
}
return nil
}
func deleteCharSelection(m action.Model, start, end action.Position) {
if start.Line == end.Line {
line := m.Line(start.Line)
endCol := min(end.Col+1, len(line))
m.SetLine(start.Line, line[:start.Col]+line[endCol:])
} else {
startLine := m.Line(start.Line)
endLine := m.Line(end.Line)
prefix := startLine[:start.Col]
suffix := ""
if end.Col+1 < len(endLine) {
suffix = endLine[end.Col+1:]
}
// Delete from end back to start to preserve indices
for i := end.Line; i >= start.Line; i-- {
m.DeleteLine(i)
}
m.InsertLine(start.Line, prefix+suffix)
}
m.SetCursorY(start.Line)
m.SetCursorX(start.Col)
m.ClampCursorX()
}
func deleteLineSelection(m action.Model, start, end action.Position) {
for i := end.Line; i >= start.Line; i-- {
m.DeleteLine(i)
}
if m.LineCount() == 0 {
m.InsertLine(0, "")
}
y := start.Line
if y >= m.LineCount() {
y = m.LineCount() - 1
}
m.SetCursorY(y)
m.ClampCursorX()
}
func deleteBlockSelection(m action.Model, start, end action.Position) {
startCol := min(start.Col, end.Col)
endCol := max(start.Col, end.Col)
for y := start.Line; y <= end.Line; y++ {
line := m.Line(y)
if startCol >= len(line) {
continue
}
ec := min(endCol+1, len(line))
m.SetLine(y, line[:startCol]+line[ec:])
}
m.SetCursorY(start.Line)
m.SetCursorX(startCol)
m.ClampCursorX()
}