feat: implemented '_' action, and tested.
This commit is contained in:
parent
84a7983a21
commit
2cadb09350
@ -14,8 +14,8 @@ func TestMoveToBottom(t *testing.T) {
|
||||
sendKeys(tm, "G")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||
if m.CursorY() != 5 {
|
||||
t.Errorf("CursorY() = %d, want 5", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -24,8 +24,8 @@ func TestMoveToBottom(t *testing.T) {
|
||||
sendKeys(tm, "G")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||
if m.CursorY() != 5 {
|
||||
t.Errorf("CursorY() = %d, want 5", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -34,23 +34,23 @@ func TestMoveToBottom(t *testing.T) {
|
||||
sendKeys(tm, "G")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||
if m.CursorY() != 5 {
|
||||
t.Errorf("CursorY() = %d, want 5", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'G' clamps cursor.x", func(t *testing.T) {
|
||||
t.Run("test 'G' clamps CursorX()", func(t *testing.T) {
|
||||
lines := []string{"long line here", "short"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 10, Line: 0})
|
||||
sendKeys(tm, "G")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
||||
if m.CursorY() != 1 {
|
||||
t.Errorf("CursorY() = %d, want 1", m.CursorY())
|
||||
}
|
||||
want := len(lines[1])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
|
||||
@ -60,8 +60,8 @@ func TestMoveToBottom(t *testing.T) {
|
||||
sendKeys(tm, "G")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -72,8 +72,8 @@ func TestMoveToTop(t *testing.T) {
|
||||
sendKeys(tm, "g", "g")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -82,8 +82,8 @@ func TestMoveToTop(t *testing.T) {
|
||||
sendKeys(tm, "g", "g")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -92,28 +92,28 @@ func TestMoveToTop(t *testing.T) {
|
||||
sendKeys(tm, "g", "g")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test 'gg' clamps cursor.x", func(t *testing.T) {
|
||||
t.Run("test 'gg' clamps CursorX()", func(t *testing.T) {
|
||||
lines := []string{"short", "long line here"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 10, Line: 1})
|
||||
sendKeys(tm, "g", "g")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("CursorY() = %d, want 0", m.CursorY())
|
||||
}
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// --- 0 and $ Tests ---
|
||||
// --- 0, $ and _ Tests ---
|
||||
|
||||
func TestMoveToLineStart(t *testing.T) {
|
||||
t.Run("test '0' from middle of line", func(t *testing.T) {
|
||||
@ -121,8 +121,8 @@ func TestMoveToLineStart(t *testing.T) {
|
||||
sendKeys(tm, "0")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -132,8 +132,8 @@ func TestMoveToLineStart(t *testing.T) {
|
||||
sendKeys(tm, "0")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -142,8 +142,8 @@ func TestMoveToLineStart(t *testing.T) {
|
||||
sendKeys(tm, "0")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -153,8 +153,8 @@ func TestMoveToLineStart(t *testing.T) {
|
||||
sendKeys(tm, "0")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -163,8 +163,8 @@ func TestMoveToLineStart(t *testing.T) {
|
||||
sendKeys(tm, "0")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 2 {
|
||||
t.Errorf("cursor.y = %d, want 2", m.cursor.y)
|
||||
if m.CursorY() != 2 {
|
||||
t.Errorf("CursorY() = %d, want 2", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -177,8 +177,8 @@ func TestMoveToLineEnd(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
|
||||
@ -189,8 +189,8 @@ func TestMoveToLineEnd(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
|
||||
@ -201,8 +201,8 @@ func TestMoveToLineEnd(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
|
||||
@ -212,8 +212,8 @@ func TestMoveToLineEnd(t *testing.T) {
|
||||
sendKeys(tm, "$")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -222,8 +222,87 @@ func TestMoveToLineEnd(t *testing.T) {
|
||||
sendKeys(tm, "$")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 2 {
|
||||
t.Errorf("cursor.y = %d, want 2", m.cursor.y)
|
||||
if m.CursorY() != 2 {
|
||||
t.Errorf("CursorY() = %d, want 2", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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, action.Position{Col: 6, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test '_' from middle of line with leading whitespace", func(t *testing.T) {
|
||||
lines := []string{" hello world"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 10, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test '_' from start of line with leading whitespace", func(t *testing.T) {
|
||||
lines := []string{" hello world"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 0, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test '_' from start of line with no leading whitespace", func(t *testing.T) {
|
||||
lines := []string{"hello world"}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 0, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test '_' from middle of line with only whitespace", func(t *testing.T) {
|
||||
lines := []string{" "}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 2, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test '_' from end of line with only whitespace", func(t *testing.T) {
|
||||
lines := []string{" "}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 4, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test '_' on empty line", func(t *testing.T) {
|
||||
lines := []string{""}
|
||||
tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 0, Line: 0})
|
||||
sendKeys(tm, "_")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ func NewNormalKeymap() *Keymap {
|
||||
"gg": motion.MoveToTop{},
|
||||
"0": motion.MoveToLineStart{},
|
||||
"$": motion.MoveToLineEnd{},
|
||||
"_": motion.MoveToLineContentStart{},
|
||||
"w": motion.MoveForwardWord{Count: 1},
|
||||
"e": motion.MoveForwardWordEnd{Count: 1},
|
||||
"b": motion.MoveBackwardWord{Count: 1},
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package motion
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"git.gophernest.net/azpect/TextEditor/internal/action"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
// MoveToTop implements Motion (gg)
|
||||
@ -40,3 +40,26 @@ func (a MoveToLineEnd) Execute(m action.Model) tea.Cmd {
|
||||
m.ClampCursorX()
|
||||
return nil
|
||||
}
|
||||
|
||||
// MoveToLineContentStart implements Motion (_)
|
||||
type MoveToLineContentStart struct{}
|
||||
|
||||
func (a MoveToLineContentStart) Execute(m action.Model) tea.Cmd {
|
||||
line := m.Line(m.CursorY())
|
||||
x := 0
|
||||
for x < len(line) {
|
||||
ch := line[x]
|
||||
if ch != ' ' && ch != '\t' {
|
||||
break
|
||||
}
|
||||
x++
|
||||
}
|
||||
|
||||
// If we are on the last char, we overflew, back once
|
||||
if x == len(line) && x > 0 {
|
||||
x--
|
||||
}
|
||||
|
||||
m.SetCursorX(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user