package editor import ( "testing" "git.gophernest.net/azpect/TextEditor/internal/core" ) // --- G and gg Tests --- func TestMoveToBottom(t *testing.T) { t.Run("test 'G' from top", func(t *testing.T) { tm := newTestModel(t) sendKeys(tm, "G") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 5 { t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line) } }) t.Run("test 'G' from middle", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 0, Line: 2}) sendKeys(tm, "G") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 5 { t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line) } }) t.Run("test 'G' already at bottom", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 0, Line: 5}) sendKeys(tm, "G") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 5 { t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line) } }) t.Run("test 'G' clamps CursorX()", func(t *testing.T) { lines := []string{"long line here", "short"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 10, Line: 0}) sendKeys(tm, "G") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 1 { t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line) } want := len(lines[1]) if m.ActiveWindow().Cursor.Col != want { t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want) } }) t.Run("test 'G' on single line file", func(t *testing.T) { lines := []string{"only line"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "G") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 0 { t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line) } }) } func TestMoveToTop(t *testing.T) { t.Run("test 'gg' from bottom", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 0, Line: 5}) sendKeys(tm, "g", "g") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 0 { t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line) } }) t.Run("test 'gg' from middle", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 0, Line: 3}) sendKeys(tm, "g", "g") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 0 { t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line) } }) t.Run("test 'gg' already at top", func(t *testing.T) { tm := newTestModel(t) sendKeys(tm, "g", "g") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 0 { t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line) } }) t.Run("test 'gg' clamps CursorX()", func(t *testing.T) { lines := []string{"short", "long line here"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 10, Line: 1}) sendKeys(tm, "g", "g") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 0 { t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line) } want := len(lines[0]) if m.ActiveWindow().Cursor.Col != want { t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want) } }) } // --- 0, $ and _ Tests --- func TestMoveToLineStart(t *testing.T) { t.Run("test '0' from middle of line", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 3, Line: 0}) sendKeys(tm, "0") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '0' from end of line", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: len(lines[0]), Line: 0}) sendKeys(tm, "0") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '0' already at start", func(t *testing.T) { tm := newTestModel(t) sendKeys(tm, "0") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '0' on empty line", func(t *testing.T) { lines := []string{""} tm := newTestModelWithLines(t, lines) sendKeys(tm, "0") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '0' preserves line", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 3, Line: 2}) sendKeys(tm, "0") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 2 { t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line) } }) } func TestMoveToLineEnd(t *testing.T) { t.Run("test '$' from start of line", func(t *testing.T) { lines := []string{"hello"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "$") m := getFinalModel(t, tm) want := len(lines[0]) - 1 if m.ActiveWindow().Cursor.Col != want { t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want) } }) t.Run("test '$' from middle of line", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0}) sendKeys(tm, "$") m := getFinalModel(t, tm) want := len(lines[0]) - 1 if m.ActiveWindow().Cursor.Col != want { t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want) } }) t.Run("test '$' already at end", func(t *testing.T) { lines := []string{"hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: len(lines[0]), Line: 0}) sendKeys(tm, "$") m := getFinalModel(t, tm) want := len(lines[0]) - 1 if m.ActiveWindow().Cursor.Col != want { t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want) } }) t.Run("test '$' on empty line", func(t *testing.T) { lines := []string{""} tm := newTestModelWithLines(t, lines) sendKeys(tm, "$") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '$' preserves line", func(t *testing.T) { tm := newTestModelWithCursorPos(t, core.Position{Col: 0, Line: 2}) sendKeys(tm, "$") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 2 { t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line) } }) } func TestMoveToLineContentStart(t *testing.T) { t.Run("test '_' from middle of line with no leading whitespace", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 6, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '_' from middle of line with leading whitespace", func(t *testing.T) { lines := []string{" hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 10, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '_' from start of line with leading whitespace", func(t *testing.T) { lines := []string{" hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '_' from start of line with no leading whitespace", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '_' from middle of line with only whitespace", func(t *testing.T) { lines := []string{" "} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '_' from end of line with only whitespace", func(t *testing.T) { lines := []string{" "} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '_' on empty line", func(t *testing.T) { lines := []string{""} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "_") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) } func TestMoveToLineContentStartAlias(t *testing.T) { t.Run("test '^' from middle of line with no leading whitespace", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 6, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '^' from middle of line with leading whitespace", func(t *testing.T) { lines := []string{" hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 10, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '^' from start of line with leading whitespace", func(t *testing.T) { lines := []string{" hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '^' from start of line with no leading whitespace", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '^' from middle of line with only whitespace", func(t *testing.T) { lines := []string{" "} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '^' from end of line with only whitespace", func(t *testing.T) { lines := []string{" "} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '^' on empty line", func(t *testing.T) { lines := []string{""} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "^") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) } // --- | (Pipe / Move to Column) Tests --- // In Vim, | moves to column N (1-indexed). So: // - | = 1| = column 1 = index 0 // - 5| = column 5 = index 4 // - 10| = column 10 = index 9 func TestMoveToColumn(t *testing.T) { t.Run("test '|' alone goes to column 1 (index 0)", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0}) sendKeys(tm, "|") m := getFinalModel(t, tm) // | with no count = 1| = column 1 = index 0 if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '1|' goes to column 1 (index 0)", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0}) sendKeys(tm, "1", "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '5|' goes to column 5 (index 4)", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "5", "|") m := getFinalModel(t, tm) // Column 5 = index 4 (the 'o' in hello) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '10|' goes to column 10 (index 9)", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "1", "0", "|") m := getFinalModel(t, tm) // Column 10 = index 9 (the 'l' in world) if m.ActiveWindow().Cursor.Col != 9 { t.Errorf("CursorX() = %d, want 9", m.ActiveWindow().Cursor.Col) } }) t.Run("test '|' already at column 1", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '5|' already at column 5", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0}) sendKeys(tm, "5", "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) } func TestMoveToColumnClamp(t *testing.T) { t.Run("test '20|' clamps to end of short line", func(t *testing.T) { lines := []string{"hello"} // 5 chars, max index 4 tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "2", "0", "|") m := getFinalModel(t, tm) // Column 20 exceeds line length, should clamp to last char (index 4) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '100|' clamps to end of line", func(t *testing.T) { lines := []string{"hello world"} // 11 chars, max index 10 tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "1", "0", "0", "|") m := getFinalModel(t, tm) // Should clamp to last char (index 10) if m.ActiveWindow().Cursor.Col != 10 { t.Errorf("CursorX() = %d, want 10", m.ActiveWindow().Cursor.Col) } }) t.Run("test '6|' clamps on 5-char line", func(t *testing.T) { lines := []string{"hello"} // 5 chars tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "6", "|") m := getFinalModel(t, tm) // Column 6 = index 5, but line only has 5 chars (max index 4) if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '|' on empty line stays at 0", func(t *testing.T) { lines := []string{""} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '5|' on empty line stays at 0", func(t *testing.T) { lines := []string{""} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "5", "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '3|' on 2-char line clamps", func(t *testing.T) { lines := []string{"ab"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "3", "|") m := getFinalModel(t, tm) // Column 3 = index 2, but line only has 2 chars (max index 1) if m.ActiveWindow().Cursor.Col != 1 { t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col) } }) } func TestMoveToColumnPreservesLine(t *testing.T) { t.Run("test '|' preserves Y position", func(t *testing.T) { lines := []string{"line one", "line two", "line three"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 1}) sendKeys(tm, "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 1 { t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line) } }) t.Run("test '5|' preserves Y position", func(t *testing.T) { lines := []string{"line one", "line two", "line three"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 2}) sendKeys(tm, "5", "|") m := getFinalModel(t, tm) if m.ActiveWindow().Cursor.Line != 2 { t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line) } }) t.Run("test '|' on different lines", func(t *testing.T) { lines := []string{"short", "longer line here"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 10, Line: 1}) sendKeys(tm, "|") m := getFinalModel(t, tm) 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) } }) } func TestMoveToColumnWithWhitespace(t *testing.T) { t.Run("test '5|' with leading whitespace", func(t *testing.T) { lines := []string{" hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "5", "|") m := getFinalModel(t, tm) // Column 5 = index 4 = 'h' in " hello" if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test '3|' lands on whitespace", func(t *testing.T) { lines := []string{" hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0}) sendKeys(tm, "3", "|") m := getFinalModel(t, tm) // Column 3 = index 2 = third space if m.ActiveWindow().Cursor.Col != 2 { t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col) } }) t.Run("test '|' with tabs", func(t *testing.T) { lines := []string{"\thello"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0}) sendKeys(tm, "|") m := getFinalModel(t, tm) // | goes to column 1 = index 0 = the tab if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test '2|' with tabs", func(t *testing.T) { lines := []string{"\thello"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "2", "|") m := getFinalModel(t, tm) // Column 2 = index 1 = 'h' in "\thello" if m.ActiveWindow().Cursor.Col != 1 { t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col) } }) } func TestMoveToColumnWithOperator(t *testing.T) { t.Run("test 'd|' deletes to column 1", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0}) sendKeys(tm, "d", "|") m := getFinalModel(t, tm) // Deletes from column 1 to current position (exclusive), so "hello" deleted // Result depends on inclusive/exclusive behavior // In Vim: d| from col 5 deletes chars 0-4, leaving " world" if m.ActiveBuffer().Lines[0].String() != " world" { t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0].String()) } }) t.Run("test 'd5|' deletes to column 5", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "d", "5", "|") m := getFinalModel(t, tm) // Deletes from cursor (0) to column 5 (index 4), so "hell" deleted // Result: "o world" if m.ActiveBuffer().Lines[0].String() != "o world" { t.Errorf("Line(0) = %q, want 'o world'", m.ActiveBuffer().Lines[0].String()) } }) t.Run("test 'y5|' yanks to column 5", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "y", "5", "|") m := getFinalModel(t, tm) reg, ok := m.GetRegister('"') if !ok { t.Fatal("unnamed register not found") } // Should yank "hell" (indices 0-3, up to but not including col 5) if len(reg.Content) != 1 || reg.Content[0] != "hell" { t.Errorf("register content = %q, want 'hell'", reg.Content) } }) t.Run("test 'y|' yanks to column 1 (nothing if at start)", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "y", "|") m := getFinalModel(t, tm) reg, ok := m.GetRegister('"') if !ok { t.Fatal("unnamed register not found") } // At col 0, y| should yank nothing (empty string) if len(reg.Content) != 1 || reg.Content[0] != "" { t.Errorf("register content = %q, want ''", reg.Content) } }) } func TestMoveToColumnInVisualMode(t *testing.T) { t.Run("test 'v5|' selects to column 5", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "v", "5", "|") m := getFinalModel(t, tm) if m.ActiveWindow().Anchor.Col != 0 { t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col) } if m.ActiveWindow().Cursor.Col != 4 { t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col) } }) t.Run("test 'v|' selects backward to column 1", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0}) sendKeys(tm, "v", "|") m := getFinalModel(t, tm) if m.ActiveWindow().Anchor.Col != 5 { t.Errorf("AnchorX() = %d, want 5", m.ActiveWindow().Anchor.Col) } if m.ActiveWindow().Cursor.Col != 0 { t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col) } }) t.Run("test 'v5|d' deletes selection to column 5", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0}) sendKeys(tm, "v", "5", "|", "d") m := getFinalModel(t, tm) // Visual selection from 0 to 4 inclusive, delete "hello" if m.ActiveBuffer().Lines[0].String() != " world" { t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0].String()) } }) }