163 lines
4.6 KiB
Go
163 lines
4.6 KiB
Go
package editor
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"git.gophernest.net/azpect/TextEditor/internal/core"
|
|
)
|
|
|
|
func TestScreenTopMotion(t *testing.T) {
|
|
t.Run("H moves to the top visible line first non-blank", func(t *testing.T) {
|
|
lines := screenMotionLines(100)
|
|
lines[82] = " top"
|
|
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "H")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 82, 4)
|
|
})
|
|
|
|
t.Run("3H moves to third visible line from top", func(t *testing.T) {
|
|
lines := screenMotionLines(100)
|
|
lines[84] = " third"
|
|
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "3", "H")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 84, 2)
|
|
})
|
|
|
|
t.Run("H count clamps to bottom visible line", func(t *testing.T) {
|
|
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "9", "9", "9", "H")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 99, 0)
|
|
})
|
|
}
|
|
|
|
func TestScreenMiddleMotion(t *testing.T) {
|
|
t.Run("M moves to middle visible line first non-blank", func(t *testing.T) {
|
|
lines := screenMotionLines(100)
|
|
lines[90] = "\tmiddle"
|
|
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "M")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 90, 1)
|
|
})
|
|
|
|
t.Run("count before M is ignored", func(t *testing.T) {
|
|
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "9", "M")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 90, 0)
|
|
})
|
|
}
|
|
|
|
func TestScreenBottomMotion(t *testing.T) {
|
|
t.Run("L moves to bottom visible line first non-blank", func(t *testing.T) {
|
|
lines := screenMotionLines(100)
|
|
lines[99] = " bottom"
|
|
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "L")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 99, 2)
|
|
})
|
|
|
|
t.Run("3L moves to third visible line from bottom", func(t *testing.T) {
|
|
lines := screenMotionLines(100)
|
|
lines[97] = " above"
|
|
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "3", "L")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 97, 4)
|
|
})
|
|
|
|
t.Run("L count clamps to top visible line", func(t *testing.T) {
|
|
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "9", "9", "9", "L")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 82, 0)
|
|
})
|
|
}
|
|
|
|
func TestScreenMotionsEdgeCases(t *testing.T) {
|
|
t.Run("small file: H and L clamp to file bounds", func(t *testing.T) {
|
|
lines := []string{" one", "two", "three", "four", "five"}
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "L")
|
|
sendKeys(tm, "H")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 0, 4)
|
|
})
|
|
|
|
t.Run("M on blank middle line lands at column 0", func(t *testing.T) {
|
|
lines := screenMotionLines(100)
|
|
lines[90] = ""
|
|
|
|
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "M")
|
|
|
|
m := getFinalModel(t, tm)
|
|
assertCursorPos(t, m, 90, 0)
|
|
})
|
|
}
|
|
|
|
func TestScreenMotionsIntegration(t *testing.T) {
|
|
t.Run("dH treats H as a linewise motion", func(t *testing.T) {
|
|
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "d", "H")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveBuffer().LineCount() != 82 {
|
|
t.Errorf("LineCount() = %d, want 82", m.ActiveBuffer().LineCount())
|
|
}
|
|
if m.ActiveBuffer().Line(81) != "line 81" {
|
|
t.Errorf("Line(81) = %q, want %q", m.ActiveBuffer().Line(81), "line 81")
|
|
}
|
|
})
|
|
|
|
t.Run("H works as a visual line motion", func(t *testing.T) {
|
|
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
|
|
sendKeys(tm, "G", "V", "H", "d")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveBuffer().LineCount() != 82 {
|
|
t.Errorf("LineCount() = %d, want 82", m.ActiveBuffer().LineCount())
|
|
}
|
|
if m.Mode() != core.NormalMode {
|
|
t.Errorf("Mode() = %v, want %v", m.Mode(), core.NormalMode)
|
|
}
|
|
})
|
|
}
|
|
|
|
func screenMotionLines(n int) []string {
|
|
lines := make([]string, n)
|
|
for i := range n {
|
|
lines[i] = fmt.Sprintf("line %d", i)
|
|
}
|
|
return lines
|
|
}
|
|
|
|
func assertCursorPos(t *testing.T, m *Model, wantLine, wantCol int) {
|
|
t.Helper()
|
|
if m.ActiveWindow().Cursor.Line != wantLine {
|
|
t.Errorf("Cursor.Line = %d, want %d", m.ActiveWindow().Cursor.Line, wantLine)
|
|
}
|
|
if m.ActiveWindow().Cursor.Col != wantCol {
|
|
t.Errorf("Cursor.Col = %d, want %d", m.ActiveWindow().Cursor.Col, wantCol)
|
|
}
|
|
}
|