feat: implemented 'D' action, tested
This commit is contained in:
parent
ee7bf9354b
commit
0e8ca21f7f
@ -57,6 +57,7 @@ type Model interface {
|
||||
SetCursorX(x int)
|
||||
SetCursorY(y int)
|
||||
ClampCursorX()
|
||||
ClampCursorXNormal()
|
||||
|
||||
// Window
|
||||
ScrollY() int
|
||||
|
||||
@ -21,3 +21,56 @@ func (a DeleteChar) Execute(m Model) tea.Cmd {
|
||||
func (a DeleteChar) WithCount(n int) Action {
|
||||
return DeleteChar{Count: n}
|
||||
}
|
||||
|
||||
type DeleteToEndOfLine struct {
|
||||
Count int
|
||||
}
|
||||
|
||||
func (a DeleteToEndOfLine) Execute(m Model) tea.Cmd {
|
||||
// Delete to end of line
|
||||
pos := m.CursorX()
|
||||
line := m.Line(m.CursorY())
|
||||
|
||||
m.SetLine(m.CursorY(), line[:pos])
|
||||
m.SetCursorX(pos - 1)
|
||||
|
||||
// If count is greater, than we will delete the next N - 1 lines below
|
||||
initY := m.CursorY()
|
||||
if a.Count > 1 {
|
||||
// Copied from `internal/operator/delete.go`
|
||||
opCount := min(a.Count-1, m.LineCount()-m.CursorY())
|
||||
|
||||
// Down one
|
||||
m.SetCursorY(initY + 1)
|
||||
|
||||
for range opCount {
|
||||
y := m.CursorY() // Changed from the copied code
|
||||
|
||||
// Stop if were on the starting line
|
||||
if y == initY {
|
||||
break
|
||||
}
|
||||
m.DeleteLine(y)
|
||||
|
||||
if m.LineCount() == 0 {
|
||||
m.InsertLine(0, "")
|
||||
}
|
||||
|
||||
if y >= m.LineCount() {
|
||||
y = m.LineCount() - 1
|
||||
}
|
||||
|
||||
m.SetCursorY(y)
|
||||
m.ClampCursorX()
|
||||
}
|
||||
}
|
||||
|
||||
m.SetCursorY(initY)
|
||||
m.ClampCursorX()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a DeleteToEndOfLine) WithCount(n int) Action {
|
||||
return DeleteToEndOfLine{Count: n}
|
||||
}
|
||||
|
||||
@ -86,3 +86,92 @@ func TestDeleteCharWithCount(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteToEndOfLine(t *testing.T) {
|
||||
t.Run("test 'D' deletes to end of line", func(t *testing.T) {
|
||||
lines := []string{"hello world"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 5, Line: 0})
|
||||
sendKeys(tm, "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'D' from start of line deletes entire content", func(t *testing.T) {
|
||||
lines := []string{"hello world"}
|
||||
tm := newTestModelWithLines(t, lines)
|
||||
sendKeys(tm, "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.Line(0) != "" {
|
||||
t.Errorf("Line(0) = %q, want ''", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'D' at last character", func(t *testing.T) {
|
||||
lines := []string{"hello"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 4, Line: 0})
|
||||
sendKeys(tm, "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.Line(0) != "hell" {
|
||||
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'D' cursor position after delete", func(t *testing.T) {
|
||||
lines := []string{"hello world"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 5, Line: 0})
|
||||
sendKeys(tm, "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Cursor should move to last character of remaining text
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'D' deletes nothing on blank line", func(t *testing.T) {
|
||||
lines := []string{""}
|
||||
tm := newTestModelWithLines(t, lines)
|
||||
sendKeys(tm, "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.Line(0) != "" {
|
||||
t.Errorf("Line(0) = %q, want ''", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'D' with count deletes following lines", func(t *testing.T) {
|
||||
lines := []string{"hello", "world", "hi", "mom"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 2, Line: 0})
|
||||
sendKeys(tm, "2", "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.LineCount() != 3 {
|
||||
t.Errorf("LineCount() = %q, want '3'", m.LineCount())
|
||||
}
|
||||
if m.Line(0) != "he" {
|
||||
t.Errorf("Line(0) = %q, want 'he'", m.Line(0))
|
||||
}
|
||||
if m.Line(1) != "hi" {
|
||||
t.Errorf("Line(1) = %q, want 'hi'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'D' with count deletes following lines with overflow", func(t *testing.T) {
|
||||
lines := []string{"hello", "world", "hi", "mom"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 2, Line: 0})
|
||||
sendKeys(tm, "8", "D")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.LineCount() != 1 {
|
||||
t.Errorf("LineCount() = %q, want '1'", m.LineCount())
|
||||
}
|
||||
if m.Line(0) != "he" {
|
||||
t.Errorf("Line(0) = %q, want 'he'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ func NewNormalKeymap() *Keymap {
|
||||
"v": action.EnterVisualMode{},
|
||||
"V": action.EnterVisualLineMode{},
|
||||
"ctrl+v": action.EnterVisualBlockMode{},
|
||||
"D": action.DeleteToEndOfLine{Count: 1},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user