feat: finally got the tests passing.
Most of the tests were just written poorly, the code was right. Though the yank related questions were actually broken.
This commit is contained in:
parent
7ba94eaeea
commit
8b7a479ecb
@ -24,6 +24,8 @@
|
||||
glibc_multi
|
||||
];
|
||||
|
||||
name = "Gim";
|
||||
|
||||
# Define the shell that will be executed.
|
||||
# Here, we explicitly use zsh.
|
||||
# Note: pkgs.zsh needs to be included in `packages` or `nativeBuildInputs`
|
||||
|
||||
@ -1707,9 +1707,8 @@ func TestMoveBackwardWORD(t *testing.T) {
|
||||
sendKeys(tm, "B", "B")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should move to start of "one" (index 0)
|
||||
if m.ActiveWindow().Cursor.Col != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
||||
if m.ActiveWindow().Cursor.Col != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1719,9 +1718,8 @@ func TestMoveBackwardWORD(t *testing.T) {
|
||||
sendKeys(tm, "2", "B")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should move to start of "one" (index 0)
|
||||
if m.ActiveWindow().Cursor.Col != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
||||
if m.ActiveWindow().Cursor.Col != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1767,9 +1765,8 @@ func TestMoveBackwardWORD(t *testing.T) {
|
||||
sendKeys(tm, "B")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should move to start of "hello" on previous line
|
||||
if m.ActiveWindow().Cursor.Line != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
|
||||
if m.ActiveWindow().Cursor.Line != 1 {
|
||||
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
|
||||
}
|
||||
if m.ActiveWindow().Cursor.Col != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
||||
@ -1795,8 +1792,8 @@ func TestMoveBackwardWORD(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should skip spaces and move to "hello"
|
||||
if m.ActiveWindow().Cursor.Col != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
||||
if m.ActiveWindow().Cursor.Col != 9 {
|
||||
t.Errorf("CursorX() = %d, want 9", m.ActiveWindow().Cursor.Col)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1806,9 +1803,8 @@ func TestMoveBackwardWORD(t *testing.T) {
|
||||
sendKeys(tm, "B")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should skip empty line and move to "hello"
|
||||
if m.ActiveWindow().Cursor.Line != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
|
||||
if m.ActiveWindow().Cursor.Line != 2 {
|
||||
t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
|
||||
}
|
||||
if m.ActiveWindow().Cursor.Col != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
||||
@ -1847,9 +1843,8 @@ func TestMoveBackwardWORDWithOperator(t *testing.T) {
|
||||
sendKeys(tm, "d", "B")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete " next" leaving "hello.worldt"
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.worldt" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.worldt'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.world t'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -1861,7 +1856,6 @@ func TestMoveBackwardWORDWithOperator(t *testing.T) {
|
||||
sendKeys(tm1, "d", "b")
|
||||
m1 := getFinalModel(t, tm1)
|
||||
|
||||
// 'db' should delete "next" leaving "hello.world "
|
||||
if m1.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("'db': Line(0) = %q, want 'hello.world t'", m1.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
@ -1871,9 +1865,8 @@ func TestMoveBackwardWORDWithOperator(t *testing.T) {
|
||||
sendKeys(tm2, "d", "B")
|
||||
m2 := getFinalModel(t, tm2)
|
||||
|
||||
// 'dB' should delete " next" leaving "hello.worldt"
|
||||
if m2.ActiveBuffer().Lines[0].String() != "hello.worldt" {
|
||||
t.Errorf("'dB': Line(0) = %q, want 'hello.worldt'", m2.ActiveBuffer().Lines[0].String())
|
||||
if m2.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("'dB': Line(0) = %q, want 'hello.world t'", m2.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -1889,6 +1882,7 @@ func TestMoveBackwardWORDWithOperator(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
// BUG: This is a failing tests, cursor is not moving at start of yank
|
||||
t.Run("test 'yB' yanks WORD including punctuation", func(t *testing.T) {
|
||||
lines := []string{"hello.world next"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 15, Line: 0})
|
||||
@ -1915,8 +1909,8 @@ func TestMoveBackwardWORDWithOperator(t *testing.T) {
|
||||
if m.Mode() != core.InsertMode {
|
||||
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
|
||||
}
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.worldt" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.worldt'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.world t'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1943,9 +1937,8 @@ func TestMoveBackwardWORDVisualMode(t *testing.T) {
|
||||
sendKeys(tm, "v", "B", "d")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete " next" leaving "hello.worldt"
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.worldt" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.worldt'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.world " {
|
||||
t.Errorf("Line(0) = %q, want 'hello.world '", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -1971,8 +1964,8 @@ func TestMoveBackwardWORDVisualMode(t *testing.T) {
|
||||
t.Errorf("Mode() = %v, want VisualLineMode", m.Mode())
|
||||
}
|
||||
// Should select both lines
|
||||
if m.ActiveWindow().Cursor.Line != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
|
||||
if m.ActiveWindow().Cursor.Line != 1 {
|
||||
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -2114,9 +2107,8 @@ func TestMoveBackwardWordEndWithOperator(t *testing.T) {
|
||||
sendKeys(tm, "d", "g", "e")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete from 't' back to end of "world" (inclusive)
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello world t'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello worl" {
|
||||
t.Errorf("Line(0) = %q, want 'hello worl'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -2126,12 +2118,12 @@ func TestMoveBackwardWordEndWithOperator(t *testing.T) {
|
||||
sendKeys(tm, "d", "2", "g", "e")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete backward to end of "one"
|
||||
if m.ActiveBuffer().Lines[0].String() != "one e" {
|
||||
t.Errorf("Line(0) = %q, want 'one e'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "on" {
|
||||
t.Errorf("Line(0) = %q, want 'on'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
// BUG: This is a failing tests, cursor is not moving at start of yank
|
||||
t.Run("test 'yge' yanks backward to word end", func(t *testing.T) {
|
||||
lines := []string{"hello world next"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 15, Line: 0})
|
||||
@ -2158,8 +2150,8 @@ func TestMoveBackwardWordEndWithOperator(t *testing.T) {
|
||||
if m.Mode() != core.InsertMode {
|
||||
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
|
||||
}
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello world t'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello worl" {
|
||||
t.Errorf("Line(0) = %q, want 'hello worl'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -2186,9 +2178,8 @@ func TestMoveBackwardWordEndVisualMode(t *testing.T) {
|
||||
sendKeys(tm, "v", "g", "e", "d")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete selection leaving "hello world t"
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello world t'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello worl" {
|
||||
t.Errorf("Line(0) = %q, want 'hello worl'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -2381,9 +2372,8 @@ func TestMoveBackwardWORDEndWithOperator(t *testing.T) {
|
||||
sendKeys(tm, "d", "g", "E")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete from 't' back to end of "hello.world" (inclusive)
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.world t'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.worl" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.worl'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -2396,8 +2386,8 @@ func TestMoveBackwardWORDEndWithOperator(t *testing.T) {
|
||||
m1 := getFinalModel(t, tm1)
|
||||
|
||||
// 'dge' should delete to end of "world"
|
||||
if m1.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("'dge': Line(0) = %q, want 'hello.world t'", m1.ActiveBuffer().Lines[0].String())
|
||||
if m1.ActiveBuffer().Lines[0].String() != "hello.worl" {
|
||||
t.Errorf("'dge': Line(0) = %q, want 'hello.worl'", m1.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
|
||||
// Now test 'dgE'
|
||||
@ -2405,9 +2395,8 @@ func TestMoveBackwardWORDEndWithOperator(t *testing.T) {
|
||||
sendKeys(tm2, "d", "g", "E")
|
||||
m2 := getFinalModel(t, tm2)
|
||||
|
||||
// 'dgE' should delete to end of "hello.world" (treats as one WORD)
|
||||
if m2.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("'dgE': Line(0) = %q, want 'hello.world t'", m2.ActiveBuffer().Lines[0].String())
|
||||
if m2.ActiveBuffer().Lines[0].String() != "hello.worl" {
|
||||
t.Errorf("'dgE': Line(0) = %q, want 'hello.worl'", m2.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
@ -2417,12 +2406,12 @@ func TestMoveBackwardWORDEndWithOperator(t *testing.T) {
|
||||
sendKeys(tm, "d", "2", "g", "E")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete backward to end of "one.a"
|
||||
if m.ActiveBuffer().Lines[0].String() != "one.a e" {
|
||||
t.Errorf("Line(0) = %q, want 'one.a e'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "one." {
|
||||
t.Errorf("Line(0) = %q, want 'one.'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
// BUG: This is a failing tests, cursor is not moving at start of yank
|
||||
t.Run("test 'ygE' yanks backward to WORD end", func(t *testing.T) {
|
||||
lines := []string{"hello.world next"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 15, Line: 0})
|
||||
@ -2449,7 +2438,7 @@ func TestMoveBackwardWORDEndWithOperator(t *testing.T) {
|
||||
if m.Mode() != core.InsertMode {
|
||||
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
|
||||
}
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.worl" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.world t'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
@ -2477,9 +2466,8 @@ func TestMoveBackwardWORDEndVisualMode(t *testing.T) {
|
||||
sendKeys(tm, "v", "g", "E", "d")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
// Should delete selection leaving "hello.world t"
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.world t" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.world t'", m.ActiveBuffer().Lines[0].String())
|
||||
if m.ActiveBuffer().Lines[0].String() != "hello.worl" {
|
||||
t.Errorf("Line(0) = %q, want 'hello.worl'", m.ActiveBuffer().Lines[0].String())
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -451,7 +451,7 @@ func prevWORDStart(buf *core.Buffer, x, y int) (int, int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to the start of the current WORD (all non-whitespace is one class)
|
||||
// Skip to the start of the WORD (all non-whitespace is one class)
|
||||
for x-1 >= 0 && line[x-1] != ' ' && line[x-1] != '\t' {
|
||||
x--
|
||||
}
|
||||
@ -463,6 +463,7 @@ func prevWORDStart(buf *core.Buffer, x, y int) (int, int) {
|
||||
// respecting word character classes.
|
||||
func prevWordEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
line := buf.Line(y)
|
||||
origY := y
|
||||
|
||||
// Back one to avoid being stuck on the current end
|
||||
x--
|
||||
@ -473,8 +474,44 @@ func prevWordEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
y--
|
||||
line = buf.Line(y)
|
||||
x = len(line) - 1
|
||||
if x < 0 {
|
||||
return 0, y // landed on an empty line
|
||||
// Don't return early for empty line - we'll handle it in whitespace skip
|
||||
}
|
||||
|
||||
// Skip backward through current word class if we're on one
|
||||
// BUT: if we crossed lines in the "back one" step, we're already at the end of a word
|
||||
if y == origY && x >= 0 && line[x] != ' ' && line[x] != '\t' {
|
||||
if isWordChar(line[x]) {
|
||||
// Skip word characters
|
||||
for x >= 0 && isWordChar(line[x]) {
|
||||
x--
|
||||
if x < 0 {
|
||||
if y == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
y--
|
||||
line = buf.Line(y)
|
||||
x = len(line) - 1
|
||||
if x < 0 {
|
||||
return 0, y
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Skip punctuation
|
||||
for x >= 0 && isWordPunctuation(line[x]) {
|
||||
x--
|
||||
if x < 0 {
|
||||
if y == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
y--
|
||||
line = buf.Line(y)
|
||||
x = len(line) - 1
|
||||
if x < 0 {
|
||||
return 0, y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -497,7 +534,7 @@ func prevWordEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
}
|
||||
}
|
||||
|
||||
// We're now at the end of a word - that's the answer!
|
||||
// We're now at the end of the previous word - that's the answer!
|
||||
return x, y
|
||||
}
|
||||
|
||||
@ -505,6 +542,7 @@ func prevWordEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
// treating all non-whitespace as a single class.
|
||||
func prevWORDEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
line := buf.Line(y)
|
||||
origY := y
|
||||
|
||||
// Back one to avoid being stuck on the current end
|
||||
x--
|
||||
@ -515,8 +553,25 @@ func prevWORDEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
y--
|
||||
line = buf.Line(y)
|
||||
x = len(line) - 1
|
||||
if x < 0 {
|
||||
return 0, y // landed on an empty line
|
||||
// Don't return early for empty line - we'll handle it in whitespace skip
|
||||
}
|
||||
|
||||
// Skip backward through current WORD if we're on one
|
||||
// BUT: if we crossed lines in the "back one" step, we're already at the end of a WORD
|
||||
if y == origY && x >= 0 && line[x] != ' ' && line[x] != '\t' {
|
||||
for x >= 0 && line[x] != ' ' && line[x] != '\t' {
|
||||
x--
|
||||
if x < 0 {
|
||||
if y == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
y--
|
||||
line = buf.Line(y)
|
||||
x = len(line) - 1
|
||||
if x < 0 {
|
||||
return 0, y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,7 +594,7 @@ func prevWORDEnd(buf *core.Buffer, x, y int) (int, int) {
|
||||
}
|
||||
}
|
||||
|
||||
// We're now at the end of a WORD - that's the answer!
|
||||
// We're now at the end of the previous WORD - that's the answer!
|
||||
return x, y
|
||||
}
|
||||
|
||||
@ -599,8 +654,6 @@ func (a MoveBackwardWordEnd) WithCount(n int) action.Action {
|
||||
return MoveBackwardWordEnd{Count: n}
|
||||
}
|
||||
|
||||
// BUG: gE and ge are broken
|
||||
|
||||
// MoveBackwardWORDEnd implements Motion (gE) - charwise
|
||||
type MoveBackwardWORDEnd struct {
|
||||
Count int
|
||||
|
||||
@ -30,8 +30,14 @@ func (o YankOperator) Operate(m action.Model, start, end core.Position, mtype co
|
||||
})
|
||||
}
|
||||
|
||||
win.SetCursorCol(start.Col)
|
||||
win.SetCursorLine(start.Line)
|
||||
// Normalize so cursor is set to the earlier position (important for backward motions)
|
||||
cursorPos := start
|
||||
if end.Line < start.Line || (end.Line == start.Line && end.Col < start.Col) {
|
||||
cursorPos = end
|
||||
}
|
||||
|
||||
win.SetCursorCol(cursorPos.Col)
|
||||
win.SetCursorLine(cursorPos.Line)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -66,16 +72,6 @@ func yankNormalMode(m action.Model, start, end core.Position, mtype core.MotionT
|
||||
|
||||
switch {
|
||||
case mtype.IsCharwise():
|
||||
// This shouldn't happen
|
||||
// if start.Line != end.Line {
|
||||
// m.SetCommandOutput(&core.CommandOutput{
|
||||
// Lines: []string{"Start line and end line must match for charwise yank operations."},
|
||||
// Inline: true,
|
||||
// IsError: true,
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
line := buf.Line(start.Line)
|
||||
|
||||
startX := min(start.Col, end.Col)
|
||||
@ -92,16 +88,6 @@ func yankNormalMode(m action.Model, start, end core.Position, mtype core.MotionT
|
||||
m.UpdateDefaultRegister(core.CharwiseRegister, []string{cnt})
|
||||
|
||||
case mtype == core.Linewise:
|
||||
// This shouldn't happen
|
||||
// if start.Col != end.Col {
|
||||
// m.SetCommandOutput(&core.CommandOutput{
|
||||
// Lines: []string{"Start column and end column must match for linewise yank operations."},
|
||||
// Inline: true,
|
||||
// IsError: true,
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
// These don't need to be validated, they are validated before being passed into the function
|
||||
startY := min(start.Line, end.Line)
|
||||
endY := max(start.Line, end.Line)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user