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() }