Compare commits

...

2 Commits

Author SHA1 Message Date
Hayden Hargreaves
b1b3edf810 feat: this is huge, and needs some review, but for now its good
The tests are not passing, something to do with view I think.
2026-02-26 23:18:18 -07:00
Hayden Hargreaves
9b1bf35a8e wip: implemented model builder, this is nice :)
Builder pattern is actually so goated
2026-02-26 22:21:29 -07:00
33 changed files with 2601 additions and 2245 deletions

View File

@ -9,10 +9,20 @@ import (
) )
func main() { func main() {
m, _ := tea.NewProgram( buf := action.NewBufferBuilder().
editor.NewModel([]string{""}, action.Position{Line: 0, Col: 0}), Build()
tea.WithAltScreen(),
).Run() win := action.NewWindowBuilder().
WithBuffer(&buf).
Build()
model := editor.NewModelBuilder().
AddBuffer(&buf).
AddWindow(&win).
WithActiveWindowId(win.Id).
Build()
m, _ := tea.NewProgram(model, tea.WithAltScreen()).Run()
final, ok := m.(*editor.Model) final, ok := m.(*editor.Model)
if ok { if ok {
@ -24,5 +34,4 @@ func main() {
} else { } else {
fmt.Printf("PRINTING ALL: %+v\n", m) fmt.Printf("PRINTING ALL: %+v\n", m)
} }
} }

View File

@ -8,8 +8,11 @@ type ChangeToEndOfLine struct {
} }
func (a ChangeToEndOfLine) Execute(m Model) tea.Cmd { func (a ChangeToEndOfLine) Execute(m Model) tea.Cmd {
pos := m.CursorX() win := m.ActiveWindow()
line := m.Line(m.CursorY()) buf := m.ActiveBuffer()
pos := win.Cursor.Col
line := buf.Lines[win.Cursor.Line]
// Save deleted text to register // Save deleted text to register
if pos < len(line) { if pos < len(line) {
@ -17,7 +20,7 @@ func (a ChangeToEndOfLine) Execute(m Model) tea.Cmd {
} }
// Delete to end of line // Delete to end of line
m.SetLine(m.CursorY(), line[:pos]) buf.SetLine(win.Cursor.Line, line[:pos])
// Enter insert mode // Enter insert mode
m.SetMode(InsertMode) m.SetMode(InsertMode)
@ -38,8 +41,11 @@ type SubstituteChar struct {
} }
func (a SubstituteChar) Execute(m Model) tea.Cmd { func (a SubstituteChar) Execute(m Model) tea.Cmd {
pos := m.CursorX() win := m.ActiveWindow()
line := m.Line(m.CursorY()) buf := m.ActiveBuffer()
pos := win.Cursor.Col
line := buf.Lines[win.Cursor.Line]
// Calculate how many chars to delete (limited by line length) // Calculate how many chars to delete (limited by line length)
count := min(a.Count, len(line)-pos) count := min(a.Count, len(line)-pos)
@ -49,7 +55,7 @@ func (a SubstituteChar) Execute(m Model) tea.Cmd {
m.UpdateDefaultRegister(CharwiseRegister, []string{line[pos : pos+count]}) m.UpdateDefaultRegister(CharwiseRegister, []string{line[pos : pos+count]})
// Delete the characters // Delete the characters
m.SetLine(m.CursorY(), line[:pos]+line[pos+count:]) buf.SetLine(win.Cursor.Line, line[:pos]+line[pos+count:])
} }
// Enter insert mode // Enter insert mode
@ -71,29 +77,31 @@ type SubstituteLine struct {
} }
func (a SubstituteLine) Execute(m Model) tea.Cmd { func (a SubstituteLine) Execute(m Model) tea.Cmd {
y := m.CursorY() win := m.ActiveWindow()
buf := m.ActiveBuffer()
y := win.Cursor.Line
// Calculate how many lines to substitute // Calculate how many lines to substitute
count := min(a.Count, m.LineCount()-y) count := min(a.Count, buf.LineCount()-y)
var lines []string var lines []string
// Collect and delete lines // Collect and delete lines
for range count { for range count {
lines = append(lines, m.Line(y)) lines = append(lines, buf.Lines[y])
m.DeleteLine(y) buf.DeleteLine(y)
} }
// Save deleted lines to register // Save deleted lines to register
m.UpdateDefaultRegister(LinewiseRegister, lines) m.UpdateDefaultRegister(LinewiseRegister, lines)
// Insert empty line at original position // Insert empty line at original position
insertY := min(y, m.LineCount()) insertY := min(y, buf.LineCount())
m.InsertLine(insertY, "") buf.InsertLine(insertY, "")
// Position cursor // Position cursor
m.SetCursorY(insertY) win.SetCursorPos(insertY, 0)
m.SetCursorX(0)
// Enter insert mode // Enter insert mode
m.SetMode(InsertMode) m.SetMode(InsertMode)

View File

@ -8,11 +8,14 @@ type DeleteChar struct {
} }
func (a DeleteChar) Execute(m Model) tea.Cmd { func (a DeleteChar) Execute(m Model) tea.Cmd {
pos := m.CursorX() win := m.ActiveWindow()
line := m.Line(m.CursorY()) buf := m.ActiveBuffer()
pos := win.Cursor.Col
line := buf.Lines[win.Cursor.Line]
for i := 0; i < a.Count && pos < len(line); i++ { for i := 0; i < a.Count && pos < len(line); i++ {
line = line[:pos] + line[pos+1:] line = line[:pos] + line[pos+1:]
m.SetLine(m.CursorY(), line) buf.SetLine(win.Cursor.Line, line)
} }
return nil return nil
@ -27,46 +30,47 @@ type DeleteToEndOfLine struct {
} }
func (a DeleteToEndOfLine) Execute(m Model) tea.Cmd { func (a DeleteToEndOfLine) Execute(m Model) tea.Cmd {
// Delete to end of line win := m.ActiveWindow()
pos := m.CursorX() buf := m.ActiveBuffer()
line := m.Line(m.CursorY())
m.SetLine(m.CursorY(), line[:pos]) // Delete to end of line
m.SetCursorX(pos - 1) pos := win.Cursor.Col
line := buf.Lines[win.Cursor.Line]
buf.SetLine(win.Cursor.Line, line[:pos])
win.SetCursorCol(pos - 1)
// If count is greater, than we will delete the next N - 1 lines below // If count is greater, than we will delete the next N - 1 lines below
initY := m.CursorY() initY := win.Cursor.Line
if a.Count > 1 { if a.Count > 1 {
// Copied from `internal/operator/delete.go` // Copied from `internal/operator/delete.go`
opCount := min(a.Count-1, m.LineCount()-m.CursorY()) opCount := min(a.Count-1, buf.LineCount()-win.Cursor.Line)
// Down one // Down one
m.SetCursorY(initY + 1) win.SetCursorLine(initY + 1)
for range opCount { for range opCount {
y := m.CursorY() // Changed from the copied code y := win.Cursor.Line // Changed from the copied code
// Stop if were on the starting line // Stop if were on the starting line
if y == initY { if y == initY {
break break
} }
m.DeleteLine(y) buf.DeleteLine(y)
if m.LineCount() == 0 { if buf.LineCount() == 0 {
m.InsertLine(0, "") buf.InsertLine(0, "")
} }
if y >= m.LineCount() { if y >= buf.LineCount() {
y = m.LineCount() - 1 y = buf.LineCount() - 1
} }
m.SetCursorY(y) win.SetCursorLine(y)
m.ClampCursorX()
} }
} }
m.SetCursorY(initY) win.SetCursorLine(initY)
m.ClampCursorX()
return nil return nil
} }

View File

@ -28,8 +28,8 @@ type EnterInsertAfter struct {
} }
func (a EnterInsertAfter) Execute(m Model) tea.Cmd { func (a EnterInsertAfter) Execute(m Model) tea.Cmd {
m.SetCursorX(m.CursorX() + 1) win := m.ActiveWindow()
m.ClampCursorX() win.SetCursorCol(win.Cursor.Col + 1)
// Start recording // Start recording
m.SetInsertRecording(a.Count, a) m.SetInsertRecording(a.Count, a)
@ -47,8 +47,8 @@ type EnterInsertLineStart struct {
} }
func (a EnterInsertLineStart) Execute(m Model) tea.Cmd { func (a EnterInsertLineStart) Execute(m Model) tea.Cmd {
m.SetCursorX(0) win := m.ActiveWindow()
m.ClampCursorX() win.SetCursorCol(0)
// Start recording // Start recording
m.SetInsertRecording(a.Count, a) m.SetInsertRecording(a.Count, a)
@ -66,8 +66,9 @@ type EnterInsertLineEnd struct {
} }
func (a EnterInsertLineEnd) Execute(m Model) tea.Cmd { func (a EnterInsertLineEnd) Execute(m Model) tea.Cmd {
m.SetCursorX(len(m.Line(m.CursorY()))) win := m.ActiveWindow()
m.ClampCursorX() buf := m.ActiveBuffer()
win.SetCursorCol(len(buf.Lines[win.Cursor.Line]))
// Start recording // Start recording
m.SetInsertRecording(a.Count, a) m.SetInsertRecording(a.Count, a)
@ -85,16 +86,18 @@ type OpenLineBelow struct {
} }
func (a OpenLineBelow) Execute(m Model) tea.Cmd { func (a OpenLineBelow) Execute(m Model) tea.Cmd {
pos := m.CursorY() win := m.ActiveWindow()
buf := m.ActiveBuffer()
if pos >= m.LineCount() { pos := win.Cursor.Line
m.InsertLine(m.LineCount(), "")
if pos >= buf.LineCount() {
buf.InsertLine(buf.LineCount(), "")
} else { } else {
m.InsertLine(pos+1, "") buf.InsertLine(pos+1, "")
} }
m.SetCursorY(m.CursorY() + 1) win.SetCursorPos(win.Cursor.Line+1, 0)
m.SetCursorX(0)
// Start recording // Start recording
m.SetInsertRecording(a.Count, a) m.SetInsertRecording(a.Count, a)
@ -112,9 +115,12 @@ type OpenLineAbove struct {
} }
func (a OpenLineAbove) Execute(m Model) tea.Cmd { func (a OpenLineAbove) Execute(m Model) tea.Cmd {
pos := m.CursorY() win := m.ActiveWindow()
m.InsertLine(pos, "") buf := m.ActiveBuffer()
m.SetCursorX(0)
pos := win.Cursor.Line
buf.InsertLine(pos, "")
win.SetCursorCol(0)
// Start recording // Start recording
m.SetInsertRecording(a.Count, a) m.SetInsertRecording(a.Count, a)
@ -134,14 +140,17 @@ type InsertChar struct {
} }
func (a InsertChar) Execute(m Model) tea.Cmd { func (a InsertChar) Execute(m Model) tea.Cmd {
x, y := m.CursorX(), m.CursorY() win := m.ActiveWindow()
l := m.Line(y) buf := m.ActiveBuffer()
x, y := win.Cursor.Col, win.Cursor.Line
l := buf.Lines[y]
if x < len(l) { if x < len(l) {
m.SetLine(y, l[:x]+a.Char+l[x:]) buf.SetLine(y, l[:x]+a.Char+l[x:])
} else { } else {
m.SetLine(y, l+a.Char) buf.SetLine(y, l+a.Char)
} }
m.SetCursorX(x + len(a.Char)) win.SetCursorCol(x + len(a.Char))
return nil return nil
} }
@ -149,16 +158,18 @@ func (a InsertChar) Execute(m Model) tea.Cmd {
type InsertNewline struct{} type InsertNewline struct{}
func (a InsertNewline) Execute(m Model) tea.Cmd { func (a InsertNewline) Execute(m Model) tea.Cmd {
x, y := m.CursorX(), m.CursorY() win := m.ActiveWindow()
l := m.Line(y) buf := m.ActiveBuffer()
x, y := win.Cursor.Col, win.Cursor.Line
l := buf.Lines[y]
if x == len(l) { if x == len(l) {
m.InsertLine(y+1, "") buf.InsertLine(y+1, "")
} else { } else {
m.SetLine(y, l[:x]) buf.SetLine(y, l[:x])
m.InsertLine(y+1, l[x:]) buf.InsertLine(y+1, l[x:])
} }
m.SetCursorY(y + 1) win.SetCursorPos(y+1, 0)
m.SetCursorX(0)
return nil return nil
} }
@ -166,18 +177,20 @@ func (a InsertNewline) Execute(m Model) tea.Cmd {
type InsertBackspace struct{} type InsertBackspace struct{}
func (a InsertBackspace) Execute(m Model) tea.Cmd { func (a InsertBackspace) Execute(m Model) tea.Cmd {
x, y := m.CursorX(), m.CursorY() win := m.ActiveWindow()
l := m.Line(y) buf := m.ActiveBuffer()
x, y := win.Cursor.Col, win.Cursor.Line
l := buf.Lines[y]
if x > 0 { if x > 0 {
m.SetLine(y, l[:x-1]+l[x:]) buf.SetLine(y, l[:x-1]+l[x:])
m.SetCursorX(x - 1) win.SetCursorCol(x - 1)
} else if y > 0 { } else if y > 0 {
prevLine := m.Line(y - 1) prevLine := buf.Lines[y-1]
newX := len(prevLine) newX := len(prevLine)
m.SetLine(y-1, prevLine+l) buf.SetLine(y-1, prevLine+l)
m.DeleteLine(y) buf.DeleteLine(y)
m.SetCursorY(y - 1) win.SetCursorPos(y-1, newX)
m.SetCursorX(newX)
} }
return nil return nil
} }
@ -186,14 +199,17 @@ func (a InsertBackspace) Execute(m Model) tea.Cmd {
type InsertDelete struct{} type InsertDelete struct{}
func (a InsertDelete) Execute(m Model) tea.Cmd { func (a InsertDelete) Execute(m Model) tea.Cmd {
x, y := m.CursorX(), m.CursorY() win := m.ActiveWindow()
l := m.Line(y) buf := m.ActiveBuffer()
if x == len(l) && y < m.LineCount()-1 {
nextLine := m.Line(y + 1) x, y := win.Cursor.Col, win.Cursor.Line
m.SetLine(y, l+nextLine) l := buf.Lines[y]
m.DeleteLine(y + 1) if x == len(l) && y < buf.LineCount()-1 {
nextLine := buf.Lines[y+1]
buf.SetLine(y, l+nextLine)
buf.DeleteLine(y + 1)
} else if x < len(l) { } else if x < len(l) {
m.SetLine(y, l[:x]+l[x+1:]) buf.SetLine(y, l[:x]+l[x+1:])
} }
return nil return nil
} }
@ -202,15 +218,18 @@ func (a InsertDelete) Execute(m Model) tea.Cmd {
type InsertTab struct{} type InsertTab struct{}
func (a InsertTab) Execute(m Model) tea.Cmd { func (a InsertTab) Execute(m Model) tea.Cmd {
x, y := m.CursorX(), m.CursorY() win := m.ActiveWindow()
l := m.Line(y) buf := m.ActiveBuffer()
x, y := win.Cursor.Col, win.Cursor.Line
l := buf.Lines[y]
tabs := strings.Repeat(" ", m.Settings().TabSize) tabs := strings.Repeat(" ", m.Settings().TabSize)
if x < len(l) { if x < len(l) {
m.SetLine(y, l[:x]+tabs+l[x:]) buf.SetLine(y, l[:x]+tabs+l[x:])
} else { } else {
m.SetLine(y, l+tabs) buf.SetLine(y, l+tabs)
} }
m.SetCursorX(x + len(tabs)) win.SetCursorCol(x + len(tabs))
return nil return nil
} }
@ -229,18 +248,20 @@ func isPunctuation(c byte) bool {
} }
func (a InsertDeletePreviousWord) Execute(m Model) tea.Cmd { func (a InsertDeletePreviousWord) Execute(m Model) tea.Cmd {
x, y := m.CursorX(), m.CursorY() win := m.ActiveWindow()
line := m.Line(y) buf := m.ActiveBuffer()
x, y := win.Cursor.Col, win.Cursor.Line
line := buf.Lines[y]
// At start of line: merge with previous line (same as backspace) // At start of line: merge with previous line (same as backspace)
if x == 0 { if x == 0 {
if y > 0 { if y > 0 {
prevLine := m.Line(y - 1) prevLine := buf.Lines[y-1]
newX := len(prevLine) newX := len(prevLine)
m.SetLine(y-1, prevLine+line) buf.SetLine(y-1, prevLine+line)
m.DeleteLine(y) buf.DeleteLine(y)
m.SetCursorY(y - 1) win.SetCursorPos(y-1, newX)
m.SetCursorX(newX)
} }
return nil return nil
} }
@ -254,8 +275,8 @@ func (a InsertDeletePreviousWord) Execute(m Model) tea.Cmd {
newX-- newX--
} }
m.SetLine(y, line[:newX]+line[x:]) buf.SetLine(y, line[:newX]+line[x:])
m.SetCursorX(newX) win.SetCursorCol(newX)
return nil return nil
} }
@ -271,8 +292,8 @@ func (a InsertDeletePreviousWord) Execute(m Model) tea.Cmd {
} }
// Delete everything from newX up to x in one operation // Delete everything from newX up to x in one operation
m.SetLine(y, line[:newX]+line[x:]) buf.SetLine(y, line[:newX]+line[x:])
m.SetCursorX(newX) win.SetCursorCol(newX)
return nil return nil
} }

View File

@ -25,8 +25,9 @@ func (a EnterComandMode) Execute(m Model) tea.Cmd {
type EnterVisualMode struct{} type EnterVisualMode struct{}
func (a EnterVisualMode) Execute(m Model) tea.Cmd { func (a EnterVisualMode) Execute(m Model) tea.Cmd {
m.SetAnchorX(m.CursorX()) win := m.ActiveWindow()
m.SetAnchorY(m.CursorY()) win.SetAnchorCol(win.Cursor.Col)
win.SetAnchorLine(win.Cursor.Line)
m.SetMode(VisualMode) m.SetMode(VisualMode)
return nil return nil
} }
@ -35,8 +36,9 @@ func (a EnterVisualMode) Execute(m Model) tea.Cmd {
type EnterVisualLineMode struct{} type EnterVisualLineMode struct{}
func (a EnterVisualLineMode) Execute(m Model) tea.Cmd { func (a EnterVisualLineMode) Execute(m Model) tea.Cmd {
m.SetAnchorX(m.CursorX()) win := m.ActiveWindow()
m.SetAnchorY(m.CursorY()) win.SetAnchorCol(win.Cursor.Col)
win.SetAnchorLine(win.Cursor.Line)
m.SetMode(VisualLineMode) m.SetMode(VisualLineMode)
return nil return nil
} }
@ -45,8 +47,9 @@ func (a EnterVisualLineMode) Execute(m Model) tea.Cmd {
type EnterVisualBlockMode struct{} type EnterVisualBlockMode struct{}
func (a EnterVisualBlockMode) Execute(m Model) tea.Cmd { func (a EnterVisualBlockMode) Execute(m Model) tea.Cmd {
m.SetAnchorX(m.CursorX()) win := m.ActiveWindow()
m.SetAnchorY(m.CursorY()) win.SetAnchorCol(win.Cursor.Col)
win.SetAnchorLine(win.Cursor.Line)
m.SetMode(VisualBlockMode) m.SetMode(VisualBlockMode)
return nil return nil
} }

View File

@ -13,6 +13,9 @@ type Paste struct {
} }
func (a Paste) Execute(m Model) tea.Cmd { func (a Paste) Execute(m Model) tea.Cmd {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
// Get reg // Get reg
reg, found := m.GetRegister('"') reg, found := m.GetRegister('"')
if !found { if !found {
@ -28,20 +31,20 @@ func (a Paste) Execute(m Model) tea.Cmd {
switch reg.Type { switch reg.Type {
case LinewiseRegister: case LinewiseRegister:
{ {
initY := m.CursorY() initY := win.Cursor.Line
lines := reg.Content lines := reg.Content
insertPos := initY + 1 insertPos := initY + 1
// Run count times // Run count times
for range a.Count { for range a.Count {
for _, line := range lines { for _, line := range lines {
m.InsertLine(insertPos, line) buf.InsertLine(insertPos, line)
insertPos++ insertPos++
} }
} }
if m.LineCount() > 1 { if buf.LineCount() > 1 {
m.SetCursorY(initY + 1) win.SetCursorLine(initY + 1)
} }
} }
case CharwiseRegister: case CharwiseRegister:
@ -54,19 +57,18 @@ func (a Paste) Execute(m Model) tea.Cmd {
break break
} }
x := m.CursorX() x := win.Cursor.Col
y := m.CursorY() y := win.Cursor.Line
cnt := strings.Repeat(lines[0], max(1, a.Count)) cnt := strings.Repeat(lines[0], max(1, a.Count))
curLine := m.Line(y) curLine := buf.Lines[y]
// Catch edge cases, end of line, start of blank line // Catch edge cases, end of line, start of blank line
insertAt := min(x+1, len(curLine)) insertAt := min(x+1, len(curLine))
newLine := curLine[:insertAt] + cnt + curLine[insertAt:] newLine := curLine[:insertAt] + cnt + curLine[insertAt:]
m.SetLine(y, newLine) buf.SetLine(y, newLine)
m.SetCursorX(x + len(cnt)) win.SetCursorCol(x + len(cnt))
m.ClampCursorX()
} }
default: default:
m.SetCommandError(fmt.Errorf("Register type is not implemented.")) m.SetCommandError(fmt.Errorf("Register type is not implemented."))
@ -88,6 +90,9 @@ type PasteBefore struct {
} }
func (a PasteBefore) Execute(m Model) tea.Cmd { func (a PasteBefore) Execute(m Model) tea.Cmd {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
// Get reg // Get reg
reg, found := m.GetRegister('"') reg, found := m.GetRegister('"')
if !found { if !found {
@ -98,14 +103,14 @@ func (a PasteBefore) Execute(m Model) tea.Cmd {
switch reg.Type { switch reg.Type {
case LinewiseRegister: case LinewiseRegister:
{ {
initY := m.CursorY() initY := win.Cursor.Line
lines := reg.Content lines := reg.Content
insertPos := initY // Leave here, this will effectively move the lines below insertPos := initY // Leave here, this will effectively move the lines below
// Run count times // Run count times
for range a.Count { for range a.Count {
for _, line := range lines { for _, line := range lines {
m.InsertLine(insertPos, line) buf.InsertLine(insertPos, line)
insertPos++ insertPos++
} }
} }
@ -120,19 +125,18 @@ func (a PasteBefore) Execute(m Model) tea.Cmd {
break break
} }
x := m.CursorX() x := win.Cursor.Col
y := m.CursorY() y := win.Cursor.Line
cnt := strings.Repeat(lines[0], max(1, a.Count)) cnt := strings.Repeat(lines[0], max(1, a.Count))
curLine := m.Line(y) curLine := buf.Lines[y]
// Catch edge cases, end of line, start of blank line // Catch edge cases, end of line, start of blank line
insertAt := min(x, len(curLine)) insertAt := min(x, len(curLine))
newLine := curLine[:insertAt] + cnt + curLine[insertAt:] newLine := curLine[:insertAt] + cnt + curLine[insertAt:]
m.SetLine(y, newLine) buf.SetLine(y, newLine)
m.SetCursorX(x + len(cnt)) win.SetCursorCol(x + len(cnt))
m.ClampCursorX()
} }
default: default:
m.SetCommandError(fmt.Errorf("Register type is not implemented.")) m.SetCommandError(fmt.Errorf("Register type is not implemented."))
@ -183,11 +187,10 @@ func (a VisualPaste) Execute(m Model) tea.Cmd {
// normalizeSelection returns start and end positions with start always before end // normalizeSelection returns start and end positions with start always before end
func normalizeSelection(m Model) (Position, Position) { func normalizeSelection(m Model) (Position, Position) {
anchorX, anchorY := m.AnchorX(), m.AnchorY() win := m.ActiveWindow()
cursorX, cursorY := m.CursorX(), m.CursorY()
start := Position{Line: anchorY, Col: anchorX} start := Position{Line: win.Anchor.Line, Col: win.Anchor.Col}
end := Position{Line: cursorY, Col: cursorX} end := Position{Line: win.Cursor.Line, Col: win.Cursor.Col}
// Normalize so start is always before end // Normalize so start is always before end
if start.Line > end.Line || (start.Line == end.Line && start.Col > end.Col) { if start.Line > end.Line || (start.Line == end.Line && start.Col > end.Col) {
@ -199,6 +202,9 @@ func normalizeSelection(m Model) (Position, Position) {
// visualCharPaste handles paste in visual (character) mode // visualCharPaste handles paste in visual (character) mode
func visualCharPaste(m Model, reg Register, start, end Position) { func visualCharPaste(m Model, reg Register, start, end Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
// First, extract the text that will be deleted (to save to register) // First, extract the text that will be deleted (to save to register)
deletedText := extractCharSelection(m, start, end) deletedText := extractCharSelection(m, start, end)
@ -211,14 +217,14 @@ func visualCharPaste(m Model, reg Register, start, end Position) {
} else if reg.Type == CharwiseRegister { } else if reg.Type == CharwiseRegister {
// Charwise paste: insert text at cursor position // Charwise paste: insert text at cursor position
if len(reg.Content) == 1 { if len(reg.Content) == 1 {
line := m.Line(start.Line) line := buf.Lines[start.Line]
insertAt := min(start.Col, len(line)) insertAt := min(start.Col, len(line))
newLine := line[:insertAt] + reg.Content[0] + line[insertAt:] newLine := line[:insertAt] + reg.Content[0] + line[insertAt:]
m.SetLine(start.Line, newLine) buf.SetLine(start.Line, newLine)
// Cursor at end of pasted text // Cursor at end of pasted text
m.SetCursorX(insertAt + len(reg.Content[0]) - 1) win.SetCursorCol(insertAt + len(reg.Content[0]) - 1)
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
} }
} else if reg.Type == LinewiseRegister { } else if reg.Type == LinewiseRegister {
// Linewise paste in visual char mode: replace selection with lines // Linewise paste in visual char mode: replace selection with lines
@ -226,38 +232,39 @@ func visualCharPaste(m Model, reg Register, start, end Position) {
for i, content := range reg.Content { for i, content := range reg.Content {
if i == 0 { if i == 0 {
// First line: insert at start position // First line: insert at start position
line := m.Line(start.Line) line := buf.Lines[start.Line]
insertAt := min(start.Col, len(line)) insertAt := min(start.Col, len(line))
newLine := line[:insertAt] + content newLine := line[:insertAt] + content
if len(reg.Content) == 1 { if len(reg.Content) == 1 {
// Single line register - append rest of line // Single line register - append rest of line
newLine += line[insertAt:] newLine += line[insertAt:]
} }
m.SetLine(start.Line, newLine) buf.SetLine(start.Line, newLine)
} else { } else {
// Subsequent lines: insert new lines // Subsequent lines: insert new lines
m.InsertLine(start.Line+i, content) buf.InsertLine(start.Line+i, content)
} }
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(start.Col) win.SetCursorCol(start.Col)
} }
m.ClampCursorX()
// Update register with deleted text // Update register with deleted text
m.UpdateDefaultRegister(CharwiseRegister, []string{deletedText}) m.UpdateDefaultRegister(CharwiseRegister, []string{deletedText})
} }
// visualBlockPaste handles paste in visual block mode // visualBlockPaste handles paste in visual block mode
func visualBlockPaste(m Model, reg Register, start, end Position) { func visualBlockPaste(m Model, reg Register, start, end Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
startCol := min(start.Col, end.Col) startCol := min(start.Col, end.Col)
endCol := max(start.Col, end.Col) endCol := max(start.Col, end.Col)
// Extract deleted text (for register) // Extract deleted text (for register)
var deletedLines []string var deletedLines []string
for y := start.Line; y <= end.Line; y++ { for y := start.Line; y <= end.Line; y++ {
line := m.Line(y) line := buf.Lines[y]
if startCol < len(line) { if startCol < len(line) {
ec := min(endCol+1, len(line)) ec := min(endCol+1, len(line))
deletedLines = append(deletedLines, line[startCol:ec]) deletedLines = append(deletedLines, line[startCol:ec])
@ -268,12 +275,12 @@ func visualBlockPaste(m Model, reg Register, start, end Position) {
// Delete the block selection // Delete the block selection
for y := start.Line; y <= end.Line; y++ { for y := start.Line; y <= end.Line; y++ {
line := m.Line(y) line := buf.Lines[y]
if startCol >= len(line) { if startCol >= len(line) {
continue continue
} }
ec := min(endCol+1, len(line)) ec := min(endCol+1, len(line))
m.SetLine(y, line[:startCol]+line[ec:]) buf.SetLine(y, line[:startCol]+line[ec:])
} }
// Insert register content // Insert register content
@ -284,20 +291,19 @@ func visualBlockPaste(m Model, reg Register, start, end Position) {
} }
for y := start.Line; y <= end.Line; y++ { for y := start.Line; y <= end.Line; y++ {
line := m.Line(y) line := buf.Lines[y]
insertAt := min(startCol, len(line)) insertAt := min(startCol, len(line))
// Pad with spaces if needed // Pad with spaces if needed
for len(line) < insertAt { for len(line) < insertAt {
line += " " line += " "
} }
newLine := line[:insertAt] + pasteContent + line[insertAt:] newLine := line[:insertAt] + pasteContent + line[insertAt:]
m.SetLine(y, newLine) buf.SetLine(y, newLine)
} }
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(startCol) win.SetCursorCol(startCol)
m.ClampCursorX()
// Update register with deleted block text (joined) // Update register with deleted block text (joined)
m.UpdateDefaultRegister(CharwiseRegister, []string{strings.Join(deletedLines, "\n")}) m.UpdateDefaultRegister(CharwiseRegister, []string{strings.Join(deletedLines, "\n")})
@ -305,48 +311,50 @@ func visualBlockPaste(m Model, reg Register, start, end Position) {
// visualLinePaste handles paste in visual line mode // visualLinePaste handles paste in visual line mode
func visualLinePaste(m Model, reg Register, start, end Position) { func visualLinePaste(m Model, reg Register, start, end Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
// Extract deleted lines (for register) // Extract deleted lines (for register)
var deletedLines []string var deletedLines []string
for y := start.Line; y <= end.Line; y++ { for y := start.Line; y <= end.Line; y++ {
deletedLines = append(deletedLines, m.Line(y)) deletedLines = append(deletedLines, buf.Lines[y])
} }
// Delete the selected lines (from end to start to preserve indices) // Delete the selected lines (from end to start to preserve indices)
for y := end.Line; y >= start.Line; y-- { for y := end.Line; y >= start.Line; y-- {
m.DeleteLine(y) buf.DeleteLine(y)
} }
// Insert register content // Insert register content
if len(reg.Content) == 0 { if len(reg.Content) == 0 {
// Empty register - ensure at least one empty line exists // Empty register - ensure at least one empty line exists
if m.LineCount() == 0 { if buf.LineCount() == 0 {
m.InsertLine(0, "") buf.InsertLine(0, "")
} }
} else if reg.Type == LinewiseRegister { } else if reg.Type == LinewiseRegister {
// Linewise register: insert each line // Linewise register: insert each line
insertPos := start.Line insertPos := start.Line
for _, content := range reg.Content { for _, content := range reg.Content {
m.InsertLine(insertPos, content) buf.InsertLine(insertPos, content)
insertPos++ insertPos++
} }
} else { } else {
// Charwise register: insert as a single line // Charwise register: insert as a single line
m.InsertLine(start.Line, reg.Content[0]) buf.InsertLine(start.Line, reg.Content[0])
} }
// Ensure we have at least one line // Ensure we have at least one line
if m.LineCount() == 0 { if buf.LineCount() == 0 {
m.InsertLine(0, "") buf.InsertLine(0, "")
} }
// Position cursor at start of pasted content // Position cursor at start of pasted content
y := start.Line y := start.Line
if y >= m.LineCount() { if y >= buf.LineCount() {
y = m.LineCount() - 1 y = buf.LineCount() - 1
} }
m.SetCursorY(y) win.SetCursorLine(y)
m.SetCursorX(0) win.SetCursorCol(0)
m.ClampCursorX()
// Update register with deleted lines // Update register with deleted lines
m.UpdateDefaultRegister(LinewiseRegister, deletedLines) m.UpdateDefaultRegister(LinewiseRegister, deletedLines)
@ -354,8 +362,10 @@ func visualLinePaste(m Model, reg Register, start, end Position) {
// extractCharSelection extracts text from a character selection // extractCharSelection extracts text from a character selection
func extractCharSelection(m Model, start, end Position) string { func extractCharSelection(m Model, start, end Position) string {
buf := m.ActiveBuffer()
if start.Line == end.Line { if start.Line == end.Line {
line := m.Line(start.Line) line := buf.Lines[start.Line]
endCol := min(end.Col+1, len(line)) endCol := min(end.Col+1, len(line))
startCol := min(start.Col, len(line)) startCol := min(start.Col, len(line))
if startCol >= endCol { if startCol >= endCol {
@ -368,7 +378,7 @@ func extractCharSelection(m Model, start, end Position) string {
var result strings.Builder var result strings.Builder
// First line: from start.Col to end // First line: from start.Col to end
firstLine := m.Line(start.Line) firstLine := buf.Lines[start.Line]
if start.Col < len(firstLine) { if start.Col < len(firstLine) {
result.WriteString(firstLine[start.Col:]) result.WriteString(firstLine[start.Col:])
} }
@ -376,12 +386,12 @@ func extractCharSelection(m Model, start, end Position) string {
// Middle lines: entire lines // Middle lines: entire lines
for y := start.Line + 1; y < end.Line; y++ { for y := start.Line + 1; y < end.Line; y++ {
result.WriteString(m.Line(y)) result.WriteString(buf.Lines[y])
result.WriteString("\n") result.WriteString("\n")
} }
// Last line: from beginning to end.Col // Last line: from beginning to end.Col
lastLine := m.Line(end.Line) lastLine := buf.Lines[end.Line]
endCol := min(end.Col+1, len(lastLine)) endCol := min(end.Col+1, len(lastLine))
result.WriteString(lastLine[:endCol]) result.WriteString(lastLine[:endCol])
@ -390,13 +400,16 @@ func extractCharSelection(m Model, start, end Position) string {
// deleteCharSelectionForPaste deletes a character selection (similar to operator/delete.go) // deleteCharSelectionForPaste deletes a character selection (similar to operator/delete.go)
func deleteCharSelectionForPaste(m Model, start, end Position) { func deleteCharSelectionForPaste(m Model, start, end Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
if start.Line == end.Line { if start.Line == end.Line {
line := m.Line(start.Line) line := buf.Lines[start.Line]
endCol := min(end.Col+1, len(line)) endCol := min(end.Col+1, len(line))
m.SetLine(start.Line, line[:start.Col]+line[endCol:]) buf.SetLine(start.Line, line[:start.Col]+line[endCol:])
} else { } else {
startLine := m.Line(start.Line) startLine := buf.Lines[start.Line]
endLine := m.Line(end.Line) endLine := buf.Lines[end.Line]
prefix := "" prefix := ""
if start.Col < len(startLine) { if start.Col < len(startLine) {
@ -410,13 +423,13 @@ func deleteCharSelectionForPaste(m Model, start, end Position) {
// Delete from end back to start to preserve indices // Delete from end back to start to preserve indices
for i := end.Line; i >= start.Line; i-- { for i := end.Line; i >= start.Line; i-- {
m.DeleteLine(i) buf.DeleteLine(i)
} }
m.InsertLine(start.Line, prefix+suffix) buf.InsertLine(start.Line, prefix+suffix)
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(start.Col) win.SetCursorCol(start.Col)
} }
// Ensure VisualPaste implements Repeatable // Ensure VisualPaste implements Repeatable

View File

@ -80,6 +80,13 @@ func (w *Window) AdjustScroll() {
w.ScrollY = max(0, min(w.ScrollY, maxScroll)) w.ScrollY = max(0, min(w.ScrollY, maxScroll))
} }
// ==================================================
// View methods
// ==================================================
func (w *Window) View() {
}
// ================================================== // ==================================================
// Setters // Setters
// ================================================== // ==================================================

Binary file not shown.

View File

@ -19,8 +19,9 @@ func TestHelperExamples(t *testing.T) {
WithLines([]string{"hello", "world"}), WithLines([]string{"hello", "world"}),
) )
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if len(m.Lines()) != 2 { buf := m.ActiveBuffer()
t.Errorf("expected 2 lines, got %d", len(m.Lines())) if buf.LineCount() != 2 {
t.Errorf("expected 2 lines, got %d", buf.LineCount())
} }
}) })
@ -29,8 +30,9 @@ func TestHelperExamples(t *testing.T) {
WithCursorPos(action.Position{Line: 2, Col: 3}), WithCursorPos(action.Position{Line: 2, Col: 3}),
) )
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 2 || m.CursorX() != 3 { win := m.ActiveWindow()
t.Errorf("expected cursor at (2,3), got (%d,%d)", m.CursorY(), m.CursorX()) if win.Cursor.Line != 2 || win.Cursor.Col != 3 {
t.Errorf("expected cursor at (2,3), got (%d,%d)", win.Cursor.Line, win.Cursor.Col)
} }
}) })
@ -39,8 +41,9 @@ func TestHelperExamples(t *testing.T) {
WithTermSize(120, 40), WithTermSize(120, 40),
) )
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.WinW() != 120 || m.WinH() != 40 { win := m.ActiveWindow()
t.Errorf("expected size 120x40, got %dx%d", m.WinW(), m.WinH()) if win.Width != 120 || win.Height != 40 {
t.Errorf("expected size 120x40, got %dx%d", win.Width, win.Height)
} }
}) })
@ -73,14 +76,17 @@ func TestHelperExamples(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Verify all options were applied // Verify all options were applied
if len(m.Lines()) != 3 { win := m.ActiveWindow()
t.Errorf("expected 3 lines, got %d", len(m.Lines())) buf := m.ActiveBuffer()
if buf.LineCount() != 3 {
t.Errorf("expected 3 lines, got %d", buf.LineCount())
} }
if m.CursorY() != 1 || m.CursorX() != 5 { if win.Cursor.Line != 1 || win.Cursor.Col != 5 {
t.Errorf("expected cursor at (1,5), got (%d,%d)", m.CursorY(), m.CursorX()) t.Errorf("expected cursor at (1,5), got (%d,%d)", win.Cursor.Line, win.Cursor.Col)
} }
if m.WinW() != 100 || m.WinH() != 30 { if win.Width != 100 || win.Height != 30 {
t.Errorf("expected size 100x30, got %dx%d", m.WinW(), m.WinH()) t.Errorf("expected size 100x30, got %dx%d", win.Width, win.Height)
} }
reg, ok := m.GetRegister('"') reg, ok := m.GetRegister('"')
@ -93,25 +99,29 @@ func TestHelperExamples(t *testing.T) {
// Old style helpers still work for existing tests // Old style helpers still work for existing tests
tm1 := newTestModelWithLines(t, []string{"a", "b"}) tm1 := newTestModelWithLines(t, []string{"a", "b"})
m1 := getFinalModel(t, tm1) m1 := getFinalModel(t, tm1)
if len(m1.Lines()) != 2 { buf1 := m1.ActiveBuffer()
if buf1.LineCount() != 2 {
t.Error("newTestModelWithLines failed") t.Error("newTestModelWithLines failed")
} }
tm2 := newTestModelWithCursorPos(t, action.Position{Line: 1, Col: 2}) tm2 := newTestModelWithCursorPos(t, action.Position{Line: 1, Col: 2})
m2 := getFinalModel(t, tm2) m2 := getFinalModel(t, tm2)
if m2.CursorY() != 1 { win2 := m2.ActiveWindow()
if win2.Cursor.Line != 1 {
t.Error("newTestModelWithCursorPos failed") t.Error("newTestModelWithCursorPos failed")
} }
tm3 := newTestModelWithLinesAndCursorPos(t, []string{"x"}, action.Position{Line: 0, Col: 0}) tm3 := newTestModelWithLinesAndCursorPos(t, []string{"x"}, action.Position{Line: 0, Col: 0})
m3 := getFinalModel(t, tm3) m3 := getFinalModel(t, tm3)
if len(m3.Lines()) != 1 { buf3 := m3.ActiveBuffer()
if buf3.LineCount() != 1 {
t.Error("newTestModelWithLinesAndCursorPos failed") t.Error("newTestModelWithLinesAndCursorPos failed")
} }
tm4 := newTestModelWithTermSize(t, []string{"y"}, action.Position{Line: 0, Col: 0}, 50, 20) tm4 := newTestModelWithTermSize(t, []string{"y"}, action.Position{Line: 0, Col: 0}, 50, 20)
m4 := getFinalModel(t, tm4) m4 := getFinalModel(t, tm4)
if m4.WinW() != 50 { win4 := m4.ActiveWindow()
if win4.Width != 50 {
t.Error("newTestModelWithTermSize failed") t.Error("newTestModelWithTermSize failed")
} }
}) })

View File

@ -9,6 +9,8 @@ import (
"github.com/charmbracelet/x/exp/teatest" "github.com/charmbracelet/x/exp/teatest"
) )
// NOTE: Lots of this actually sucks ass, but it works for now...
// sendKeys sends a sequence of keys to the test model // sendKeys sends a sequence of keys to the test model
func sendKeys(tm *teatest.TestModel, keys ...string) { func sendKeys(tm *teatest.TestModel, keys ...string) {
for _, key := range keys { for _, key := range keys {
@ -94,12 +96,31 @@ func newTestModel(t *testing.T, opts ...TestModelOption) *teatest.TestModel {
opt(&cfg) opt(&cfg)
} }
// Create model buf := action.NewBufferBuilder().
m := NewModel(cfg.lines, cfg.pos) WithLines(cfg.lines).
Build()
// Set register if provided win := action.NewWindowBuilder().
WithBuffer(&buf).
WithCursorPos(cfg.pos.Line, cfg.pos.Col).
WithDimensions(cfg.width, cfg.height).
Build()
// Create model with default registers
m := NewModelBuilder().
AddBuffer(&buf).
AddWindow(&win).
WithActiveWindowId(win.Id).
WithTermSize(cfg.width, cfg.height).
Build()
// Set register if provided (must be done AFTER Build because SetRegister
// requires the register to already exist in the default register map)
if cfg.regContent != nil { if cfg.regContent != nil {
m.SetRegister(cfg.regName, cfg.regType, cfg.regContent) err := m.SetRegister(cfg.regName, cfg.regType, cfg.regContent)
if err != nil {
t.Fatalf("Failed to set register %c: %v", cfg.regName, err)
}
} }
return teatest.NewTestModel(t, m, teatest.WithInitialTermSize(cfg.width, cfg.height)) return teatest.NewTestModel(t, m, teatest.WithInitialTermSize(cfg.width, cfg.height))

View File

@ -13,8 +13,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ello" { if m.ActiveBuffer().Lines[0] != "ello" {
t.Errorf("lines[0] = %q, want 'ello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'ello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -24,8 +24,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "helo" { if m.ActiveBuffer().Lines[0] != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -35,8 +35,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hell" { if m.ActiveBuffer().Lines[0] != "hell" {
t.Errorf("lines[0] = %q, want 'hell'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hell'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -46,8 +46,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x", "x") sendKeys(tm, "x", "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "llo" { if m.ActiveBuffer().Lines[0] != "llo" {
t.Errorf("lines[0] = %q, want 'llo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'llo'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -59,8 +59,8 @@ func TestDeleteCharWithCount(t *testing.T) {
sendKeys(tm, "3", "x") sendKeys(tm, "3", "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "lo" { if m.ActiveBuffer().Lines[0] != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'lo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -70,8 +70,8 @@ func TestDeleteCharWithCount(t *testing.T) {
sendKeys(tm, "1", "0", "x") sendKeys(tm, "1", "0", "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0)) t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -81,8 +81,8 @@ func TestDeleteCharWithCount(t *testing.T) {
sendKeys(tm, "2", "x") sendKeys(tm, "2", "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hlo" { if m.ActiveBuffer().Lines[0] != "hlo" {
t.Errorf("lines[0] = %q, want 'hlo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hlo'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -94,11 +94,11 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -108,8 +108,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -119,8 +119,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "a" { if m.ActiveBuffer().Lines[0] != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.Line(0)) t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -130,8 +130,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ab c" { if m.ActiveBuffer().Lines[0] != "ab c" {
t.Errorf("Line(0) = %q, want 'ab c'", m.Line(0)) t.Errorf("Line(0) = %q, want 'ab c'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -141,11 +141,11 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "world" { if m.ActiveBuffer().Lines[1] != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.Line(1)) t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -155,8 +155,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x", "x", "x") sendKeys(tm, "x", "x", "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "lo" { if m.ActiveBuffer().Lines[0] != "lo" {
t.Errorf("Line(0) = %q, want 'lo'", m.Line(0)) t.Errorf("Line(0) = %q, want 'lo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -166,8 +166,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ab" { if m.ActiveBuffer().Lines[0] != "ab" {
t.Errorf("Line(0) = %q, want 'ab'", m.Line(0)) t.Errorf("Line(0) = %q, want 'ab'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -177,8 +177,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "5", "x") sendKeys(tm, "5", "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -188,8 +188,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x") sendKeys(tm, "x")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "abde" { if m.ActiveBuffer().Lines[0] != "abde" {
t.Errorf("Line(0) = %q, want 'abde'", m.Line(0)) t.Errorf("Line(0) = %q, want 'abde'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -201,8 +201,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -212,8 +212,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -223,8 +223,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hell" { if m.ActiveBuffer().Lines[0] != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hell'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -235,8 +235,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Cursor should move to last character of remaining text // Cursor should move to last character of remaining text
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -246,8 +246,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -257,14 +257,14 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "2", "D") sendKeys(tm, "2", "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %q, want '3'", m.LineCount()) t.Errorf("LineCount() = %q, want '3'", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "he" { if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.Line(0)) t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "hi" { if m.ActiveBuffer().Lines[1] != "hi" {
t.Errorf("Line(1) = %q, want 'hi'", m.Line(1)) t.Errorf("Line(1) = %q, want 'hi'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -274,11 +274,11 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "8", "D") sendKeys(tm, "8", "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %q, want '1'", m.LineCount()) t.Errorf("LineCount() = %q, want '1'", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "he" { if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.Line(0)) t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -290,8 +290,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -301,11 +301,11 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
}) })
@ -315,11 +315,11 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "line 1" { if m.ActiveBuffer().Lines[0] != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line 1'", m.ActiveBuffer().Lines[0])
} }
if m.Line(2) != "line 3" { if m.ActiveBuffer().Lines[2] != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line 3'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -329,12 +329,12 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "he" { if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.Line(0)) t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0])
} }
// Cursor should clamp to last char // Cursor should clamp to last char
if m.CursorX() != 1 { if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX()) t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -344,8 +344,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -355,8 +355,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != " " { if m.ActiveBuffer().Lines[0] != " " {
t.Errorf("Line(0) = %q, want ' '", m.Line(0)) t.Errorf("Line(0) = %q, want ' '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -366,8 +366,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -377,8 +377,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "a" { if m.ActiveBuffer().Lines[0] != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.Line(0)) t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -388,8 +388,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(1) != "world" { if m.ActiveBuffer().Lines[1] != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.Line(1)) t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -399,11 +399,11 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "first" { if m.ActiveBuffer().Lines[0] != "first" {
t.Errorf("Line(0) = %q, want 'first'", m.Line(0)) t.Errorf("Line(0) = %q, want 'first'", m.ActiveBuffer().Lines[0])
} }
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
}) })
@ -413,8 +413,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D") sendKeys(tm, "D")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY()) t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
}) })
} }

View File

@ -25,8 +25,8 @@ func TestEnterInsert(t *testing.T) {
sendKeys(tm, "i", "X", "esc") sendKeys(tm, "i", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" { if m.ActiveBuffer().Lines[0] != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'Xhello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -36,8 +36,8 @@ func TestEnterInsert(t *testing.T) {
sendKeys(tm, "i", "X", "esc") sendKeys(tm, "i", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" { if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -47,8 +47,8 @@ func TestEnterInsert(t *testing.T) {
sendKeys(tm, "i", "X", "esc") sendKeys(tm, "i", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("cursor.x = %d, want 2", m.CursorX()) t.Errorf("cursor.x = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -70,8 +70,8 @@ func TestEnterInsertAfter(t *testing.T) {
sendKeys(tm, "a", "X", "esc") sendKeys(tm, "a", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hXello" { if m.ActiveBuffer().Lines[0] != "hXello" {
t.Errorf("lines[0] = %q, want 'hXello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hXello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -81,8 +81,8 @@ func TestEnterInsertAfter(t *testing.T) {
sendKeys(tm, "a", "X", "esc") sendKeys(tm, "a", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "helXlo" { if m.ActiveBuffer().Lines[0] != "helXlo" {
t.Errorf("lines[0] = %q, want 'helXlo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helXlo'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -94,8 +94,8 @@ func TestEnterInsertLineStart(t *testing.T) {
sendKeys(tm, "I", "X", "esc") sendKeys(tm, "I", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" { if m.ActiveBuffer().Lines[0] != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'Xhello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -105,8 +105,8 @@ func TestEnterInsertLineStart(t *testing.T) {
sendKeys(tm, "I", "X", "esc") sendKeys(tm, "I", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" { if m.ActiveBuffer().Lines[0] != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'Xhello'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -118,8 +118,8 @@ func TestEnterInsertLineEnd(t *testing.T) {
sendKeys(tm, "A", "X", "esc") sendKeys(tm, "A", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "helloX" { if m.ActiveBuffer().Lines[0] != "helloX" {
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helloX'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -129,8 +129,8 @@ func TestEnterInsertLineEnd(t *testing.T) {
sendKeys(tm, "A", "X", "esc") sendKeys(tm, "A", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "helloX" { if m.ActiveBuffer().Lines[0] != "helloX" {
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helloX'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -144,11 +144,11 @@ func TestOpenLineBelow(t *testing.T) {
sendKeys(tm, "o", "n", "e", "w", "esc") sendKeys(tm, "o", "n", "e", "w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount()) t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "new" { if m.ActiveBuffer().Lines[1] != "new" {
t.Errorf("lines[1] = %q, want 'new'", m.Line(1)) t.Errorf("lines[1] = %q, want 'new'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -158,11 +158,11 @@ func TestOpenLineBelow(t *testing.T) {
sendKeys(tm, "o", "n", "e", "w", "esc") sendKeys(tm, "o", "n", "e", "w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 4 { if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.LineCount()) t.Errorf("len(lines) = %d, want 4", m.ActiveBuffer().LineCount())
} }
if m.Line(2) != "new" { if m.ActiveBuffer().Lines[2] != "new" {
t.Errorf("lines[2] = %q, want 'new'", m.Line(2)) t.Errorf("lines[2] = %q, want 'new'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -172,11 +172,11 @@ func TestOpenLineBelow(t *testing.T) {
sendKeys(tm, "o", "n", "e", "w", "esc") sendKeys(tm, "o", "n", "e", "w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount()) t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(2) != "new" { if m.ActiveBuffer().Lines[2] != "new" {
t.Errorf("lines[2] = %q, want 'new'", m.Line(2)) t.Errorf("lines[2] = %q, want 'new'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -186,11 +186,11 @@ func TestOpenLineBelow(t *testing.T) {
sendKeys(tm, "o", "esc") sendKeys(tm, "o", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("cursor.y = %d, want 1", m.CursorY()) t.Errorf("cursor.y = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX()) t.Errorf("cursor.x = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -202,12 +202,12 @@ func TestOpenLineBelowWithCount(t *testing.T) {
sendKeys(tm, "3", "o", "x", "esc") sendKeys(tm, "3", "o", "x", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 4 { if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.LineCount()) t.Errorf("len(lines) = %d, want 4", m.ActiveBuffer().LineCount())
} }
for i := 1; i <= 3; i++ { for i := 1; i <= 3; i++ {
if m.Line(i) != "x" { if m.ActiveBuffer().Lines[i] != "x" {
t.Errorf("lines[%d] = %q, want 'x'", i, m.Line(i)) t.Errorf("lines[%d] = %q, want 'x'", i, m.ActiveBuffer().Lines[i])
} }
} }
}) })
@ -218,14 +218,14 @@ func TestOpenLineBelowWithCount(t *testing.T) {
sendKeys(tm, "2", "o", "a", "b", "esc") sendKeys(tm, "2", "o", "a", "b", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount()) t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "ab" { if m.ActiveBuffer().Lines[1] != "ab" {
t.Errorf("lines[1] = %q, want 'ab'", m.Line(1)) t.Errorf("lines[1] = %q, want 'ab'", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "ab" { if m.ActiveBuffer().Lines[2] != "ab" {
t.Errorf("lines[2] = %q, want 'ab'", m.Line(2)) t.Errorf("lines[2] = %q, want 'ab'", m.ActiveBuffer().Lines[2])
} }
}) })
} }
@ -237,11 +237,11 @@ func TestOpenLineAbove(t *testing.T) {
sendKeys(tm, "O", "n", "e", "w", "esc") sendKeys(tm, "O", "n", "e", "w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount()) t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "new" { if m.ActiveBuffer().Lines[1] != "new" {
t.Errorf("lines[1] = %q, want 'new'", m.Line(1)) t.Errorf("lines[1] = %q, want 'new'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -251,11 +251,11 @@ func TestOpenLineAbove(t *testing.T) {
sendKeys(tm, "O", "n", "e", "w", "esc") sendKeys(tm, "O", "n", "e", "w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount()) t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "new" { if m.ActiveBuffer().Lines[0] != "new" {
t.Errorf("lines[0] = %q, want 'new'", m.Line(0)) t.Errorf("lines[0] = %q, want 'new'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -265,8 +265,8 @@ func TestOpenLineAbove(t *testing.T) {
sendKeys(tm, "O", "esc") sendKeys(tm, "O", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX()) t.Errorf("cursor.x = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -278,12 +278,12 @@ func TestOpenLineAboveWithCount(t *testing.T) {
sendKeys(tm, "3", "O", "x", "esc") sendKeys(tm, "3", "O", "x", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 4 { if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.LineCount()) t.Errorf("len(lines) = %d, want 4", m.ActiveBuffer().LineCount())
} }
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
if m.Line(i) != "x" { if m.ActiveBuffer().Lines[i] != "x" {
t.Errorf("lines[%d] = %q, want 'x'", i, m.Line(i)) t.Errorf("lines[%d] = %q, want 'x'", i, m.ActiveBuffer().Lines[i])
} }
} }
}) })
@ -298,14 +298,14 @@ func TestInsertModeEnter(t *testing.T) {
sendKeys(tm, "i", "enter", "esc") sendKeys(tm, "i", "enter", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.LineCount()) t.Errorf("len(lines) = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != " world" { if m.ActiveBuffer().Lines[1] != " world" {
t.Errorf("lines[1] = %q, want ' world'", m.Line(1)) t.Errorf("lines[1] = %q, want ' world'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -315,14 +315,14 @@ func TestInsertModeEnter(t *testing.T) {
sendKeys(tm, "i", "enter", "esc") sendKeys(tm, "i", "enter", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.LineCount()) t.Errorf("len(lines) = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("lines[1] = %q, want ''", m.Line(1)) t.Errorf("lines[1] = %q, want ''", m.ActiveBuffer().Lines[1])
} }
}) })
@ -332,14 +332,14 @@ func TestInsertModeEnter(t *testing.T) {
sendKeys(tm, "i", "enter", "esc") sendKeys(tm, "i", "enter", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.LineCount()) t.Errorf("len(lines) = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0)) t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "hello" { if m.ActiveBuffer().Lines[1] != "hello" {
t.Errorf("lines[1] = %q, want 'hello'", m.Line(1)) t.Errorf("lines[1] = %q, want 'hello'", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -351,8 +351,8 @@ func TestInsertModeBackspace(t *testing.T) {
sendKeys(tm, "i", "backspace", "esc") sendKeys(tm, "i", "backspace", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "helo" { if m.ActiveBuffer().Lines[0] != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -362,11 +362,11 @@ func TestInsertModeBackspace(t *testing.T) {
sendKeys(tm, "i", "backspace", "esc") sendKeys(tm, "i", "backspace", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.LineCount()) t.Errorf("len(lines) = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "helloworld" { if m.ActiveBuffer().Lines[0] != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helloworld'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -376,8 +376,8 @@ func TestInsertModeBackspace(t *testing.T) {
sendKeys(tm, "i", "backspace", "esc") sendKeys(tm, "i", "backspace", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -387,8 +387,8 @@ func TestInsertModeBackspace(t *testing.T) {
sendKeys(tm, "i", "backspace", "backspace", "backspace", "esc") sendKeys(tm, "i", "backspace", "backspace", "backspace", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "he" { if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("lines[0] = %q, want 'he'", m.Line(0)) t.Errorf("lines[0] = %q, want 'he'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -400,8 +400,8 @@ func TestInsertModeDelete(t *testing.T) {
sendKeys(tm, "i", "delete", "esc") sendKeys(tm, "i", "delete", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "word" { if m.ActiveBuffer().Lines[0] != "word" {
t.Errorf("lines[0] = %q, want 'word'", m.Line(0)) t.Errorf("lines[0] = %q, want 'word'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -411,11 +411,11 @@ func TestInsertModeDelete(t *testing.T) {
sendKeys(tm, "i", "delete", "esc") sendKeys(tm, "i", "delete", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.LineCount()) t.Errorf("len(lines) = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "helloworld" { if m.ActiveBuffer().Lines[0] != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helloworld'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -425,11 +425,11 @@ func TestInsertModeDelete(t *testing.T) {
sendKeys(tm, "i", "delete", "esc") sendKeys(tm, "i", "delete", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.LineCount()) t.Errorf("len(lines) = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "world" { if m.ActiveBuffer().Lines[0] != "world" {
t.Errorf("lines[0] = %q, want 'world'", m.Line(0)) t.Errorf("lines[0] = %q, want 'world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -439,8 +439,8 @@ func TestInsertModeDelete(t *testing.T) {
sendKeys(tm, "i", "delete", "esc") sendKeys(tm, "i", "delete", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -450,8 +450,8 @@ func TestInsertModeDelete(t *testing.T) {
sendKeys(tm, "i", "delete", "delete", "delete", "esc") sendKeys(tm, "i", "delete", "delete", "delete", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ho" { if m.ActiveBuffer().Lines[0] != "ho" {
t.Errorf("lines[0] = %q, want 'he'", m.Line(0)) t.Errorf("lines[0] = %q, want 'he'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -464,8 +464,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "left", "X", "esc") sendKeys(tm, "i", "left", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" { if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -475,8 +475,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "right", "X", "esc") sendKeys(tm, "i", "right", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" { if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -486,11 +486,11 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "up", "X", "esc") sendKeys(tm, "i", "up", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" { if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "world" { if m.ActiveBuffer().Lines[1] != "world" {
t.Errorf("lines[1] = %q, want 'world'", m.Line(1)) t.Errorf("lines[1] = %q, want 'world'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -500,11 +500,11 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "down", "X", "esc") sendKeys(tm, "i", "down", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "woXrld" { if m.ActiveBuffer().Lines[1] != "woXrld" {
t.Errorf("lines[1] = %q, want 'woXrld'", m.Line(1)) t.Errorf("lines[1] = %q, want 'woXrld'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -514,8 +514,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "left", "X", "esc") sendKeys(tm, "i", "left", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" { if m.ActiveBuffer().Lines[0] != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'Xhello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -525,8 +525,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "a", "right", "X", "esc") sendKeys(tm, "a", "right", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "helloX" { if m.ActiveBuffer().Lines[0] != "helloX" {
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helloX'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -536,8 +536,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "up", "X", "esc") sendKeys(tm, "i", "up", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" { if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -547,8 +547,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "down", "X", "esc") sendKeys(tm, "i", "down", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" { if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -558,8 +558,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "up", "X", "esc") sendKeys(tm, "i", "up", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hiX" { if m.ActiveBuffer().Lines[0] != "hiX" {
t.Errorf("lines[0] = %q, want 'hiX'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hiX'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -569,8 +569,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "down", "X", "esc") sendKeys(tm, "i", "down", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(1) != "hiX" { if m.ActiveBuffer().Lines[1] != "hiX" {
t.Errorf("lines[1] = %q, want 'hiX'", m.Line(1)) t.Errorf("lines[1] = %q, want 'hiX'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -580,8 +580,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
sendKeys(tm, "i", "right", "right", "down", "X", "esc") sendKeys(tm, "i", "right", "right", "down", "X", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(1) != "woXrld" { if m.ActiveBuffer().Lines[1] != "woXrld" {
t.Errorf("lines[1] = %q, want 'woXrld'", m.Line(1)) t.Errorf("lines[1] = %q, want 'woXrld'", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -593,11 +593,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello " { if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("lines[0] = %q, want 'hello '", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello '", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 5 { if m.ActiveWindow().Cursor.Col != 5 {
t.Errorf("CursorX() = %d, want '5'", m.CursorX()) t.Errorf("CursorX() = %d, want '5'", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -607,11 +607,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0)) t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want '0'", m.CursorX()) t.Errorf("CursorX() = %d, want '0'", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -621,11 +621,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello wo" { if m.ActiveBuffer().Lines[0] != "hello wo" {
t.Errorf("lines[0] = %q, want 'hello wo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello wo'", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 7 { if m.ActiveWindow().Cursor.Col != 7 {
t.Errorf("CursorX() = %d, want '7'", m.CursorX()) t.Errorf("CursorX() = %d, want '7'", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -635,14 +635,14 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want '1'", m.LineCount()) t.Errorf("LineCount() = %d, want '1'", m.ActiveBuffer().LineCount())
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want '0'", m.CursorX()) t.Errorf("CursorX() = %d, want '0'", m.ActiveWindow().Cursor.Col)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want '0'", m.CursorY()) t.Errorf("CursorY() = %d, want '0'", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -652,17 +652,17 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want '1'", m.LineCount()) t.Errorf("LineCount() = %d, want '1'", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %s, want ''", m.Line(0)) t.Errorf("Line(0) = %s, want ''", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want '0'", m.CursorX()) t.Errorf("CursorX() = %d, want '0'", m.ActiveWindow().Cursor.Col)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want '0'", m.CursorY()) t.Errorf("CursorY() = %d, want '0'", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -672,11 +672,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "i", "ctrl+w", "esc") sendKeys(tm, "i", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -686,11 +686,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "i", "ctrl+w", "esc") sendKeys(tm, "i", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "lo" { if m.ActiveBuffer().Lines[0] != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.Line(0)) t.Errorf("lines[0] = %q, want 'lo'", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -700,11 +700,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "..." { if m.ActiveBuffer().Lines[0] != "..." {
t.Errorf("lines[0] = %q, want '...'", m.Line(0)) t.Errorf("lines[0] = %q, want '...'", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX()) t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -714,11 +714,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello\t" { if m.ActiveBuffer().Lines[0] != "hello\t" {
t.Errorf("lines[0] = %q, want 'hello\\t'", m.Line(0)) t.Errorf("lines[0] = %q, want 'hello\\t'", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 5 { if m.ActiveWindow().Cursor.Col != 5 {
t.Errorf("CursorX() = %d, want 5", m.CursorX()) t.Errorf("CursorX() = %d, want 5", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -728,17 +728,17 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "i", "ctrl+w", "esc") sendKeys(tm, "i", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "helloworld" { if m.ActiveBuffer().Lines[0] != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0)) t.Errorf("lines[0] = %q, want 'helloworld'", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -748,11 +748,11 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
sendKeys(tm, "a", "ctrl+w", "esc") sendKeys(tm, "a", "ctrl+w", "esc")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0)) t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }

View File

@ -12,8 +12,8 @@ func TestMoveDown(t *testing.T) {
sendKeys(tm, "j") sendKeys(tm, "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("cursor.y = %d, want 1", m.CursorY()) t.Errorf("cursor.y = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -22,8 +22,8 @@ func TestMoveDown(t *testing.T) {
sendKeys(tm, "j", "j", "j", "j") sendKeys(tm, "j", "j", "j", "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 4 { if m.ActiveWindow().Cursor.Line != 4 {
t.Errorf("cursor.y = %d, want 4", m.CursorY()) t.Errorf("cursor.y = %d, want 4", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -32,8 +32,8 @@ func TestMoveDown(t *testing.T) {
sendKeys(tm, "j", "j", "j", "j", "j", "j", "j", "j", "j") sendKeys(tm, "j", "j", "j", "j", "j", "j", "j", "j", "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 5 { if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("cursor.y = %d, want 5", m.CursorY()) t.Errorf("cursor.y = %d, want 5", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -44,8 +44,8 @@ func TestMoveDownWithCount(t *testing.T) {
sendKeys(tm, "3", "j") sendKeys(tm, "3", "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 3 { if m.ActiveWindow().Cursor.Line != 3 {
t.Errorf("cursor.y = %d, want 3", m.CursorY()) t.Errorf("cursor.y = %d, want 3", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -54,8 +54,8 @@ func TestMoveDownWithCount(t *testing.T) {
sendKeys(tm, "1", "0", "j") sendKeys(tm, "1", "0", "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 5 { if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("cursor.y = %d, want 5", m.CursorY()) t.Errorf("cursor.y = %d, want 5", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -69,8 +69,8 @@ func TestMoveDownWithOverflow(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[1]) want := len(lines[1])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want) t.Errorf("cursor.x = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
@ -79,8 +79,8 @@ func TestMoveDownWithOverflow(t *testing.T) {
sendKeys(tm, "j") sendKeys(tm, "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 3 { if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("cursor.x = %d, want 3", m.CursorX()) t.Errorf("cursor.x = %d, want 3", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -91,8 +91,8 @@ func TestMoveUp(t *testing.T) {
sendKeys(tm, "k") sendKeys(tm, "k")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("cursor.y = %d, want 1", m.CursorY()) t.Errorf("cursor.y = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -101,8 +101,8 @@ func TestMoveUp(t *testing.T) {
sendKeys(tm, "k", "k", "k", "k") sendKeys(tm, "k", "k", "k", "k")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("cursor.y = %d, want 0", m.CursorY()) t.Errorf("cursor.y = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -111,8 +111,8 @@ func TestMoveUp(t *testing.T) {
sendKeys(tm, "k", "k", "k") sendKeys(tm, "k", "k", "k")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("cursor.y = %d, want 0", m.CursorY()) t.Errorf("cursor.y = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -123,8 +123,8 @@ func TestMoveUpWithCount(t *testing.T) {
sendKeys(tm, "3", "k") sendKeys(tm, "3", "k")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 2 { if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("cursor.y = %d, want 2", m.CursorY()) t.Errorf("cursor.y = %d, want 2", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -133,8 +133,8 @@ func TestMoveUpWithCount(t *testing.T) {
sendKeys(tm, "1", "0", "k") sendKeys(tm, "1", "0", "k")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("cursor.y = %d, want 0", m.CursorY()) t.Errorf("cursor.y = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -148,8 +148,8 @@ func TestMoveUpWithOverflow(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want) t.Errorf("cursor.x = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
@ -158,8 +158,8 @@ func TestMoveUpWithOverflow(t *testing.T) {
sendKeys(tm, "k") sendKeys(tm, "k")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 3 { if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("cursor.x = %d, want 3", m.CursorX()) t.Errorf("cursor.x = %d, want 3", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -170,8 +170,8 @@ func TestMoveRight(t *testing.T) {
sendKeys(tm, "l") sendKeys(tm, "l")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 1 { if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("cursor.x = %d, want 1", m.CursorX()) t.Errorf("cursor.x = %d, want 1", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -180,8 +180,8 @@ func TestMoveRight(t *testing.T) {
sendKeys(tm, "l", "l", "l", "l") sendKeys(tm, "l", "l", "l", "l")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("cursor.x = %d, want 4", m.CursorX()) t.Errorf("cursor.x = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -192,8 +192,8 @@ func TestMoveRight(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want) t.Errorf("cursor.x = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
} }
@ -204,8 +204,8 @@ func TestMoveRightWithCount(t *testing.T) {
sendKeys(tm, "3", "l") sendKeys(tm, "3", "l")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 3 { if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("cursor.x = %d, want 3", m.CursorX()) t.Errorf("cursor.x = %d, want 3", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -216,8 +216,8 @@ func TestMoveRightWithCount(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want) t.Errorf("cursor.x = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
} }
@ -228,8 +228,8 @@ func TestMoveLeft(t *testing.T) {
sendKeys(tm, "h") sendKeys(tm, "h")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("cursor.x = %d, want 2", m.CursorX()) t.Errorf("cursor.x = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -238,8 +238,8 @@ func TestMoveLeft(t *testing.T) {
sendKeys(tm, "h", "h", "h", "h") sendKeys(tm, "h", "h", "h", "h")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX()) t.Errorf("cursor.x = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -248,8 +248,8 @@ func TestMoveLeft(t *testing.T) {
sendKeys(tm, "h", "h", "h") sendKeys(tm, "h", "h", "h")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX()) t.Errorf("cursor.x = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -260,8 +260,8 @@ func TestMoveLeftWithCount(t *testing.T) {
sendKeys(tm, "3", "h") sendKeys(tm, "3", "h")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("cursor.x = %d, want 2", m.CursorX()) t.Errorf("cursor.x = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -270,8 +270,8 @@ func TestMoveLeftWithCount(t *testing.T) {
sendKeys(tm, "1", "0", "h") sendKeys(tm, "1", "0", "h")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX()) t.Errorf("cursor.x = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }

View File

@ -14,8 +14,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G") sendKeys(tm, "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 5 { if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY()) t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -24,8 +24,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G") sendKeys(tm, "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 5 { if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY()) t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -34,8 +34,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G") sendKeys(tm, "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 5 { if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY()) t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -45,12 +45,12 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G") sendKeys(tm, "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY()) t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
want := len(lines[1]) want := len(lines[1])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want) t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
@ -60,8 +60,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G") sendKeys(tm, "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -72,8 +72,8 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g") sendKeys(tm, "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -82,8 +82,8 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g") sendKeys(tm, "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -92,8 +92,8 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g") sendKeys(tm, "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -103,12 +103,12 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g") sendKeys(tm, "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want) t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
} }
@ -121,8 +121,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0") sendKeys(tm, "0")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -132,8 +132,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0") sendKeys(tm, "0")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -142,8 +142,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0") sendKeys(tm, "0")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -153,8 +153,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0") sendKeys(tm, "0")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -163,8 +163,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0") sendKeys(tm, "0")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 2 { if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY()) t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -177,8 +177,8 @@ func TestMoveToLineEnd(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want) t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
@ -189,8 +189,8 @@ func TestMoveToLineEnd(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want) t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
@ -201,8 +201,8 @@ func TestMoveToLineEnd(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
want := len(lines[0]) want := len(lines[0])
if m.CursorX() != want { if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want) t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
} }
}) })
@ -212,8 +212,8 @@ func TestMoveToLineEnd(t *testing.T) {
sendKeys(tm, "$") sendKeys(tm, "$")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -222,8 +222,8 @@ func TestMoveToLineEnd(t *testing.T) {
sendKeys(tm, "$") sendKeys(tm, "$")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 2 { if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY()) t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -235,8 +235,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -246,8 +246,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -257,8 +257,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -268,8 +268,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -279,8 +279,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -290,8 +290,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -301,8 +301,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_") sendKeys(tm, "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -314,8 +314,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -325,8 +325,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -336,8 +336,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -347,8 +347,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -358,8 +358,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -369,8 +369,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -380,8 +380,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^") sendKeys(tm, "^")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -400,8 +400,8 @@ func TestMoveToColumn(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// | with no count = 1| = column 1 = index 0 // | with no count = 1| = column 1 = index 0
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -411,8 +411,8 @@ func TestMoveToColumn(t *testing.T) {
sendKeys(tm, "1", "|") sendKeys(tm, "1", "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -423,8 +423,8 @@ func TestMoveToColumn(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 5 = index 4 (the 'o' in hello) // Column 5 = index 4 (the 'o' in hello)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -435,8 +435,8 @@ func TestMoveToColumn(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 10 = index 9 (the 'l' in world) // Column 10 = index 9 (the 'l' in world)
if m.CursorX() != 9 { if m.ActiveWindow().Cursor.Col != 9 {
t.Errorf("CursorX() = %d, want 9", m.CursorX()) t.Errorf("CursorX() = %d, want 9", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -446,8 +446,8 @@ func TestMoveToColumn(t *testing.T) {
sendKeys(tm, "|") sendKeys(tm, "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -457,8 +457,8 @@ func TestMoveToColumn(t *testing.T) {
sendKeys(tm, "5", "|") sendKeys(tm, "5", "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -471,8 +471,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 20 exceeds line length, should clamp to last char (index 4) // Column 20 exceeds line length, should clamp to last char (index 4)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -483,8 +483,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Should clamp to last char (index 10) // Should clamp to last char (index 10)
if m.CursorX() != 10 { if m.ActiveWindow().Cursor.Col != 10 {
t.Errorf("CursorX() = %d, want 10", m.CursorX()) t.Errorf("CursorX() = %d, want 10", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -495,8 +495,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 6 = index 5, but line only has 5 chars (max index 4) // Column 6 = index 5, but line only has 5 chars (max index 4)
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -506,8 +506,8 @@ func TestMoveToColumnClamp(t *testing.T) {
sendKeys(tm, "|") sendKeys(tm, "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -517,8 +517,8 @@ func TestMoveToColumnClamp(t *testing.T) {
sendKeys(tm, "5", "|") sendKeys(tm, "5", "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -529,8 +529,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 3 = index 2, but line only has 2 chars (max index 1) // Column 3 = index 2, but line only has 2 chars (max index 1)
if m.CursorX() != 1 { if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX()) t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -542,8 +542,8 @@ func TestMoveToColumnPreservesLine(t *testing.T) {
sendKeys(tm, "|") sendKeys(tm, "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY()) t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -553,8 +553,8 @@ func TestMoveToColumnPreservesLine(t *testing.T) {
sendKeys(tm, "5", "|") sendKeys(tm, "5", "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 2 { if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY()) t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -564,11 +564,11 @@ func TestMoveToColumnPreservesLine(t *testing.T) {
sendKeys(tm, "|") sendKeys(tm, "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY()) t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -581,8 +581,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 5 = index 4 = 'h' in " hello" // Column 5 = index 4 = 'h' in " hello"
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -593,8 +593,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 3 = index 2 = third space // Column 3 = index 2 = third space
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX()) t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -605,8 +605,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// | goes to column 1 = index 0 = the tab // | goes to column 1 = index 0 = the tab
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -617,8 +617,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Column 2 = index 1 = 'h' in "\thello" // Column 2 = index 1 = 'h' in "\thello"
if m.CursorX() != 1 { if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX()) t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -633,8 +633,8 @@ func TestMoveToColumnWithOperator(t *testing.T) {
// Deletes from column 1 to current position (exclusive), so "hello" deleted // Deletes from column 1 to current position (exclusive), so "hello" deleted
// Result depends on inclusive/exclusive behavior // Result depends on inclusive/exclusive behavior
// In Vim: d| from col 5 deletes chars 0-4, leaving " world" // In Vim: d| from col 5 deletes chars 0-4, leaving " world"
if m.Line(0) != " world" { if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0)) t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -646,8 +646,8 @@ func TestMoveToColumnWithOperator(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Deletes from cursor (0) to column 5 (index 4), so "hell" deleted // Deletes from cursor (0) to column 5 (index 4), so "hell" deleted
// Result: "o world" // Result: "o world"
if m.Line(0) != "o world" { if m.ActiveBuffer().Lines[0] != "o world" {
t.Errorf("Line(0) = %q, want 'o world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'o world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -691,11 +691,11 @@ func TestMoveToColumnInVisualMode(t *testing.T) {
sendKeys(tm, "v", "5", "|") sendKeys(tm, "v", "5", "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 0 { if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX()) t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
} }
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -705,11 +705,11 @@ func TestMoveToColumnInVisualMode(t *testing.T) {
sendKeys(tm, "v", "|") sendKeys(tm, "v", "|")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 5 { if m.ActiveWindow().Anchor.Col != 5 {
t.Errorf("AnchorX() = %d, want 5", m.AnchorX()) t.Errorf("AnchorX() = %d, want 5", m.ActiveWindow().Anchor.Col)
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -720,8 +720,8 @@ func TestMoveToColumnInVisualMode(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Visual selection from 0 to 4 inclusive, delete "hello" // Visual selection from 0 to 4 inclusive, delete "hello"
if m.Line(0) != " world" { if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0)) t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
} }
}) })
} }

File diff suppressed because it is too large Load Diff

View File

@ -22,15 +22,15 @@ func TestChangeLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
// First line should be empty (ready for insert) // First line should be empty (ready for insert)
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "world" { if m.ActiveBuffer().Lines[1] != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.Line(1)) t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -45,14 +45,14 @@ func TestChangeLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "line one" { if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "line three" { if m.ActiveBuffer().Lines[2] != "line three" {
t.Errorf("Line(2) = %q, want 'line three'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line three'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -67,11 +67,11 @@ func TestChangeLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
}) })
@ -106,11 +106,11 @@ func TestChangeLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -123,11 +123,11 @@ func TestChangeLine(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Cursor should be at column 0 on the empty line // Cursor should be at column 0 on the empty line
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -145,14 +145,14 @@ func TestChangeLineWithCount(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have 3 lines: empty + line three + line four // Should have 3 lines: empty + line three + line four
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "line three" { if m.ActiveBuffer().Lines[1] != "line three" {
t.Errorf("Line(1) = %q, want 'line three'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line three'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -168,17 +168,17 @@ func TestChangeLineWithCount(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have 3 lines: one + empty + five // Should have 3 lines: one + empty + five
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "one" { if m.ActiveBuffer().Lines[0] != "one" {
t.Errorf("Line(0) = %q, want 'one'", m.Line(0)) t.Errorf("Line(0) = %q, want 'one'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "five" { if m.ActiveBuffer().Lines[2] != "five" {
t.Errorf("Line(2) = %q, want 'five'", m.Line(2)) t.Errorf("Line(2) = %q, want 'five'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -193,11 +193,11 @@ func TestChangeLineWithCount(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -235,8 +235,8 @@ func TestChangeWithHorizontalMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "ello world" { if m.ActiveBuffer().Lines[0] != "ello world" {
t.Errorf("Line(0) = %q, want 'ello world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'ello world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -251,8 +251,8 @@ func TestChangeWithHorizontalMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "llo world" { if m.ActiveBuffer().Lines[0] != "llo world" {
t.Errorf("Line(0) = %q, want 'llo world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'llo world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -267,8 +267,8 @@ func TestChangeWithHorizontalMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "hell world" { if m.ActiveBuffer().Lines[0] != "hell world" {
t.Errorf("Line(0) = %q, want 'hell world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hell world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -283,8 +283,8 @@ func TestChangeWithHorizontalMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "hello " { if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -299,8 +299,8 @@ func TestChangeWithHorizontalMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "world" { if m.ActiveBuffer().Lines[0] != "world" {
t.Errorf("Line(0) = %q, want 'world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -317,8 +317,8 @@ func TestChangeWithHorizontalMotion(t *testing.T) {
} }
// ^ is exclusive motion, so position 8 (space) is not included // ^ is exclusive motion, so position 8 (space) is not included
// Delete positions 3-7 ("hello"), leaving " " + " world" = " world" // Delete positions 3-7 ("hello"), leaving " " + " world" = " world"
if m.Line(0) != " world" { if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0)) t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -339,8 +339,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "world" { if m.ActiveBuffer().Lines[0] != "world" {
t.Errorf("Line(0) = %q, want 'world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -355,8 +355,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "heworld" { if m.ActiveBuffer().Lines[0] != "heworld" {
t.Errorf("Line(0) = %q, want 'heworld'", m.Line(0)) t.Errorf("Line(0) = %q, want 'heworld'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -371,8 +371,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != " world" { if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0)) t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -387,8 +387,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "world" { if m.ActiveBuffer().Lines[0] != "world" {
t.Errorf("Line(0) = %q, want 'world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -403,8 +403,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "three four" { if m.ActiveBuffer().Lines[0] != "three four" {
t.Errorf("Line(0) = %q, want 'three four'", m.Line(0)) t.Errorf("Line(0) = %q, want 'three four'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -419,8 +419,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "next" { if m.ActiveBuffer().Lines[0] != "next" {
t.Errorf("Line(0) = %q, want 'next'", m.Line(0)) t.Errorf("Line(0) = %q, want 'next'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -435,8 +435,8 @@ func TestChangeWithWordMotion(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != " next" { if m.ActiveBuffer().Lines[0] != " next" {
t.Errorf("Line(0) = %q, want ' next'", m.Line(0)) t.Errorf("Line(0) = %q, want ' next'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -458,14 +458,14 @@ func TestChangeWithVerticalMotion(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have empty line + line three // Should have empty line + line three
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "line three" { if m.ActiveBuffer().Lines[1] != "line three" {
t.Errorf("Line(1) = %q, want 'line three'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line three'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -481,14 +481,14 @@ func TestChangeWithVerticalMotion(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have empty line + line three // Should have empty line + line three
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "line three" { if m.ActiveBuffer().Lines[1] != "line three" {
t.Errorf("Line(1) = %q, want 'line three'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line three'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -504,14 +504,14 @@ func TestChangeWithVerticalMotion(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have empty + four + five // Should have empty + four + five
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "four" { if m.ActiveBuffer().Lines[1] != "four" {
t.Errorf("Line(1) = %q, want 'four'", m.Line(1)) t.Errorf("Line(1) = %q, want 'four'", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -533,11 +533,11 @@ func TestChangeWithJumpMotion(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// All lines should be replaced with one empty line // All lines should be replaced with one empty line
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -553,11 +553,11 @@ func TestChangeWithJumpMotion(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// All lines should be replaced with one empty line // All lines should be replaced with one empty line
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -573,14 +573,14 @@ func TestChangeWithJumpMotion(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have line one + empty // Should have line one + empty
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "line one" { if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -601,8 +601,8 @@ func TestChangeToEndOfLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "hello " { if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -617,8 +617,8 @@ func TestChangeToEndOfLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -634,8 +634,8 @@ func TestChangeToEndOfLine(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should delete last char // Should delete last char
if m.Line(0) != "hell" { if m.ActiveBuffer().Lines[0] != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hell'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -673,8 +673,8 @@ func TestSubstituteCharacter(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "ello" { if m.ActiveBuffer().Lines[0] != "ello" {
t.Errorf("Line(0) = %q, want 'ello'", m.Line(0)) t.Errorf("Line(0) = %q, want 'ello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -689,8 +689,8 @@ func TestSubstituteCharacter(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "llo" { if m.ActiveBuffer().Lines[0] != "llo" {
t.Errorf("Line(0) = %q, want 'llo'", m.Line(0)) t.Errorf("Line(0) = %q, want 'llo'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -705,8 +705,8 @@ func TestSubstituteCharacter(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "hell" { if m.ActiveBuffer().Lines[0] != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hell'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -727,8 +727,8 @@ func TestSubstituteLine(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -740,14 +740,14 @@ func TestSubstituteLine(t *testing.T) {
sendKeys(tm, "S") sendKeys(tm, "S")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "line one" { if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "line three" { if m.ActiveBuffer().Lines[2] != "line three" {
t.Errorf("Line(2) = %q, want 'line three'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line three'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -763,14 +763,14 @@ func TestSubstituteLine(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have empty + three + four // Should have empty + three + four
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "three" { if m.ActiveBuffer().Lines[1] != "three" {
t.Errorf("Line(1) = %q, want 'three'", m.Line(1)) t.Errorf("Line(1) = %q, want 'three'", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -791,8 +791,8 @@ func TestVisualModeChange(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "ello world" { if m.ActiveBuffer().Lines[0] != "ello world" {
t.Errorf("Line(0) = %q, want 'ello world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'ello world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -807,8 +807,8 @@ func TestVisualModeChange(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != " world" { if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0)) t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -823,8 +823,8 @@ func TestVisualModeChange(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "hello " { if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -840,8 +840,8 @@ func TestVisualModeChange(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should merge lines with selection removed // Should merge lines with selection removed
if m.LineCount() != 2 { if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount()) t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
} }
}) })
@ -875,11 +875,11 @@ func TestVisualLineModeChange(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
}) })
@ -895,17 +895,17 @@ func TestVisualLineModeChange(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// Should have: line one, empty, line four // Should have: line one, empty, line four
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "line one" { if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "" { if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1)) t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "line four" { if m.ActiveBuffer().Lines[2] != "line four" {
t.Errorf("Line(2) = %q, want 'line four'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line four'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -946,8 +946,8 @@ func TestChangeEdgeCases(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -963,8 +963,8 @@ func TestChangeEdgeCases(t *testing.T) {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
// cw on last word should change to end of line // cw on last word should change to end of line
if m.Line(0) != "hello " { if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -979,8 +979,8 @@ func TestChangeEdgeCases(t *testing.T) {
if m.Mode() != action.InsertMode { if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode()) t.Errorf("Mode() = %v, want InsertMode", m.Mode())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,8 @@ func TestScrollBasic(t *testing.T) {
sendKeys(tm, "G") // go to bottom sendKeys(tm, "G") // go to bottom
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
}) })
@ -45,14 +45,14 @@ func TestScrollBasic(t *testing.T) {
} }
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 15 { if m.ActiveWindow().Cursor.Line != 15 {
t.Errorf("CursorY() = %d, want 15", m.CursorY()) t.Errorf("CursorY() = %d, want 15", m.ActiveWindow().Cursor.Line)
} }
// With scrollOff=8, viewport=19, cursor at 15 means: // With scrollOff=8, viewport=19, cursor at 15 means:
// cursor should be at position 10 from top (19-1-8=10) // cursor should be at position 10 from top (19-1-8=10)
// so scrollY = 15 - 10 = 5 // so scrollY = 15 - 10 = 5
if m.ScrollY() < 1 { if m.ActiveWindow().ScrollY < 1 {
t.Errorf("ScrollY() = %d, want > 0 (should have scrolled)", m.ScrollY()) t.Errorf("ScrollY() = %d, want > 0 (should have scrolled)", m.ActiveWindow().ScrollY)
} }
}) })
@ -68,13 +68,13 @@ func TestScrollBasic(t *testing.T) {
} }
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 5 { if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY()) t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
} }
// Cursor at line 5 with scrollOff=8 means scrollY should be 0 // Cursor at line 5 with scrollOff=8 means scrollY should be 0
// (can't scroll negative, and cursor is within safe zone from top) // (can't scroll negative, and cursor is within safe zone from top)
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
}) })
@ -84,13 +84,13 @@ func TestScrollBasic(t *testing.T) {
sendKeys(tm, "G") sendKeys(tm, "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 99 { if m.ActiveWindow().Cursor.Line != 99 {
t.Errorf("CursorY() = %d, want 99", m.CursorY()) t.Errorf("CursorY() = %d, want 99", m.ActiveWindow().Cursor.Line)
} }
// With 100 lines and viewport 18 (height - 2 for status + command bar), // With 100 lines and viewport 18 (height - 2 for status + command bar),
// max scrollY = 100 - 18 = 82 // max scrollY = 100 - 18 = 82
if m.ScrollY() != 82 { if m.ActiveWindow().ScrollY != 82 {
t.Errorf("ScrollY() = %d, want 82", m.ScrollY()) t.Errorf("ScrollY() = %d, want 82", m.ActiveWindow().ScrollY)
} }
}) })
@ -100,11 +100,11 @@ func TestScrollBasic(t *testing.T) {
sendKeys(tm, "g", "g") sendKeys(tm, "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
}) })
} }
@ -120,8 +120,8 @@ func TestScrollEdgeCases(t *testing.T) {
} }
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() < 0 { if m.ActiveWindow().ScrollY < 0 {
t.Errorf("ScrollY() = %d, want >= 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want >= 0", m.ActiveWindow().ScrollY)
} }
}) })
@ -133,8 +133,8 @@ func TestScrollEdgeCases(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// 30 lines, viewport 18 (height - 2) -> maxScroll = 30 - 18 = 12 // 30 lines, viewport 18 (height - 2) -> maxScroll = 30 - 18 = 12
maxScroll := 30 - 18 maxScroll := 30 - 18
if m.ScrollY() > maxScroll { if m.ActiveWindow().ScrollY > maxScroll {
t.Errorf("ScrollY() = %d, want <= %d", m.ScrollY(), maxScroll) t.Errorf("ScrollY() = %d, want <= %d", m.ActiveWindow().ScrollY, maxScroll)
} }
}) })
@ -148,9 +148,9 @@ func TestScrollEdgeCases(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Cursor should still be visible // Cursor should still be visible
viewportHeight := 19 viewportHeight := 19
if m.CursorY() < m.ScrollY() || m.CursorY() >= m.ScrollY()+viewportHeight { if m.ActiveWindow().Cursor.Line < m.ActiveWindow().ScrollY || m.ActiveWindow().Cursor.Line >= m.ActiveWindow().ScrollY+viewportHeight {
t.Errorf("Cursor at %d not visible in viewport [%d, %d)", t.Errorf("Cursor at %d not visible in viewport [%d, %d)",
m.CursorY(), m.ScrollY(), m.ScrollY()+viewportHeight) m.ActiveWindow().Cursor.Line, m.ActiveWindow().ScrollY, m.ActiveWindow().ScrollY+viewportHeight)
} }
}) })
} }
@ -166,11 +166,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d") sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 14 { if m.ActiveWindow().ScrollY != 14 {
t.Errorf("ScrollY() = %d, want 14", m.ScrollY()) t.Errorf("ScrollY() = %d, want 14", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 29 { if m.ActiveWindow().Cursor.Line != 29 {
t.Errorf("CursorY() = %d, want 29", m.CursorY()) t.Errorf("CursorY() = %d, want 29", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -181,7 +181,7 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d") sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
relY := m.CursorY() - m.ScrollY() relY := m.ActiveWindow().Cursor.Line - m.ActiveWindow().ScrollY
if relY != 15 { if relY != 15 {
t.Errorf("relative position = %d, want 15", relY) t.Errorf("relative position = %d, want 15", relY)
} }
@ -195,11 +195,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d") sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 14 { if m.ActiveWindow().ScrollY != 14 {
t.Errorf("ScrollY() = %d, want 14", m.ScrollY()) t.Errorf("ScrollY() = %d, want 14", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 22 { if m.ActiveWindow().Cursor.Line != 22 {
t.Errorf("CursorY() = %d, want 22", m.CursorY()) t.Errorf("CursorY() = %d, want 22", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -213,11 +213,11 @@ func TestHalfPageScrollDown(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
maxScroll := 40 - 28 maxScroll := 40 - 28
if m.ScrollY() > maxScroll { if m.ActiveWindow().ScrollY > maxScroll {
t.Errorf("ScrollY() = %d, want <= %d", m.ScrollY(), maxScroll) t.Errorf("ScrollY() = %d, want <= %d", m.ActiveWindow().ScrollY, maxScroll)
} }
if m.CursorY() != 31 { if m.ActiveWindow().Cursor.Line != 31 {
t.Errorf("CursorY() = %d, want 31", m.CursorY()) t.Errorf("CursorY() = %d, want 31", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -229,11 +229,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d") sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 8 { if m.ActiveWindow().Cursor.Line != 8 {
t.Errorf("CursorY() = %d, want 8", m.CursorY()) t.Errorf("CursorY() = %d, want 8", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -253,11 +253,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d") sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 22 { if m.ActiveWindow().Cursor.Line != 22 {
t.Errorf("CursorY() = %d, want 22", m.CursorY()) t.Errorf("CursorY() = %d, want 22", m.ActiveWindow().Cursor.Line)
} }
if m.CursorX() > len(m.Line(m.CursorY())) { if m.ActiveWindow().Cursor.Col > len(m.ActiveBuffer().Lines[m.ActiveWindow().Cursor.Line]) {
t.Errorf("CursorX() = %d exceeds line length %d", m.CursorX(), len(m.Line(m.CursorY()))) t.Errorf("CursorX() = %d exceeds line length %d", m.ActiveWindow().Cursor.Col, len(m.ActiveBuffer().Lines[m.ActiveWindow().Cursor.Line]))
} }
}) })
@ -270,11 +270,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d", "ctrl+d") sendKeys(tm, "ctrl+d", "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 28 { if m.ActiveWindow().ScrollY != 28 {
t.Errorf("ScrollY() = %d, want 28", m.ScrollY()) t.Errorf("ScrollY() = %d, want 28", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 43 { if m.ActiveWindow().Cursor.Line != 43 {
t.Errorf("CursorY() = %d, want 43", m.CursorY()) t.Errorf("CursorY() = %d, want 43", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -288,11 +288,11 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u") sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 17 { if m.ActiveWindow().ScrollY != 17 {
t.Errorf("ScrollY() = %d, want 17", m.ScrollY()) t.Errorf("ScrollY() = %d, want 17", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 36 { if m.ActiveWindow().Cursor.Line != 36 {
t.Errorf("CursorY() = %d, want 36", m.CursorY()) t.Errorf("CursorY() = %d, want 36", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -303,7 +303,7 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u") sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
relY := m.CursorY() - m.ScrollY() relY := m.ActiveWindow().Cursor.Line - m.ActiveWindow().ScrollY
if relY != 19 { if relY != 19 {
t.Errorf("relative position = %d, want 19", relY) t.Errorf("relative position = %d, want 19", relY)
} }
@ -317,14 +317,14 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u") sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() < 0 { if m.ActiveWindow().ScrollY < 0 {
t.Errorf("ScrollY() = %d, want >= 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want >= 0", m.ActiveWindow().ScrollY)
} }
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 10 { if m.ActiveWindow().Cursor.Line != 10 {
t.Errorf("CursorY() = %d, want 10", m.CursorY()) t.Errorf("CursorY() = %d, want 10", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -336,11 +336,11 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u") sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 8 { if m.ActiveWindow().Cursor.Line != 8 {
t.Errorf("CursorY() = %d, want 8", m.CursorY()) t.Errorf("CursorY() = %d, want 8", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -353,11 +353,11 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u", "ctrl+u") sendKeys(tm, "ctrl+u", "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 33 { if m.ActiveWindow().ScrollY != 33 {
t.Errorf("ScrollY() = %d, want 33", m.ScrollY()) t.Errorf("ScrollY() = %d, want 33", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 52 { if m.ActiveWindow().Cursor.Line != 52 {
t.Errorf("CursorY() = %d, want 52", m.CursorY()) t.Errorf("CursorY() = %d, want 52", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -372,11 +372,11 @@ func TestHalfPageScrollRoundTrip(t *testing.T) {
sendKeys(tm, "ctrl+d", "ctrl+u") sendKeys(tm, "ctrl+d", "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 15 { if m.ActiveWindow().Cursor.Line != 15 {
t.Errorf("CursorY() = %d, want 15", m.CursorY()) t.Errorf("CursorY() = %d, want 15", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -389,11 +389,11 @@ func TestHalfPageScrollRoundTrip(t *testing.T) {
sendKeys(tm, "ctrl+u", "ctrl+d") sendKeys(tm, "ctrl+u", "ctrl+d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 31 { if m.ActiveWindow().ScrollY != 31 {
t.Errorf("ScrollY() = %d, want 31", m.ScrollY()) t.Errorf("ScrollY() = %d, want 31", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 50 { if m.ActiveWindow().Cursor.Line != 50 {
t.Errorf("CursorY() = %d, want 50", m.CursorY()) t.Errorf("CursorY() = %d, want 50", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -403,11 +403,11 @@ func TestHalfPageScrollRoundTrip(t *testing.T) {
sendKeys(tm, "ctrl+d", "ctrl+u", "ctrl+d", "ctrl+u") sendKeys(tm, "ctrl+d", "ctrl+u", "ctrl+d", "ctrl+u")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.ScrollY() != 0 { if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0 after 2 round trips", m.ScrollY()) t.Errorf("ScrollY() = %d, want 0 after 2 round trips", m.ActiveWindow().ScrollY)
} }
if m.CursorY() != 15 { if m.ActiveWindow().Cursor.Line != 15 {
t.Errorf("CursorY() = %d, want 15 after 2 round trips", m.CursorY()) t.Errorf("CursorY() = %d, want 15 after 2 round trips", m.ActiveWindow().Cursor.Line)
} }
}) })
} }
@ -420,12 +420,12 @@ func TestScrollWithCount(t *testing.T) {
sendKeys(tm, "1", "0", "j") // move down 10 lines sendKeys(tm, "1", "0", "j") // move down 10 lines
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 15 { if m.ActiveWindow().Cursor.Line != 15 {
t.Errorf("CursorY() = %d, want 15", m.CursorY()) t.Errorf("CursorY() = %d, want 15", m.ActiveWindow().Cursor.Line)
} }
// Should have scrolled since we moved past the safe zone // Should have scrolled since we moved past the safe zone
if m.ScrollY() == 0 { if m.ActiveWindow().ScrollY == 0 {
t.Errorf("ScrollY() = %d, want > 0", m.ScrollY()) t.Errorf("ScrollY() = %d, want > 0", m.ActiveWindow().ScrollY)
} }
}) })
@ -436,8 +436,8 @@ func TestScrollWithCount(t *testing.T) {
sendKeys(tm, "1", "5", "k") // move up 15 lines sendKeys(tm, "1", "5", "k") // move up 15 lines
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 10 { if m.ActiveWindow().Cursor.Line != 10 {
t.Errorf("CursorY() = %d, want 10", m.CursorY()) t.Errorf("CursorY() = %d, want 10", m.ActiveWindow().Cursor.Line)
} }
}) })
} }

View File

@ -20,11 +20,11 @@ func TestVisualModeSelectionState(t *testing.T) {
if m.Mode() != action.VisualMode { if m.Mode() != action.VisualMode {
t.Errorf("Mode() = %v, want VisualMode", m.Mode()) t.Errorf("Mode() = %v, want VisualMode", m.Mode())
} }
if m.AnchorX() != 3 { if m.ActiveWindow().Anchor.Col != 3 {
t.Errorf("AnchorX() = %d, want 3", m.AnchorX()) t.Errorf("AnchorX() = %d, want 3", m.ActiveWindow().Anchor.Col)
} }
if m.AnchorY() != 0 { if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY()) t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
} }
}) })
@ -34,11 +34,11 @@ func TestVisualModeSelectionState(t *testing.T) {
sendKeys(tm, "v", "l") sendKeys(tm, "v", "l")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 0 { if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX()) t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
} }
if m.CursorX() != 1 { if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX()) t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -48,11 +48,11 @@ func TestVisualModeSelectionState(t *testing.T) {
sendKeys(tm, "v", "h") sendKeys(tm, "v", "h")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 3 { if m.ActiveWindow().Anchor.Col != 3 {
t.Errorf("AnchorX() = %d, want 3", m.AnchorX()) t.Errorf("AnchorX() = %d, want 3", m.ActiveWindow().Anchor.Col)
} }
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX()) t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -62,14 +62,14 @@ func TestVisualModeSelectionState(t *testing.T) {
sendKeys(tm, "v", "j") sendKeys(tm, "v", "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 2 { if m.ActiveWindow().Anchor.Col != 2 {
t.Errorf("AnchorX() = %d, want 2", m.AnchorX()) t.Errorf("AnchorX() = %d, want 2", m.ActiveWindow().Anchor.Col)
} }
if m.AnchorY() != 0 { if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY()) t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
} }
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY()) t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -82,8 +82,8 @@ func TestVisualModeSelectionState(t *testing.T) {
if m.Mode() != action.VisualLineMode { if m.Mode() != action.VisualLineMode {
t.Errorf("Mode() = %v, want VisualLineMode", m.Mode()) t.Errorf("Mode() = %v, want VisualLineMode", m.Mode())
} }
if m.AnchorY() != 1 { if m.ActiveWindow().Anchor.Line != 1 {
t.Errorf("AnchorY() = %d, want 1", m.AnchorY()) t.Errorf("AnchorY() = %d, want 1", m.ActiveWindow().Anchor.Line)
} }
}) })
@ -96,11 +96,11 @@ func TestVisualModeSelectionState(t *testing.T) {
if m.Mode() != action.VisualBlockMode { if m.Mode() != action.VisualBlockMode {
t.Errorf("Mode() = %v, want VisualBlockMode", m.Mode()) t.Errorf("Mode() = %v, want VisualBlockMode", m.Mode())
} }
if m.AnchorX() != 2 { if m.ActiveWindow().Anchor.Col != 2 {
t.Errorf("AnchorX() = %d, want 2", m.AnchorX()) t.Errorf("AnchorX() = %d, want 2", m.ActiveWindow().Anchor.Col)
} }
if m.AnchorY() != 1 { if m.ActiveWindow().Anchor.Line != 1 {
t.Errorf("AnchorY() = %d, want 1", m.AnchorY()) t.Errorf("AnchorY() = %d, want 1", m.ActiveWindow().Anchor.Line)
} }
}) })
@ -125,11 +125,11 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "v", "d") sendKeys(tm, "v", "d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ello" { if m.ActiveBuffer().Lines[0] != "ello" {
t.Errorf("Line(0) = %q, want \"ello\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"ello\"", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -139,11 +139,11 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "v", "l", "l", "l", "d") sendKeys(tm, "v", "l", "l", "l", "d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "o world" { if m.ActiveBuffer().Lines[0] != "o world" {
t.Errorf("Line(0) = %q, want \"o world\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"o world\"", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -154,11 +154,11 @@ func TestVisualModeDelete(t *testing.T) {
// anchor=3, cursor=1 → normalized start=1, end=3 → delete "ell" → "ho" // anchor=3, cursor=1 → normalized start=1, end=3 → delete "ell" → "ho"
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ho" { if m.ActiveBuffer().Lines[0] != "ho" {
t.Errorf("Line(0) = %q, want \"ho\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"ho\"", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 1 { if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX()) t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -169,17 +169,17 @@ func TestVisualModeDelete(t *testing.T) {
// start=(2,0), end=(2,1) → prefix="he", suffix="ld" → "held" // start=(2,0), end=(2,1) → prefix="he", suffix="ld" → "held"
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "held" { if m.ActiveBuffer().Lines[0] != "held" {
t.Errorf("Line(0) = %q, want \"held\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"held\"", m.ActiveBuffer().Lines[0])
} }
if m.CursorX() != 2 { if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX()) t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -189,14 +189,14 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "V", "d") sendKeys(tm, "V", "d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "world" { if m.ActiveBuffer().Lines[0] != "world" {
t.Errorf("Line(0) = %q, want \"world\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"world\"", m.ActiveBuffer().Lines[0])
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -206,14 +206,14 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "V", "j", "d") sendKeys(tm, "V", "j", "d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "testing" { if m.ActiveBuffer().Lines[0] != "testing" {
t.Errorf("Line(0) = %q, want \"testing\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"testing\"", m.ActiveBuffer().Lines[0])
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -224,11 +224,11 @@ func TestVisualModeDelete(t *testing.T) {
// anchor=line2, cursor=line1 → normalized start=line1, end=line2 → delete both // anchor=line2, cursor=line1 → normalized start=line1, end=line2 → delete both
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "hello" { if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want \"hello\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"hello\"", m.ActiveBuffer().Lines[0])
} }
}) })
@ -241,17 +241,17 @@ func TestVisualModeDelete(t *testing.T) {
// "hello"[:0]+"hello"[2:] = "llo" // "hello"[:0]+"hello"[2:] = "llo"
// "world"[:0]+"world"[2:] = "rld" // "world"[:0]+"world"[2:] = "rld"
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "llo" { if m.ActiveBuffer().Lines[0] != "llo" {
t.Errorf("Line(0) = %q, want \"llo\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"llo\"", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "rld" { if m.ActiveBuffer().Lines[1] != "rld" {
t.Errorf("Line(1) = %q, want \"rld\"", m.Line(1)) t.Errorf("Line(1) = %q, want \"rld\"", m.ActiveBuffer().Lines[1])
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -264,11 +264,11 @@ func TestVisualModeDelete(t *testing.T) {
// "hello"[:1]+"hello"[4:] = "h"+"o" = "ho" // "hello"[:1]+"hello"[4:] = "h"+"o" = "ho"
// "world"[:1]+"world"[4:] = "w"+"d" = "wd" // "world"[:1]+"world"[4:] = "w"+"d" = "wd"
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "ho" { if m.ActiveBuffer().Lines[0] != "ho" {
t.Errorf("Line(0) = %q, want \"ho\"", m.Line(0)) t.Errorf("Line(0) = %q, want \"ho\"", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "wd" { if m.ActiveBuffer().Lines[1] != "wd" {
t.Errorf("Line(1) = %q, want \"wd\"", m.Line(1)) t.Errorf("Line(1) = %q, want \"wd\"", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -284,12 +284,12 @@ func TestVisualModeWordMotions(t *testing.T) {
sendKeys(tm, "v", "w") sendKeys(tm, "v", "w")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 0 { if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX()) t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
} }
// w moves to start of "world" at col 6 // w moves to start of "world" at col 6
if m.CursorX() != 6 { if m.ActiveWindow().Cursor.Col != 6 {
t.Errorf("CursorX() = %d, want 6", m.CursorX()) t.Errorf("CursorX() = %d, want 6", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -302,8 +302,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Deletes from 0 to 6 inclusive = "hello w", leaves "orld" // Deletes from 0 to 6 inclusive = "hello w", leaves "orld"
if m.Line(0) != "orld" { if m.ActiveBuffer().Lines[0] != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.Line(0)) t.Errorf("Line(0) = %q, want 'orld'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -315,12 +315,12 @@ func TestVisualModeWordMotions(t *testing.T) {
sendKeys(tm, "v", "e") sendKeys(tm, "v", "e")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 0 { if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX()) t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
} }
// e moves to end of "hello" at col 4 // e moves to end of "hello" at col 4
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -333,8 +333,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Deletes "hello" // Deletes "hello"
if m.Line(0) != " world" { if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0)) t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -346,12 +346,12 @@ func TestVisualModeWordMotions(t *testing.T) {
sendKeys(tm, "v", "b") sendKeys(tm, "v", "b")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 6 { if m.ActiveWindow().Anchor.Col != 6 {
t.Errorf("AnchorX() = %d, want 6", m.AnchorX()) t.Errorf("AnchorX() = %d, want 6", m.ActiveWindow().Anchor.Col)
} }
// b moves to start of "hello" at col 0 // b moves to start of "hello" at col 0
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -364,8 +364,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Deletes from "h" (0) to "w" (6) inclusive // Deletes from "h" (0) to "w" (6) inclusive
if m.Line(0) != "orld" { if m.ActiveBuffer().Lines[0] != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.Line(0)) t.Errorf("Line(0) = %q, want 'orld'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -378,8 +378,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// 2w moves past "one " and "two " to start of "three" at col 8 // 2w moves past "one " and "two " to start of "three" at col 8
if m.CursorX() != 8 { if m.ActiveWindow().Cursor.Col != 8 {
t.Errorf("CursorX() = %d, want 8", m.CursorX()) t.Errorf("CursorX() = %d, want 8", m.ActiveWindow().Cursor.Col)
} }
}) })
} }
@ -395,12 +395,12 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "$") sendKeys(tm, "v", "$")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 0 { if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX()) t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
} }
// $ moves past end of line // $ moves past end of line
if m.CursorX() != 11 { if m.ActiveWindow().Cursor.Col != 11 {
t.Errorf("CursorX() = %d, want 11", m.CursorX()) t.Errorf("CursorX() = %d, want 11", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -412,8 +412,8 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "$", "d") sendKeys(tm, "v", "$", "d")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello " { if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -425,11 +425,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "0") sendKeys(tm, "v", "0")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 6 { if m.ActiveWindow().Anchor.Col != 6 {
t.Errorf("AnchorX() = %d, want 6", m.AnchorX()) t.Errorf("AnchorX() = %d, want 6", m.ActiveWindow().Anchor.Col)
} }
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -442,8 +442,8 @@ func TestVisualModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// Deletes from 'h' (0) to 'w' (6) inclusive // Deletes from 'h' (0) to 'w' (6) inclusive
if m.Line(0) != "orld" { if m.ActiveBuffer().Lines[0] != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.Line(0)) t.Errorf("Line(0) = %q, want 'orld'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -455,12 +455,12 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "_") sendKeys(tm, "v", "_")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorX() != 10 { if m.ActiveWindow().Anchor.Col != 10 {
t.Errorf("AnchorX() = %d, want 10", m.AnchorX()) t.Errorf("AnchorX() = %d, want 10", m.ActiveWindow().Anchor.Col)
} }
// _ moves to first non-ws at col 4 // _ moves to first non-ws at col 4
if m.CursorX() != 4 { if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX()) t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -472,11 +472,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "G") sendKeys(tm, "v", "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorY() != 0 { if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY()) t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
} }
if m.CursorY() != 2 { if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY()) t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -490,11 +490,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// G goes to last line at same col, deletes from (0,3) to (2,3) // G goes to last line at same col, deletes from (0,3) to (2,3)
// Keeps "lin" from first line + "e 3" from last line = "lin 3" // Keeps "lin" from first line + "e 3" from last line = "lin 3"
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "lin 3" { if m.ActiveBuffer().Lines[0] != "lin 3" {
t.Errorf("Line(0) = %q, want 'lin 3'", m.Line(0)) t.Errorf("Line(0) = %q, want 'lin 3'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -506,11 +506,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "g", "g") sendKeys(tm, "v", "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorY() != 2 { if m.ActiveWindow().Anchor.Line != 2 {
t.Errorf("AnchorY() = %d, want 2", m.AnchorY()) t.Errorf("AnchorY() = %d, want 2", m.ActiveWindow().Anchor.Line)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -524,11 +524,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// gg goes to first line at same col, deletes selection // gg goes to first line at same col, deletes selection
// Keeps "lin" from first line + " 3" from last line = "lin 3" // Keeps "lin" from first line + " 3" from last line = "lin 3"
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "lin 3" { if m.ActiveBuffer().Lines[0] != "lin 3" {
t.Errorf("Line(0) = %q, want 'lin 3'", m.Line(0)) t.Errorf("Line(0) = %q, want 'lin 3'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -544,11 +544,11 @@ func TestVisualLineModeJumpMotions(t *testing.T) {
sendKeys(tm, "V", "G") sendKeys(tm, "V", "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorY() != 0 { if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY()) t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
} }
if m.CursorY() != 2 { if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY()) t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -561,11 +561,11 @@ func TestVisualLineModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
// All lines deleted, should have empty buffer // All lines deleted, should have empty buffer
if m.LineCount() != 1 { if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount()) t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "" { if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0)) t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
} }
}) })
@ -577,11 +577,11 @@ func TestVisualLineModeJumpMotions(t *testing.T) {
sendKeys(tm, "V", "g", "g") sendKeys(tm, "V", "g", "g")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.AnchorY() != 2 { if m.ActiveWindow().Anchor.Line != 2 {
t.Errorf("AnchorY() = %d, want 2", m.AnchorY()) t.Errorf("AnchorY() = %d, want 2", m.ActiveWindow().Anchor.Line)
} }
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
} }

View File

@ -43,17 +43,17 @@ func TestYankLineBasic(t *testing.T) {
sendKeys(tm, "y", "y") sendKeys(tm, "y", "y")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "line 1" { if m.ActiveBuffer().Lines[0] != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line 1'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "line 2" { if m.ActiveBuffer().Lines[1] != "line 2" {
t.Errorf("Line(1) = %q, want 'line 2'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line 2'", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "line 3" { if m.ActiveBuffer().Lines[2] != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line 3'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -65,11 +65,11 @@ func TestYankLineBasic(t *testing.T) {
sendKeys(tm, "y", "y") sendKeys(tm, "y", "y")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 1 { if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY()) t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
} }
if m.CursorX() != 3 { if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("CursorX() = %d, want 3", m.CursorX()) t.Errorf("CursorX() = %d, want 3", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -174,8 +174,8 @@ func TestYankLineWithCount(t *testing.T) {
sendKeys(tm, "3", "y", "y") sendKeys(tm, "3", "y", "y")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
}) })
} }
@ -376,8 +376,8 @@ func TestYankWithLinewiseMotions(t *testing.T) {
sendKeys(tm, "y", "j") sendKeys(tm, "y", "j")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorY() != 0 { if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY()) t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
} }
}) })
@ -389,8 +389,8 @@ func TestYankWithLinewiseMotions(t *testing.T) {
sendKeys(tm, "y", "G") sendKeys(tm, "y", "G")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
}) })
} }
@ -570,8 +570,8 @@ func TestYankWithCharwiseMotions(t *testing.T) {
sendKeys(tm, "y", "w") sendKeys(tm, "y", "w")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.CursorX() != 0 { if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX()) t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
} }
}) })
@ -583,8 +583,8 @@ func TestYankWithCharwiseMotions(t *testing.T) {
sendKeys(tm, "y", "w") sendKeys(tm, "y", "w")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello world" { if m.ActiveBuffer().Lines[0] != "hello world" {
t.Errorf("Line(0) = %q, want 'hello world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello world'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -659,8 +659,8 @@ func TestYankVisualCharwise(t *testing.T) {
sendKeys(tm, "v", "l", "l", "l", "l", "y") sendKeys(tm, "v", "l", "l", "l", "l", "y")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello world" { if m.ActiveBuffer().Lines[0] != "hello world" {
t.Errorf("Line(0) = %q, want 'hello world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello world'", m.ActiveBuffer().Lines[0])
} }
}) })
} }
@ -901,11 +901,11 @@ func TestYankRegisterBehavior(t *testing.T) {
sendKeys(tm, "p") // paste sendKeys(tm, "p") // paste
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(1) != "to copy" { if m.ActiveBuffer().Lines[1] != "to copy" {
t.Errorf("Line(1) = %q, want 'to copy'", m.Line(1)) t.Errorf("Line(1) = %q, want 'to copy'", m.ActiveBuffer().Lines[1])
} }
}) })
} }
@ -1053,8 +1053,8 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "v", "l", "l", "l", "l", "y", "$", "p") sendKeys(tm, "v", "l", "l", "l", "l", "y", "$", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello worldhello" { if m.ActiveBuffer().Lines[0] != "hello worldhello" {
t.Errorf("Line(0) = %q, want 'hello worldhello'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello worldhello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -1067,8 +1067,8 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "v", "$", "y", "0", "P") sendKeys(tm, "v", "$", "y", "0", "P")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "worldhello world" { if m.ActiveBuffer().Lines[0] != "worldhello world" {
t.Errorf("Line(0) = %q, want 'worldhello world'", m.Line(0)) t.Errorf("Line(0) = %q, want 'worldhello world'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -1081,11 +1081,11 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "V", "y", "j", "p") sendKeys(tm, "V", "y", "j", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 4 { if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("LineCount() = %d, want 4", m.LineCount()) t.Errorf("LineCount() = %d, want 4", m.ActiveBuffer().LineCount())
} }
if m.Line(2) != "line 1" { if m.ActiveBuffer().Lines[2] != "line 1" {
t.Errorf("Line(2) = %q, want 'line 1'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line 1'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -1098,14 +1098,14 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "V", "j", "y", "G", "p") sendKeys(tm, "V", "j", "y", "G", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 6 { if m.ActiveBuffer().LineCount() != 6 {
t.Errorf("LineCount() = %d, want 6", m.LineCount()) t.Errorf("LineCount() = %d, want 6", m.ActiveBuffer().LineCount())
} }
if m.Line(4) != "line 1" { if m.ActiveBuffer().Lines[4] != "line 1" {
t.Errorf("Line(4) = %q, want 'line 1'", m.Line(4)) t.Errorf("Line(4) = %q, want 'line 1'", m.ActiveBuffer().Lines[4])
} }
if m.Line(5) != "line 2" { if m.ActiveBuffer().Lines[5] != "line 2" {
t.Errorf("Line(5) = %q, want 'line 2'", m.Line(5)) t.Errorf("Line(5) = %q, want 'line 2'", m.ActiveBuffer().Lines[5])
} }
}) })
@ -1118,14 +1118,14 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "V", "y", "g", "g", "P") sendKeys(tm, "V", "y", "g", "g", "P")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 4 { if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("LineCount() = %d, want 4", m.LineCount()) t.Errorf("LineCount() = %d, want 4", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "line 3" { if m.ActiveBuffer().Lines[0] != "line 3" {
t.Errorf("Line(0) = %q, want 'line 3'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line 3'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "line 1" { if m.ActiveBuffer().Lines[1] != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line 1'", m.ActiveBuffer().Lines[1])
} }
}) })
@ -1137,17 +1137,17 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "y", "y", "p") sendKeys(tm, "y", "y", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "original" { if m.ActiveBuffer().Lines[0] != "original" {
t.Errorf("Line(0) = %q, want 'original'", m.Line(0)) t.Errorf("Line(0) = %q, want 'original'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "original" { if m.ActiveBuffer().Lines[1] != "original" {
t.Errorf("Line(1) = %q, want 'original'", m.Line(1)) t.Errorf("Line(1) = %q, want 'original'", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "other" { if m.ActiveBuffer().Lines[2] != "other" {
t.Errorf("Line(2) = %q, want 'other'", m.Line(2)) t.Errorf("Line(2) = %q, want 'other'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -1159,17 +1159,17 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "y", "y", "P") sendKeys(tm, "y", "y", "P")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "original" { if m.ActiveBuffer().Lines[0] != "original" {
t.Errorf("Line(0) = %q, want 'original'", m.Line(0)) t.Errorf("Line(0) = %q, want 'original'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "other" { if m.ActiveBuffer().Lines[1] != "other" {
t.Errorf("Line(1) = %q, want 'other'", m.Line(1)) t.Errorf("Line(1) = %q, want 'other'", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "other" { if m.ActiveBuffer().Lines[2] != "other" {
t.Errorf("Line(2) = %q, want 'other'", m.Line(2)) t.Errorf("Line(2) = %q, want 'other'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -1182,8 +1182,8 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "y", "w", "$", "p") sendKeys(tm, "y", "w", "$", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello worldhello " { if m.ActiveBuffer().Lines[0] != "hello worldhello " {
t.Errorf("Line(0) = %q, want 'hello worldhello '", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello worldhello '", m.ActiveBuffer().Lines[0])
} }
}) })
@ -1196,8 +1196,8 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "y", "e", "$", "p") sendKeys(tm, "y", "e", "$", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "hello worldhello" { if m.ActiveBuffer().Lines[0] != "hello worldhello" {
t.Errorf("Line(0) = %q, want 'hello worldhello'", m.Line(0)) t.Errorf("Line(0) = %q, want 'hello worldhello'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -1210,8 +1210,8 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "v", "l", "l", "y", "$", "p") sendKeys(tm, "v", "l", "l", "y", "$", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.Line(0) != "abcdefghcde" { if m.ActiveBuffer().Lines[0] != "abcdefghcde" {
t.Errorf("Line(0) = %q, want 'abcdefghcde'", m.Line(0)) t.Errorf("Line(0) = %q, want 'abcdefghcde'", m.ActiveBuffer().Lines[0])
} }
}) })
@ -1243,17 +1243,17 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "d", "d", "p") sendKeys(tm, "d", "d", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 3 { if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount()) t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
} }
if m.Line(0) != "line 2" { if m.ActiveBuffer().Lines[0] != "line 2" {
t.Errorf("Line(0) = %q, want 'line 2'", m.Line(0)) t.Errorf("Line(0) = %q, want 'line 2'", m.ActiveBuffer().Lines[0])
} }
if m.Line(1) != "line 1" { if m.ActiveBuffer().Lines[1] != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line 1'", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "line 3" { if m.ActiveBuffer().Lines[2] != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line 3'", m.ActiveBuffer().Lines[2])
} }
}) })
@ -1266,21 +1266,21 @@ func TestVisualYankPasteRoundTrip(t *testing.T) {
sendKeys(tm, "2", "y", "y", "2", "p") sendKeys(tm, "2", "y", "y", "2", "p")
m := getFinalModel(t, tm) m := getFinalModel(t, tm)
if m.LineCount() != 7 { if m.ActiveBuffer().LineCount() != 7 {
t.Errorf("LineCount() = %d, want 7", m.LineCount()) t.Errorf("LineCount() = %d, want 7", m.ActiveBuffer().LineCount())
} }
// Original + 2 copies of 2 lines = 3 + 4 = 7 // Original + 2 copies of 2 lines = 3 + 4 = 7
if m.Line(1) != "line 1" { if m.ActiveBuffer().Lines[1] != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.Line(1)) t.Errorf("Line(1) = %q, want 'line 1'", m.ActiveBuffer().Lines[1])
} }
if m.Line(2) != "line 2" { if m.ActiveBuffer().Lines[2] != "line 2" {
t.Errorf("Line(2) = %q, want 'line 2'", m.Line(2)) t.Errorf("Line(2) = %q, want 'line 2'", m.ActiveBuffer().Lines[2])
} }
if m.Line(3) != "line 1" { if m.ActiveBuffer().Lines[3] != "line 1" {
t.Errorf("Line(3) = %q, want 'line 1'", m.Line(3)) t.Errorf("Line(3) = %q, want 'line 1'", m.ActiveBuffer().Lines[3])
} }
if m.Line(4) != "line 2" { if m.ActiveBuffer().Lines[4] != "line 2" {
t.Errorf("Line(4) = %q, want 'line 2'", m.Line(4)) t.Errorf("Line(4) = %q, want 'line 2'", m.ActiveBuffer().Lines[4])
} }
}) })
} }

View File

@ -44,37 +44,9 @@ type Model struct {
// Registers // Registers
registers map[rune]action.Register // name -> register registers map[rune]action.Register // name -> register
}
func NewModel(lines []string, pos action.Position) *Model { // Visual styles
m := Model{ styles Styles
mode: action.NormalMode,
command: "",
input: input.NewHandler(),
settings: action.NewDefaultSettings(),
registers: action.DefaultRegisters(),
windows: []*action.Window{},
}
// TODO: Temporary: Build the single buffer and window
buf := action.
NewBufferBuilder().
WithLines(lines).
Build()
m.buffers = append(m.buffers, &buf)
win := action.
NewWindowBuilder().
WithBuffer(&buf).
WithCursor(pos).
Build()
m.windows = append(m.windows, &win)
m.activeWindowId = win.Id
return &m
} }
// Model.Init: Initialize the model and start any commands that may need to run. Required // Model.Init: Initialize the model and start any commands that may need to run. Required
@ -222,13 +194,11 @@ func (m *Model) processInsertKey(key string) {
case "up": case "up":
if line > 0 { if line > 0 {
win.SetCursorLine(line - 1) win.SetCursorLine(line - 1)
win.ClampCursorX()
} }
case "down": case "down":
if line+1 < buf.LineCount() { if line+1 < buf.LineCount() {
win.SetCursorLine(line + 1) win.SetCursorLine(line + 1)
win.ClampCursorX()
} }
case "left": case "left":
@ -318,6 +288,16 @@ func (m *Model) SetSettings(s action.Settings) {
m.settings = s m.settings = s
} }
// Model.Styles: Returns the visual styles used for rendering.
func (m *Model) Styles() Styles {
return m.styles
}
// Model.SetStyles: Sets the visual styles used for rendering.
func (m *Model) SetStyles(s Styles) {
m.styles = s
}
// ================================================== // ==================================================
// Registers // Registers
// ================================================== // ==================================================

View File

@ -0,0 +1,139 @@
package editor
import (
"git.gophernest.net/azpect/TextEditor/internal/action"
"git.gophernest.net/azpect/TextEditor/internal/input"
)
type ModelBuilder struct {
model Model
}
func NewModelBuilder() *ModelBuilder {
return &ModelBuilder{
model: Model{
buffers: []*action.Buffer{},
windows: []*action.Window{},
activeWindowId: -1,
mode: action.NormalMode,
termWidth: 0,
termHeight: 0,
input: input.NewHandler(),
insertCount: 0,
insertKeys: []string{},
insertAction: nil,
command: "",
commandCursor: 0,
commandError: nil,
commandOutput: "",
settings: action.NewDefaultSettings(),
registers: action.DefaultRegisters(),
styles: DefaultStyles(),
},
}
}
// ModelBuilder.WithBuffers: Set the buffers for the model. Buffers represent
// the in-memory text content of files being edited.
func (mb *ModelBuilder) WithBuffers(buffers []*action.Buffer) *ModelBuilder {
mb.model.buffers = buffers
return mb
}
// ModelBuilder.AddBuffer: Add a single buffer to the model's buffer list.
func (mb *ModelBuilder) AddBuffer(buffer *action.Buffer) *ModelBuilder {
mb.model.buffers = append(mb.model.buffers, buffer)
return mb
}
// ModelBuilder.WithWindows: Set the windows for the model. Windows are viewports
// that display buffer content with their own cursor position and scroll state.
func (mb *ModelBuilder) WithWindows(windows []*action.Window) *ModelBuilder {
mb.model.windows = windows
return mb
}
// ModelBuilder.AddWindow: Add a single window to the model's window list.
func (mb *ModelBuilder) AddWindow(window *action.Window) *ModelBuilder {
mb.model.windows = append(mb.model.windows, window)
return mb
}
// ModelBuilder.WithActiveWindowId: Set the ID of the currently active window.
// This determines which window receives input and displays the cursor.
func (mb *ModelBuilder) WithActiveWindowId(id int) *ModelBuilder {
mb.model.activeWindowId = id
return mb
}
// ModelBuilder.WithMode: Set the editor mode (Normal, Insert, Visual, etc).
func (mb *ModelBuilder) WithMode(mode action.Mode) *ModelBuilder {
mb.model.mode = mode
return mb
}
// ModelBuilder.WithTermSize: Set the terminal dimensions in columns and rows.
func (mb *ModelBuilder) WithTermSize(width, height int) *ModelBuilder {
mb.model.termWidth = width
mb.model.termHeight = height
return mb
}
// ModelBuilder.WithTermWidth: Set the terminal width in columns.
func (mb *ModelBuilder) WithTermWidth(width int) *ModelBuilder {
mb.model.termWidth = width
return mb
}
// ModelBuilder.WithTermHeight: Set the terminal height in rows.
func (mb *ModelBuilder) WithTermHeight(height int) *ModelBuilder {
mb.model.termHeight = height
return mb
}
// ModelBuilder.WithSettings: Set the editor settings (tabstop, scrolloff, etc).
func (mb *ModelBuilder) WithSettings(settings action.Settings) *ModelBuilder {
mb.model.settings = settings
return mb
}
// ModelBuilder.WithRegisters: Set the register map for yank/delete/paste operations.
func (mb *ModelBuilder) WithRegisters(registers map[rune]action.Register) *ModelBuilder {
mb.model.registers = registers
return mb
}
// ModelBuilder.WithCommand: Set the command line text.
func (mb *ModelBuilder) WithCommand(command string) *ModelBuilder {
mb.model.command = command
return mb
}
// ModelBuilder.WithCommandCursor: Set the cursor position in the command line.
func (mb *ModelBuilder) WithCommandCursor(cursor int) *ModelBuilder {
mb.model.commandCursor = cursor
return mb
}
// ModelBuilder.WithCommandError: Set the command line error state.
func (mb *ModelBuilder) WithCommandError(err error) *ModelBuilder {
mb.model.commandError = err
return mb
}
// ModelBuilder.WithCommandOutput: Set the command line output text.
func (mb *ModelBuilder) WithCommandOutput(output string) *ModelBuilder {
mb.model.commandOutput = output
return mb
}
// ModelBuilder.WithStyles: Set the visual styling for the editor.
func (mb *ModelBuilder) WithStyles(styles Styles) *ModelBuilder {
mb.model.styles = styles
return mb
}
// ModelBuilder.Build: Build and return the configured Model instance.
func (mb *ModelBuilder) Build() *Model {
return &mb.model
}

View File

@ -5,48 +5,121 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
) )
func (m Model) cursorStyle() lipgloss.Style { // Styles holds all the visual styling for the editor.
switch m.mode { // Passed to Window.View() so windows can render themselves.
case action.NormalMode, type Styles struct {
action.VisualMode, // Cursor styles by mode
action.VisualBlockMode, CursorNormal lipgloss.Style
action.VisualLineMode: CursorInsert lipgloss.Style
// Block cursor for normal mode CursorCommand lipgloss.Style
return lipgloss.NewStyle().Reverse(true)
// Gutter (line numbers)
Gutter lipgloss.Style
GutterCurrentLine lipgloss.Style
// Visual mode
VisualHighlight lipgloss.Style
VisualAnchor lipgloss.Style // debugging
// Status bar
StatusBar lipgloss.Style
StatusBarActive lipgloss.Style
// Command line
CommandError lipgloss.Style
}
// DefaultStyles returns the default editor color scheme.
func DefaultStyles() Styles {
return Styles{
CursorNormal: lipgloss.NewStyle().Reverse(true),
CursorInsert: lipgloss.NewStyle().Underline(true),
CursorCommand: lipgloss.NewStyle().Reverse(true),
Gutter: lipgloss.NewStyle().
Background(lipgloss.Color("236")).
Foreground(lipgloss.Color("243")),
GutterCurrentLine: lipgloss.NewStyle().
Background(lipgloss.Color("236")).
Foreground(lipgloss.Color("#d69d00")),
VisualHighlight: lipgloss.NewStyle().
Background(lipgloss.Color("#7a6a00")),
VisualAnchor: lipgloss.NewStyle().
Background(lipgloss.Color("#a89020")),
StatusBar: lipgloss.NewStyle().
Background(lipgloss.Color("236")).
Foreground(lipgloss.Color("243")),
StatusBarActive: lipgloss.NewStyle().
Background(lipgloss.Color("62")).
Foreground(lipgloss.Color("230")),
CommandError: lipgloss.NewStyle().
Foreground(lipgloss.Color("#e3203a")),
}
}
// CursorStyle returns the appropriate cursor style for the given mode.
func (s Styles) CursorStyle(mode action.Mode) lipgloss.Style {
switch mode {
case action.InsertMode: case action.InsertMode:
// Bar/underline for insert mode return s.CursorInsert
return lipgloss.NewStyle().Underline(true)
case action.CommandMode: case action.CommandMode:
return lipgloss.NewStyle().Reverse(true) return s.CursorCommand
default: default:
return lipgloss.NewStyle().Reverse(true) return s.CursorNormal
} }
} }
// DEBUGGING STYLE // ==================================================
func (m Model) visualAnchorStyle() lipgloss.Style { // Deprecated
bg := lipgloss.Color("#a89020") // ==================================================
return lipgloss.NewStyle().Background(bg) // func (m Model) cursorStyle() lipgloss.Style {
} // switch m.mode {
// case action.NormalMode,
func (m Model) gutterStyle(currentLine bool) lipgloss.Style { // action.VisualMode,
bg := lipgloss.Color("236") // action.VisualBlockMode,
fg := lipgloss.Color("243") // action.VisualLineMode:
if currentLine { // // Block cursor for normal mode
fg = lipgloss.Color("#d69d00") // return lipgloss.NewStyle().Reverse(true)
} // case action.InsertMode:
return lipgloss.NewStyle(). // // Bar/underline for insert mode
Width(m.Settings().GutterSize). // return lipgloss.NewStyle().Underline(true)
Background(bg). // case action.CommandMode:
Foreground(fg) // return lipgloss.NewStyle().Reverse(true)
} // default:
// return lipgloss.NewStyle().Reverse(true)
func (m Model) visualHighlightStyle() lipgloss.Style { // }
bg := lipgloss.Color("#7a6a00") // }
return lipgloss.NewStyle().Background(bg) //
} // // DEBUGGING STYLE
// func (m Model) visualAnchorStyle() lipgloss.Style {
func (m Model) commandErrorStyle() lipgloss.Style { // bg := lipgloss.Color("#a89020")
fg := lipgloss.Color("#e3203a") // return lipgloss.NewStyle().Background(bg)
return lipgloss.NewStyle().Foreground(fg) // }
} //
// func (m Model) gutterStyle(currentLine bool) lipgloss.Style {
// bg := lipgloss.Color("236")
// fg := lipgloss.Color("243")
// if currentLine {
// fg = lipgloss.Color("#d69d00")
// }
// return lipgloss.NewStyle().
// Width(m.Settings().GutterSize).
// Background(bg).
// Foreground(fg)
// }
//
// func (m Model) visualHighlightStyle() lipgloss.Style {
// bg := lipgloss.Color("#7a6a00")
// return lipgloss.NewStyle().Background(bg)
// }
//
// func (m Model) commandErrorStyle() lipgloss.Style {
// fg := lipgloss.Color("#e3203a")
// return lipgloss.NewStyle().Foreground(fg)
// }

View File

@ -56,7 +56,8 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
// Keep cursor in view after any update // Keep cursor in view after any update
m.AdjustScroll() win := m.ActiveWindow()
win.AdjustScroll()
return m, cmd return m, cmd
} }

View File

@ -8,18 +8,20 @@ import (
) )
func posInsideSelection(m Model, col, line int) bool { func posInsideSelection(m Model, col, line int) bool {
win := m.ActiveWindow()
switch m.Mode() { switch m.Mode() {
case action.VisualLineMode: case action.VisualLineMode:
startY := min(m.AnchorY(), m.CursorY()) startY := min(win.Anchor.Line, win.Cursor.Line)
endY := max(m.AnchorY(), m.CursorY()) endY := max(win.Anchor.Line, win.Cursor.Line)
return line >= startY && line <= endY return line >= startY && line <= endY
case action.VisualMode: case action.VisualMode:
ax := m.AnchorX() ax := win.Anchor.Col
ay := m.AnchorY() ay := win.Anchor.Line
cx := m.CursorX() cx := win.Cursor.Col
cy := m.CursorY() cy := win.Cursor.Line
// Normalize so start is always before end in document order // Normalize so start is always before end in document order
var startX, startY, endX, endY int var startX, startY, endX, endY int
@ -37,10 +39,10 @@ func posInsideSelection(m Model, col, line int) bool {
return afterStart && beforeEnd return afterStart && beforeEnd
case action.VisualBlockMode: case action.VisualBlockMode:
startX := min(m.AnchorX(), m.CursorX()) startX := min(win.Anchor.Col, win.Cursor.Col)
startY := min(m.AnchorY(), m.CursorY()) startY := min(win.Anchor.Line, win.Cursor.Line)
endX := max(m.AnchorX(), m.CursorX()) endX := max(win.Anchor.Col, win.Cursor.Col)
endY := max(m.AnchorY(), m.CursorY()) endY := max(win.Anchor.Line, win.Cursor.Line)
return col >= startX && col <= endX && return col >= startX && col <= endX &&
line >= startY && line <= endY line >= startY && line <= endY
@ -51,21 +53,25 @@ func posInsideSelection(m Model, col, line int) bool {
} }
func posIsAnchor(m Model, col, line int) bool { func posIsAnchor(m Model, col, line int) bool {
ax := m.AnchorX() win := m.ActiveWindow()
ay := m.AnchorY() ax := win.Anchor.Col
ay := win.Anchor.Line
return col == ax && line == ay return col == ax && line == ay
} }
func (m Model) View() string { func (m Model) View() string {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var view strings.Builder var view strings.Builder
viewportHeight := m.ViewPortH() viewportHeight := win.Height - 2
start := m.ScrollY() start := win.ScrollY
end := m.ScrollY() + viewportHeight end := win.ScrollY + viewportHeight
for i := start; i < end; i++ { for i := start; i < end; i++ {
if i < m.LineCount() { if i < buf.LineCount() {
if m.Settings().Number || m.Settings().RelativeNumber { if m.Settings().Number || m.Settings().RelativeNumber {
var ( var (
@ -76,11 +82,11 @@ func (m Model) View() string {
if m.Settings().RelativeNumber { if m.Settings().RelativeNumber {
// Relative line numbers: show distance from cursor, current line shows absolute // Relative line numbers: show distance from cursor, current line shows absolute
if i > m.CursorY() { if i > win.Cursor.Line {
lineNumber = i - m.CursorY() lineNumber = i - win.Cursor.Line
gutter = fmt.Sprintf("%*d ", m.Settings().GutterSize-1, lineNumber) gutter = fmt.Sprintf("%*d ", m.Settings().GutterSize-1, lineNumber)
} else if i < m.CursorY() { } else if i < win.Cursor.Line {
lineNumber = m.CursorY() - i lineNumber = win.Cursor.Line - i
gutter = fmt.Sprintf("%*d ", m.Settings().GutterSize-1, lineNumber) gutter = fmt.Sprintf("%*d ", m.Settings().GutterSize-1, lineNumber)
} else { } else {
// Current line: show absolute number if Number is also set, otherwise show 0 // Current line: show absolute number if Number is also set, otherwise show 0
@ -95,31 +101,35 @@ func (m Model) View() string {
} else if m.Settings().Number { } else if m.Settings().Number {
// Absolute line numbers only // Absolute line numbers only
lineNumber = i + 1 lineNumber = i + 1
currentLine = (i == m.CursorY()) currentLine = (i == win.Cursor.Line)
gutter = fmt.Sprintf("%*d ", m.Settings().GutterSize-1, lineNumber) gutter = fmt.Sprintf("%*d ", m.Settings().GutterSize-1, lineNumber)
} }
view.WriteString(m.gutterStyle(currentLine).Render(gutter)) if currentLine {
view.WriteString(m.Styles().GutterCurrentLine.Render(gutter))
} else {
view.WriteString(m.Styles().Gutter.Render(gutter))
}
} }
runes := []rune(m.Line(i)) runes := []rune(buf.Lines[i])
for x := 0; x <= len(runes); x++ { for x := 0; x <= len(runes); x++ {
if m.CursorY() == i && m.CursorX() == x { if win.Cursor.Line == i && win.Cursor.Col == x {
if x < len(runes) { if x < len(runes) {
view.WriteString(m.cursorStyle().Render(string(runes[x]))) view.WriteString(m.Styles().CursorStyle(m.Mode()).Render(string(runes[x])))
} else { } else {
view.WriteString(m.cursorStyle().Render(" ")) view.WriteString(m.Styles().CursorStyle(m.Mode()).Render(" "))
} }
} else if x < len(runes) { } else if x < len(runes) {
if m.Mode().IsVisualMode() && posIsAnchor(m, x, i) { if m.Mode().IsVisualMode() && posIsAnchor(m, x, i) {
view.WriteString(m.visualAnchorStyle().Render(string(runes[x]))) view.WriteString(m.Styles().VisualAnchor.Render(string(runes[x])))
} else if m.Mode().IsVisualMode() && posInsideSelection(m, x, i) { } else if m.Mode().IsVisualMode() && posInsideSelection(m, x, i) {
view.WriteString(m.visualHighlightStyle().Render(string(runes[x]))) view.WriteString(m.Styles().VisualHighlight.Render(string(runes[x])))
} else { } else {
view.WriteRune(runes[x]) view.WriteRune(runes[x])
} }
// To highlight blank lines when in visual mode // To highlight blank lines when in visual mode
} else if m.Mode().IsVisualMode() && posInsideSelection(m, x, i) { } else if m.Mode().IsVisualMode() && posInsideSelection(m, x, i) {
view.WriteString(m.visualHighlightStyle().Render(" ")) view.WriteString(m.Styles().VisualHighlight.Render(" "))
} }
} }
} else { } else {
@ -162,11 +172,13 @@ func leftBar(m Model) string {
} }
func rightBar(m Model) (bar string) { func rightBar(m Model) (bar string) {
win := m.ActiveWindow()
if m.Mode().IsVisualMode() { if m.Mode().IsVisualMode() {
lineCount := max(m.AnchorY(), m.CursorY()) - min(m.AnchorY(), m.CursorY()) + 1 lineCount := max(win.Anchor.Line, win.Cursor.Line) - min(win.Anchor.Line, win.Cursor.Line) + 1
bar = fmt.Sprintf("%d:%d <%d>", m.CursorY(), m.CursorX(), lineCount) bar = fmt.Sprintf("%d:%d <%d>", win.Cursor.Line, win.Cursor.Col, lineCount)
} else { } else {
bar = fmt.Sprintf("%d:%d ", m.CursorY(), m.CursorX()) bar = fmt.Sprintf("%d:%d ", win.Cursor.Line, win.Cursor.Col)
} }
return return
} }
@ -178,18 +190,18 @@ func drawCommandBar(m Model) (bar string) {
cur := m.CommandCursor() cur := m.CommandCursor()
for i := 0; i < len(cmd); i++ { for i := 0; i < len(cmd); i++ {
if i == cur { if i == cur {
bar += m.cursorStyle().Render(string(cmd[i])) bar += m.Styles().CursorStyle(m.Mode()).Render(string(cmd[i]))
} else { } else {
bar += string(cmd[i]) bar += string(cmd[i])
} }
} }
// Cursor at end of command // Cursor at end of command
if cur >= len(cmd) { if cur >= len(cmd) {
bar += m.cursorStyle().Render(" ") bar += m.Styles().CursorStyle(m.Mode()).Render(" ")
} }
// bar = fmt.Sprintf("%s %d", bar, cur) // bar = fmt.Sprintf("%s %d", bar, cur)
} else if m.CommandError() != nil { } else if m.CommandError() != nil {
bar = m.commandErrorStyle().Render(m.CommandError().Error()) bar = m.Styles().CommandError.Render(m.CommandError().Error())
} else if strings.TrimSpace(m.CommandOutput()) != "" { } else if strings.TrimSpace(m.CommandOutput()) != "" {
bar = m.CommandOutput() bar = m.CommandOutput()
} else if strings.TrimSpace(m.Command()) != "" { } else if strings.TrimSpace(m.Command()) != "" {

View File

@ -14,11 +14,6 @@ const (
StateMotionCount StateMotionCount
) )
// PositionGetter is used to get cursor position for operator ranges
type PositionGetter interface {
GetCursorPosition() *action.Position
}
type Handler struct { type Handler struct {
state InputState state InputState
count1 int count1 int
@ -181,6 +176,7 @@ func (h *Handler) handleInitial(m action.Model, kind string, binding any, key st
func (h *Handler) handleAfterOperator(m action.Model, kind string, binding any, key string) tea.Cmd { func (h *Handler) handleAfterOperator(m action.Model, kind string, binding any, key string) tea.Cmd {
count := h.effectiveCount() count := h.effectiveCount()
win := m.ActiveWindow()
// dd, yy, cc - same operator key pressed twice // dd, yy, cc - same operator key pressed twice
if kind == "operator" && key == h.operatorKey { if kind == "operator" && key == h.operatorKey {
@ -201,11 +197,10 @@ func (h *Handler) handleAfterOperator(m action.Model, kind string, binding any,
mot = r.WithCount(count).(action.Motion) mot = r.WithCount(count).(action.Motion)
} }
// Get range and motion type // Get range and motion type
pg := m.(PositionGetter) start := win.Cursor
start := pg.GetCursorPosition()
mot.Execute(m) mot.Execute(m)
end := pg.GetCursorPosition() end := win.Cursor
cmd := h.operator.Operate(m, *start, *end, mot.Type()) cmd := h.operator.Operate(m, start, end, mot.Type())
h.Reset() h.Reset()
return cmd return cmd
} }
@ -302,8 +297,9 @@ func (h *Handler) handleCommandKey(m action.Model, key string) tea.Cmd {
} }
func normalizeVisualSelection(m action.Model) (action.Position, action.Position) { func normalizeVisualSelection(m action.Model) (action.Position, action.Position) {
a := action.Position{Line: m.AnchorY(), Col: m.AnchorX()} win := m.ActiveWindow()
c := action.Position{Line: m.CursorY(), Col: m.CursorX()} a := action.Position{Line: win.Anchor.Line, Col: win.Anchor.Col}
c := action.Position{Line: win.Cursor.Line, Col: win.Cursor.Col}
if a.Line < c.Line || (a.Line == c.Line && a.Col <= c.Col) { if a.Line < c.Line || (a.Line == c.Line && a.Col <= c.Col) {
return a, c return a, c
} }

View File

@ -1,8 +1,8 @@
package motion package motion
import ( import (
tea "github.com/charmbracelet/bubbletea"
"git.gophernest.net/azpect/TextEditor/internal/action" "git.gophernest.net/azpect/TextEditor/internal/action"
tea "github.com/charmbracelet/bubbletea"
) )
// MoveDown implements Motion (j) - linewise // MoveDown implements Motion (j) - linewise
@ -11,10 +11,11 @@ type MoveDown struct {
} }
func (a MoveDown) Execute(m action.Model) tea.Cmd { func (a MoveDown) Execute(m action.Model) tea.Cmd {
for i := 0; i < a.Count && m.CursorY() < m.LineCount()-1; i++ { win := m.ActiveWindow()
m.SetCursorY(m.CursorY() + 1) buf := m.ActiveBuffer()
for i := 0; i < a.Count && win.Cursor.Line < buf.LineCount()-1; i++ {
win.SetCursorLine(win.Cursor.Line + 1)
} }
m.ClampCursorX()
return nil return nil
} }
@ -30,10 +31,10 @@ type MoveUp struct {
} }
func (a MoveUp) Execute(m action.Model) tea.Cmd { func (a MoveUp) Execute(m action.Model) tea.Cmd {
for i := 0; i < a.Count && m.CursorY() > 0; i++ { win := m.ActiveWindow()
m.SetCursorY(m.CursorY() - 1) for i := 0; i < a.Count && win.Cursor.Line > 0; i++ {
win.SetCursorLine(win.Cursor.Line - 1)
} }
m.ClampCursorX()
return nil return nil
} }
@ -49,10 +50,10 @@ type MoveLeft struct {
} }
func (a MoveLeft) Execute(m action.Model) tea.Cmd { func (a MoveLeft) Execute(m action.Model) tea.Cmd {
for i := 0; i < a.Count && m.CursorX() > 0; i++ { win := m.ActiveWindow()
m.SetCursorX(m.CursorX() - 1) for i := 0; i < a.Count && win.Cursor.Col > 0; i++ {
win.SetCursorCol(win.Cursor.Col - 1)
} }
m.ClampCursorX()
return nil return nil
} }
@ -68,11 +69,12 @@ type MoveRight struct {
} }
func (a MoveRight) Execute(m action.Model) tea.Cmd { func (a MoveRight) Execute(m action.Model) tea.Cmd {
lineLen := len(m.Line(m.CursorY())) win := m.ActiveWindow()
for i := 0; i < a.Count && m.CursorX() <= lineLen; i++ { buf := m.ActiveBuffer()
m.SetCursorX(m.CursorX() + 1) lineLen := len(buf.Lines[win.Cursor.Line])
for i := 0; i < a.Count && win.Cursor.Col <= lineLen; i++ {
win.SetCursorCol(win.Cursor.Col + 1)
} }
m.ClampCursorX()
return nil return nil
} }

View File

@ -9,8 +9,8 @@ import (
type MoveToTop struct{} type MoveToTop struct{}
func (a MoveToTop) Execute(m action.Model) tea.Cmd { func (a MoveToTop) Execute(m action.Model) tea.Cmd {
m.SetCursorY(0) win := m.ActiveWindow()
m.ClampCursorX() win.SetCursorLine(0)
return nil return nil
} }
@ -20,8 +20,9 @@ func (a MoveToTop) Type() action.MotionType { return action.Linewise }
type MoveToBottom struct{} type MoveToBottom struct{}
func (a MoveToBottom) Execute(m action.Model) tea.Cmd { func (a MoveToBottom) Execute(m action.Model) tea.Cmd {
m.SetCursorY(m.LineCount() - 1) win := m.ActiveWindow()
m.ClampCursorX() buf := m.ActiveBuffer()
win.SetCursorLine(buf.LineCount() - 1)
return nil return nil
} }
@ -31,8 +32,8 @@ func (a MoveToBottom) Type() action.MotionType { return action.Linewise }
type MoveToLineStart struct{} type MoveToLineStart struct{}
func (a MoveToLineStart) Execute(m action.Model) tea.Cmd { func (a MoveToLineStart) Execute(m action.Model) tea.Cmd {
m.SetCursorX(0) win := m.ActiveWindow()
m.ClampCursorX() win.SetCursorCol(0)
return nil return nil
} }
@ -42,8 +43,9 @@ func (a MoveToLineStart) Type() action.MotionType { return action.CharwiseExclus
type MoveToLineEnd struct{} type MoveToLineEnd struct{}
func (a MoveToLineEnd) Execute(m action.Model) tea.Cmd { func (a MoveToLineEnd) Execute(m action.Model) tea.Cmd {
m.SetCursorX(len(m.Line(m.CursorY()))) win := m.ActiveWindow()
m.ClampCursorX() buf := m.ActiveBuffer()
win.SetCursorCol(len(buf.Lines[win.Cursor.Line]))
return nil return nil
} }
@ -53,7 +55,10 @@ func (a MoveToLineEnd) Type() action.MotionType { return action.CharwiseInclusiv
type MoveToLineContentStart struct{} type MoveToLineContentStart struct{}
func (a MoveToLineContentStart) Execute(m action.Model) tea.Cmd { func (a MoveToLineContentStart) Execute(m action.Model) tea.Cmd {
line := m.Line(m.CursorY()) win := m.ActiveWindow()
buf := m.ActiveBuffer()
line := buf.Lines[win.Cursor.Line]
x := 0 x := 0
for x < len(line) { for x < len(line) {
ch := line[x] ch := line[x]
@ -68,7 +73,7 @@ func (a MoveToLineContentStart) Execute(m action.Model) tea.Cmd {
x-- x--
} }
m.SetCursorX(x) win.SetCursorCol(x)
return nil return nil
} }
@ -80,11 +85,13 @@ type MoveToColumn struct {
} }
func (a MoveToColumn) Execute(m action.Model) tea.Cmd { func (a MoveToColumn) Execute(m action.Model) tea.Cmd {
line := m.Line(m.CursorY()) win := m.ActiveWindow()
buf := m.ActiveBuffer()
line := buf.Lines[win.Cursor.Line]
col := min(a.Count-1, len(line)-1) col := min(a.Count-1, len(line)-1)
m.SetCursorX(col) win.SetCursorCol(col)
m.ClampCursorX()
return nil return nil
} }
@ -100,22 +107,25 @@ func (a MoveToColumn) WithCount(n int) action.Action {
type ScrollDownHalfPage struct{} type ScrollDownHalfPage struct{}
func (a ScrollDownHalfPage) Execute(m action.Model) tea.Cmd { func (a ScrollDownHalfPage) Execute(m action.Model) tea.Cmd {
viewportHeight := m.ViewPortH() win := m.ActiveWindow()
buf := m.ActiveBuffer()
viewportHeight := win.Height - 2
if viewportHeight <= 0 { if viewportHeight <= 0 {
return nil return nil
} }
scroll := viewportHeight / 2 scroll := viewportHeight / 2
scrollOff := m.Settings().ScrollOff scrollOff := win.Options.ScrollOff
// Current relative position in viewport // Current relative position in viewport
relY := m.CursorY() - m.ScrollY() relY := win.Cursor.Line - win.ScrollY
// Scroll down, clamped to valid range // Scroll down, clamped to valid range
newScrollY := m.ScrollY() + scroll newScrollY := win.ScrollY + scroll
maxScroll := max(0, m.LineCount()-viewportHeight) maxScroll := max(0, buf.LineCount()-viewportHeight)
newScrollY = min(newScrollY, maxScroll) newScrollY = min(newScrollY, maxScroll)
m.SetScrollY(newScrollY) win.SetScrollY(newScrollY)
// Maintain relative position, respecting scrollOff // Maintain relative position, respecting scrollOff
if relY < scrollOff { if relY < scrollOff {
@ -126,9 +136,8 @@ func (a ScrollDownHalfPage) Execute(m action.Model) tea.Cmd {
} }
newCursorY := newScrollY + relY newCursorY := newScrollY + relY
newCursorY = max(0, min(newCursorY, m.LineCount()-1)) newCursorY = max(0, min(newCursorY, buf.LineCount()-1))
m.SetCursorY(newCursorY) win.SetCursorLine(newCursorY)
m.ClampCursorX()
return nil return nil
} }
@ -139,20 +148,23 @@ func (a ScrollDownHalfPage) Type() action.MotionType { return action.Linewise }
type ScrollUpHalfPage struct{} type ScrollUpHalfPage struct{}
func (a ScrollUpHalfPage) Execute(m action.Model) tea.Cmd { func (a ScrollUpHalfPage) Execute(m action.Model) tea.Cmd {
viewportHeight := m.ViewPortH() win := m.ActiveWindow()
buf := m.ActiveBuffer()
viewportHeight := win.Height - 2
if viewportHeight <= 0 { if viewportHeight <= 0 {
return nil return nil
} }
scroll := viewportHeight / 2 scroll := viewportHeight / 2
scrollOff := m.Settings().ScrollOff scrollOff := win.Options.ScrollOff
// Current relative position in viewport // Current relative position in viewport
relY := m.CursorY() - m.ScrollY() relY := win.Cursor.Line - win.ScrollY
// Scroll up, clamped to valid range // Scroll up, clamped to valid range
newScrollY := m.ScrollY() - scroll newScrollY := win.ScrollY - scroll
newScrollY = max(0, newScrollY) newScrollY = max(0, newScrollY)
m.SetScrollY(newScrollY) win.SetScrollY(newScrollY)
// Maintain relative position, respecting scrollOff // Maintain relative position, respecting scrollOff
if relY < scrollOff { if relY < scrollOff {
@ -163,9 +175,8 @@ func (a ScrollUpHalfPage) Execute(m action.Model) tea.Cmd {
} }
newCursorY := newScrollY + relY newCursorY := newScrollY + relY
newCursorY = max(0, min(newCursorY, m.LineCount()-1)) newCursorY = max(0, min(newCursorY, buf.LineCount()-1))
m.SetCursorY(newCursorY) win.SetCursorLine(newCursorY)
m.ClampCursorX()
return nil return nil
} }

View File

@ -16,8 +16,8 @@ func isWordPunctuation(c byte) bool {
return c != ' ' && c != '\t' && !isWordChar(c) return c != ' ' && c != '\t' && !isWordChar(c)
} }
func nextWordStart(m action.Model, x, y int) (int, int) { func nextWordStart(buf *action.Buffer, x, y int) (int, int) {
line := m.Line(y) line := buf.Lines[y]
// Skip current class // Skip current class
if x < len(line) { if x < len(line) {
@ -46,13 +46,13 @@ func nextWordStart(m action.Model, x, y int) (int, int) {
} }
// If next line is the end of the file, exit now // If next line is the end of the file, exit now
if y+1 >= m.LineCount() { if y+1 >= buf.LineCount() {
return x, y return x, y
} }
// Move to first char of next line // Move to first char of next line
y++ y++
line = m.Line(y) line = buf.Lines[y]
x = 0 x = 0
// If the first char of the new line is no whitespace, stay here! // If the first char of the new line is no whitespace, stay here!
@ -64,8 +64,8 @@ func nextWordStart(m action.Model, x, y int) (int, int) {
return x, y return x, y
} }
func nextWORDStart(m action.Model, x, y int) (int, int) { func nextWORDStart(buf *action.Buffer, x, y int) (int, int) {
line := m.Line(y) line := buf.Lines[y]
// Skip current WORD (all non-whitespace is one class for W) // Skip current WORD (all non-whitespace is one class for W)
for x < len(line) && line[x] != ' ' && line[x] != '\t' { for x < len(line) && line[x] != ' ' && line[x] != '\t' {
@ -85,13 +85,13 @@ func nextWORDStart(m action.Model, x, y int) (int, int) {
} }
// If next line is the end of the file, exit now // If next line is the end of the file, exit now
if y+1 >= m.LineCount() { if y+1 >= buf.LineCount() {
return x, y return x, y
} }
// Move to first char of next line // Move to first char of next line
y++ y++
line = m.Line(y) line = buf.Lines[y]
x = 0 x = 0
// If the first char of the new line is no whitespace, stay here! // If the first char of the new line is no whitespace, stay here!
@ -103,21 +103,21 @@ func nextWORDStart(m action.Model, x, y int) (int, int) {
return x, y return x, y
} }
func nextWordEnd(m action.Model, x, y int) (int, int) { func nextWordEnd(buf *action.Buffer, x, y int) (int, int) {
line := m.Line(y) line := buf.Lines[y]
// Advance once to avoid being stuck on the current end // Advance once to avoid being stuck on the current end
x++ x++
if x >= len(line) { if x >= len(line) {
// At last line of file, pin cursor to end of file // At last line of file, pin cursor to end of file
if y+1 >= m.LineCount() { if y+1 >= buf.LineCount() {
return len(line) - 1, y return len(line) - 1, y
} }
// Otherwise, move to next line // Otherwise, move to next line
y++ y++
x = 0 x = 0
line = m.Line(y) line = buf.Lines[y]
} }
// Skip whitespace and cross lines if needed // Skip whitespace and cross lines if needed
@ -133,13 +133,13 @@ func nextWordEnd(m action.Model, x, y int) (int, int) {
} }
// If next line is the end of the file, exit now // If next line is the end of the file, exit now
if y+1 >= m.LineCount() { if y+1 >= buf.LineCount() {
return x, y return x, y
} }
// Move to first char of next line // Move to first char of next line
y++ y++
line = m.Line(y) line = buf.Lines[y]
x = 0 x = 0
} }
@ -160,21 +160,21 @@ func nextWordEnd(m action.Model, x, y int) (int, int) {
return x, y return x, y
} }
func nextWORDEnd(m action.Model, x, y int) (int, int) { func nextWORDEnd(buf *action.Buffer, x, y int) (int, int) {
line := m.Line(y) line := buf.Lines[y]
// Advance once to avoid being stuck on the current end // Advance once to avoid being stuck on the current end
x++ x++
if x >= len(line) { if x >= len(line) {
// At last line of file, pin cursor to end of file // At last line of file, pin cursor to end of file
if y+1 >= m.LineCount() { if y+1 >= buf.LineCount() {
return len(line) - 1, y return len(line) - 1, y
} }
// Otherwise, move to next line // Otherwise, move to next line
y++ y++
x = 0 x = 0
line = m.Line(y) line = buf.Lines[y]
} }
// Skip whitespace and cross lines if needed // Skip whitespace and cross lines if needed
@ -190,13 +190,13 @@ func nextWORDEnd(m action.Model, x, y int) (int, int) {
} }
// If next line is the end of the file, exit now // If next line is the end of the file, exit now
if y+1 >= m.LineCount() { if y+1 >= buf.LineCount() {
return x, y return x, y
} }
// Move to first char of next line // Move to first char of next line
y++ y++
line = m.Line(y) line = buf.Lines[y]
x = 0 x = 0
} }
@ -208,8 +208,8 @@ func nextWORDEnd(m action.Model, x, y int) (int, int) {
return x, y return x, y
} }
func prevWordStart(m action.Model, x, y int) (int, int) { func prevWordStart(buf *action.Buffer, x, y int) (int, int) {
line := m.Line(y) line := buf.Lines[y]
// Back one to avoid being stuck on the current start // Back one to avoid being stuck on the current start
x-- x--
@ -218,7 +218,7 @@ func prevWordStart(m action.Model, x, y int) (int, int) {
return 0, 0 // beginning of file, stay put return 0, 0 // beginning of file, stay put
} }
y-- y--
line = m.Line(y) line = buf.Lines[y]
x = len(line) - 1 x = len(line) - 1
if x < 0 { if x < 0 {
return 0, y // landed on an empty line return 0, y // landed on an empty line
@ -237,7 +237,7 @@ func prevWordStart(m action.Model, x, y int) (int, int) {
return 0, 0 return 0, 0
} }
y-- y--
line = m.Line(y) line = buf.Lines[y]
x = len(line) - 1 x = len(line) - 1
if len(line) == 0 { if len(line) == 0 {
return 0, y // empty line acts as a word boundary return 0, y // empty line acts as a word boundary
@ -264,13 +264,16 @@ type MoveForwardWord struct {
} }
func (a MoveForwardWord) Execute(m action.Model) tea.Cmd { func (a MoveForwardWord) Execute(m action.Model) tea.Cmd {
x := m.CursorX() win := m.ActiveWindow()
y := m.CursorY() buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ { for i := 0; i < a.Count; i++ {
x, y = nextWordStart(m, x, y) x, y = nextWordStart(buf, x, y)
} }
m.SetCursorX(x) win.SetCursorCol(x)
m.SetCursorY(y) win.SetCursorLine(y)
return nil return nil
} }
@ -286,13 +289,16 @@ type MoveForwardWORD struct {
} }
func (a MoveForwardWORD) Execute(m action.Model) tea.Cmd { func (a MoveForwardWORD) Execute(m action.Model) tea.Cmd {
x := m.CursorX() win := m.ActiveWindow()
y := m.CursorY() buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ { for i := 0; i < a.Count; i++ {
x, y = nextWORDStart(m, x, y) x, y = nextWORDStart(buf, x, y)
} }
m.SetCursorX(x) win.SetCursorCol(x)
m.SetCursorY(y) win.SetCursorLine(y)
return nil return nil
} }
@ -308,13 +314,16 @@ type MoveForwardWordEnd struct {
} }
func (a MoveForwardWordEnd) Execute(m action.Model) tea.Cmd { func (a MoveForwardWordEnd) Execute(m action.Model) tea.Cmd {
x := m.CursorX() win := m.ActiveWindow()
y := m.CursorY() buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ { for i := 0; i < a.Count; i++ {
x, y = nextWordEnd(m, x, y) x, y = nextWordEnd(buf, x, y)
} }
m.SetCursorX(x) win.SetCursorCol(x)
m.SetCursorY(y) win.SetCursorLine(y)
return nil return nil
} }
@ -330,13 +339,16 @@ type MoveForwardWORDEnd struct {
} }
func (a MoveForwardWORDEnd) Execute(m action.Model) tea.Cmd { func (a MoveForwardWORDEnd) Execute(m action.Model) tea.Cmd {
x := m.CursorX() win := m.ActiveWindow()
y := m.CursorY() buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ { for i := 0; i < a.Count; i++ {
x, y = nextWORDEnd(m, x, y) x, y = nextWORDEnd(buf, x, y)
} }
m.SetCursorX(x) win.SetCursorCol(x)
m.SetCursorY(y) win.SetCursorLine(y)
return nil return nil
} }
@ -352,13 +364,16 @@ type MoveBackwardWord struct {
} }
func (a MoveBackwardWord) Execute(m action.Model) tea.Cmd { func (a MoveBackwardWord) Execute(m action.Model) tea.Cmd {
x := m.CursorX() win := m.ActiveWindow()
y := m.CursorY() buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ { for i := 0; i < a.Count; i++ {
x, y = prevWordStart(m, x, y) x, y = prevWordStart(buf, x, y)
} }
m.SetCursorX(x) win.SetCursorCol(x)
m.SetCursorY(y) win.SetCursorLine(y)
return nil return nil
} }

View File

@ -58,21 +58,24 @@ func changeNormalMode(m action.Model, start, end action.Position, mtype action.M
} }
func changeCharSelection(m action.Model, start, end action.Position) { func changeCharSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var deletedText string var deletedText string
if start.Line == end.Line { if start.Line == end.Line {
line := m.Line(start.Line) line := buf.Lines[start.Line]
endCol := min(end.Col+1, len(line)) endCol := min(end.Col+1, len(line))
deletedText = line[start.Col:endCol] deletedText = line[start.Col:endCol]
m.SetLine(start.Line, line[:start.Col]+line[endCol:]) buf.SetLine(start.Line, line[:start.Col]+line[endCol:])
} else { } else {
startLine := m.Line(start.Line) startLine := buf.Lines[start.Line]
endLine := m.Line(end.Line) endLine := buf.Lines[end.Line]
// Extract deleted text // Extract deleted text
deletedText = startLine[start.Col:] + "\n" deletedText = startLine[start.Col:] + "\n"
for y := start.Line + 1; y < end.Line; y++ { for y := start.Line + 1; y < end.Line; y++ {
deletedText += m.Line(y) + "\n" deletedText += buf.Lines[y] + "\n"
} }
endCol := min(end.Col+1, len(endLine)) endCol := min(end.Col+1, len(endLine))
deletedText += endLine[:endCol] deletedText += endLine[:endCol]
@ -85,14 +88,13 @@ func changeCharSelection(m action.Model, start, end action.Position) {
// Delete from end back to start to preserve indices // Delete from end back to start to preserve indices
for i := end.Line; i >= start.Line; i-- { for i := end.Line; i >= start.Line; i-- {
m.DeleteLine(i) buf.DeleteLine(i)
} }
m.InsertLine(start.Line, prefix+suffix) buf.InsertLine(start.Line, prefix+suffix)
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(start.Col) win.SetCursorCol(start.Col)
m.ClampCursorX()
m.SetMode(action.InsertMode) m.SetMode(action.InsertMode)
// Update register with deleted text // Update register with deleted text
@ -100,19 +102,22 @@ func changeCharSelection(m action.Model, start, end action.Position) {
} }
func changeLineSelection(m action.Model, start, end action.Position) { func changeLineSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var lines []string var lines []string
for i := end.Line; i >= start.Line; i-- { for i := end.Line; i >= start.Line; i-- {
lines = append([]string{m.Line(i)}, lines...) lines = append([]string{buf.Lines[i]}, lines...)
m.DeleteLine(i) buf.DeleteLine(i)
} }
// Insert an empty line for editing // Insert an empty line for editing
insertY := min(start.Line, m.LineCount()) insertY := min(start.Line, buf.LineCount())
m.InsertLine(insertY, "") buf.InsertLine(insertY, "")
m.SetCursorY(insertY) win.SetCursorLine(insertY)
m.SetCursorX(0) win.SetCursorCol(0)
m.SetMode(action.InsertMode) m.SetMode(action.InsertMode)
// Update registers // Update registers
@ -120,21 +125,23 @@ func changeLineSelection(m action.Model, start, end action.Position) {
} }
func changeBlockSelection(m action.Model, start, end action.Position) { func changeBlockSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
startCol := min(start.Col, end.Col) startCol := min(start.Col, end.Col)
endCol := max(start.Col, end.Col) endCol := max(start.Col, end.Col)
for y := start.Line; y <= end.Line; y++ { for y := start.Line; y <= end.Line; y++ {
line := m.Line(y) line := buf.Lines[y]
if startCol >= len(line) { if startCol >= len(line) {
continue continue
} }
ec := min(endCol+1, len(line)) ec := min(endCol+1, len(line))
m.SetLine(y, line[:startCol]+line[ec:]) buf.SetLine(y, line[:startCol]+line[ec:])
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(startCol) win.SetCursorCol(startCol)
m.ClampCursorX()
m.SetMode(action.InsertMode) m.SetMode(action.InsertMode)
} }
@ -143,17 +150,20 @@ var _ action.DoublePresser = ChangeOperator{}
// Double press handles cc - change the entire line // Double press handles cc - change the entire line
func (o ChangeOperator) DoublePress(m action.Model, count int) tea.Cmd { func (o ChangeOperator) DoublePress(m action.Model, count int) tea.Cmd {
startY := m.CursorY() win := m.ActiveWindow()
buf := m.ActiveBuffer()
startY := win.Cursor.Line
// If we have a higher value than lines remaining, we can only run so many times // If we have a higher value than lines remaining, we can only run so many times
opCount := min(count, m.LineCount()-startY) opCount := min(count, buf.LineCount()-startY)
var lines []string var lines []string
// Collect lines to delete (always delete at startY since lines shift up) // Collect lines to delete (always delete at startY since lines shift up)
for range opCount { for range opCount {
lines = append(lines, m.Line(startY)) lines = append(lines, buf.Lines[startY])
m.DeleteLine(startY) buf.DeleteLine(startY)
} }
// Put deleted lines in register // Put deleted lines in register
@ -161,12 +171,12 @@ func (o ChangeOperator) DoublePress(m action.Model, count int) tea.Cmd {
// Insert empty line at the original position for editing // Insert empty line at the original position for editing
// If we deleted everything, startY might be past end, so clamp it // If we deleted everything, startY might be past end, so clamp it
insertY := min(startY, m.LineCount()) insertY := min(startY, buf.LineCount())
m.InsertLine(insertY, "") buf.InsertLine(insertY, "")
// Position cursor on the new empty line // Position cursor on the new empty line
m.SetCursorY(insertY) win.SetCursorLine(insertY)
m.SetCursorX(0) win.SetCursorCol(0)
m.SetMode(action.InsertMode) m.SetMode(action.InsertMode)
return nil return nil

View File

@ -27,27 +27,29 @@ var _ action.DoublePresser = DeleteOperator{}
// Double press handles dd - delete the entire line // Double press handles dd - delete the entire line
func (o DeleteOperator) DoublePress(m action.Model, count int) tea.Cmd { func (o DeleteOperator) DoublePress(m action.Model, count int) tea.Cmd {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
// If we have a higher value than lines remaining, we can only run so many times // If we have a higher value than lines remaining, we can only run so many times
opCount := min(count, m.LineCount()-m.CursorY()) opCount := min(count, buf.LineCount()-win.Cursor.Line)
var lines []string var lines []string
for range opCount { for range opCount {
y := m.CursorY() y := win.Cursor.Line
lines = append(lines, m.Line(y)) lines = append(lines, buf.Lines[y])
m.DeleteLine(y) buf.DeleteLine(y)
if m.LineCount() == 0 { if buf.LineCount() == 0 {
m.InsertLine(0, "") buf.InsertLine(0, "")
} }
if y >= m.LineCount() { if y >= buf.LineCount() {
y = m.LineCount() - 1 y = buf.LineCount() - 1
} }
m.SetCursorY(y) win.SetCursorLine(y)
m.ClampCursorX()
} }
// Put her in the register! // Put her in the register!
@ -89,13 +91,16 @@ func deleteNormalMode(m action.Model, start, end action.Position, mtype action.M
} }
func deleteCharSelection(m action.Model, start, end action.Position) { func deleteCharSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
if start.Line == end.Line { if start.Line == end.Line {
line := m.Line(start.Line) line := buf.Lines[start.Line]
endCol := min(end.Col+1, len(line)) endCol := min(end.Col+1, len(line))
m.SetLine(start.Line, line[:start.Col]+line[endCol:]) buf.SetLine(start.Line, line[:start.Col]+line[endCol:])
} else { } else {
startLine := m.Line(start.Line) startLine := buf.Lines[start.Line]
endLine := m.Line(end.Line) endLine := buf.Lines[end.Line]
prefix := startLine[:start.Col] prefix := startLine[:start.Col]
suffix := "" suffix := ""
@ -105,54 +110,57 @@ func deleteCharSelection(m action.Model, start, end action.Position) {
// Delete from end back to start to preserve indices // Delete from end back to start to preserve indices
for i := end.Line; i >= start.Line; i-- { for i := end.Line; i >= start.Line; i-- {
m.DeleteLine(i) buf.DeleteLine(i)
} }
m.InsertLine(start.Line, prefix+suffix) buf.InsertLine(start.Line, prefix+suffix)
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(start.Col) win.SetCursorCol(start.Col)
m.ClampCursorX()
} }
func deleteLineSelection(m action.Model, start, end action.Position) { func deleteLineSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var lines []string var lines []string
for i := end.Line; i >= start.Line; i-- { for i := end.Line; i >= start.Line; i-- {
lines = append(lines, m.Line(i)) lines = append(lines, buf.Lines[i])
m.DeleteLine(i) buf.DeleteLine(i)
} }
if m.LineCount() == 0 { if buf.LineCount() == 0 {
m.InsertLine(0, "") buf.InsertLine(0, "")
} }
y := start.Line y := start.Line
if y >= m.LineCount() { if y >= buf.LineCount() {
y = m.LineCount() - 1 y = buf.LineCount() - 1
} }
m.SetCursorY(y) win.SetCursorLine(y)
m.ClampCursorX()
// Update registers // Update registers
m.UpdateDefaultRegister(action.LinewiseRegister, lines) m.UpdateDefaultRegister(action.LinewiseRegister, lines)
} }
func deleteBlockSelection(m action.Model, start, end action.Position) { func deleteBlockSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
startCol := min(start.Col, end.Col) startCol := min(start.Col, end.Col)
endCol := max(start.Col, end.Col) endCol := max(start.Col, end.Col)
for y := start.Line; y <= end.Line; y++ { for y := start.Line; y <= end.Line; y++ {
line := m.Line(y) line := buf.Lines[y]
if startCol >= len(line) { if startCol >= len(line) {
continue continue
} }
ec := min(endCol+1, len(line)) ec := min(endCol+1, len(line))
m.SetLine(y, line[:startCol]+line[ec:]) buf.SetLine(y, line[:startCol]+line[ec:])
} }
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
m.SetCursorX(startCol) win.SetCursorCol(startCol)
m.ClampCursorX()
} }

View File

@ -11,6 +11,8 @@ import (
type YankOperator struct{} type YankOperator struct{}
func (o YankOperator) Operate(m action.Model, start, end action.Position, mtype action.MotionType) tea.Cmd { func (o YankOperator) Operate(m action.Model, start, end action.Position, mtype action.MotionType) tea.Cmd {
win := m.ActiveWindow()
switch m.Mode() { switch m.Mode() {
case action.VisualMode: case action.VisualMode:
yankVisualMode(m, start, end) yankVisualMode(m, start, end)
@ -24,8 +26,8 @@ func (o YankOperator) Operate(m action.Model, start, end action.Position, mtype
m.SetCommandError(fmt.Errorf("'y' operator not yet implemented.")) m.SetCommandError(fmt.Errorf("'y' operator not yet implemented."))
} }
m.SetCursorX(start.Col) win.SetCursorCol(start.Col)
m.SetCursorY(start.Line) win.SetCursorLine(start.Line)
return nil return nil
} }
@ -33,15 +35,18 @@ func (o YankOperator) Operate(m action.Model, start, end action.Position, mtype
var _ action.DoublePresser = YankOperator{} var _ action.DoublePresser = YankOperator{}
func (o YankOperator) DoublePress(m action.Model, count int) tea.Cmd { func (o YankOperator) DoublePress(m action.Model, count int) tea.Cmd {
y := m.CursorY() win := m.ActiveWindow()
buf := m.ActiveBuffer()
y := win.Cursor.Line
// If we have a higher value than lines remaining, we can only run so many times // If we have a higher value than lines remaining, we can only run so many times
opCount := min(count, m.LineCount()-y) opCount := min(count, buf.LineCount()-y)
var lines []string var lines []string
for i := range opCount { for i := range opCount {
lines = append(lines, m.Line(y+i)) lines = append(lines, buf.Lines[y+i])
} }
// Put her in the register! // Put her in the register!
@ -51,6 +56,8 @@ func (o YankOperator) DoublePress(m action.Model, count int) tea.Cmd {
} }
func yankNormalMode(m action.Model, start, end action.Position, mtype action.MotionType) { func yankNormalMode(m action.Model, start, end action.Position, mtype action.MotionType) {
buf := m.ActiveBuffer()
switch { switch {
case mtype.IsCharwise(): case mtype.IsCharwise():
// This shouldn't happen // This shouldn't happen
@ -59,7 +66,7 @@ func yankNormalMode(m action.Model, start, end action.Position, mtype action.Mot
return return
} }
line := m.Line(start.Line) line := buf.Lines[start.Line]
startX := min(start.Col, end.Col) startX := min(start.Col, end.Col)
endX := max(start.Col, end.Col) endX := max(start.Col, end.Col)
@ -85,12 +92,14 @@ func yankNormalMode(m action.Model, start, end action.Position, mtype action.Mot
startY := min(start.Line, end.Line) startY := min(start.Line, end.Line)
endY := max(start.Line, end.Line) endY := max(start.Line, end.Line)
cnt := m.Lines()[startY : endY+1] cnt := buf.Lines[startY : endY+1]
m.UpdateDefaultRegister(action.LinewiseRegister, cnt) m.UpdateDefaultRegister(action.LinewiseRegister, cnt)
} }
} }
func yankVisualMode(m action.Model, start, end action.Position) { func yankVisualMode(m action.Model, start, end action.Position) {
buf := m.ActiveBuffer()
// Normalize so start is before end // Normalize so start is before end
if start.Line > end.Line || (start.Line == end.Line && start.Col > end.Col) { if start.Line > end.Line || (start.Line == end.Line && start.Col > end.Col) {
start, end = end, start start, end = end, start
@ -98,7 +107,7 @@ func yankVisualMode(m action.Model, start, end action.Position) {
// Single line selection // Single line selection
if start.Line == end.Line { if start.Line == end.Line {
line := m.Line(start.Line) line := buf.Lines[start.Line]
endCol := min(end.Col+1, len(line)) // +1 because visual selection is inclusive endCol := min(end.Col+1, len(line)) // +1 because visual selection is inclusive
startCol := min(start.Col, len(line)) startCol := min(start.Col, len(line))
cnt := line[startCol:endCol] cnt := line[startCol:endCol]
@ -110,17 +119,17 @@ func yankVisualMode(m action.Model, start, end action.Position) {
var content []string var content []string
// First line: from start.Col to end of line // First line: from start.Col to end of line
firstLine := m.Line(start.Line) firstLine := buf.Lines[start.Line]
startCol := min(start.Col, len(firstLine)) startCol := min(start.Col, len(firstLine))
content = append(content, firstLine[startCol:]) content = append(content, firstLine[startCol:])
// Middle lines: entire lines // Middle lines: entire lines
for y := start.Line + 1; y < end.Line; y++ { for y := start.Line + 1; y < end.Line; y++ {
content = append(content, m.Line(y)) content = append(content, buf.Lines[y])
} }
// Last line: from beginning to end.Col (inclusive) // Last line: from beginning to end.Col (inclusive)
lastLine := m.Line(end.Line) lastLine := buf.Lines[end.Line]
endCol := min(end.Col+1, len(lastLine)) endCol := min(end.Col+1, len(lastLine))
content = append(content, lastLine[:endCol]) content = append(content, lastLine[:endCol])
@ -128,6 +137,8 @@ func yankVisualMode(m action.Model, start, end action.Position) {
} }
func yankVisualLineMode(m action.Model, start, end action.Position) { func yankVisualLineMode(m action.Model, start, end action.Position) {
buf := m.ActiveBuffer()
// This shouldn't happen // This shouldn't happen
if start.Col != end.Col { if start.Col != end.Col {
m.SetCommandError(fmt.Errorf("Start column and end column must match for linewise yank operations.")) m.SetCommandError(fmt.Errorf("Start column and end column must match for linewise yank operations."))
@ -138,12 +149,14 @@ func yankVisualLineMode(m action.Model, start, end action.Position) {
startY := min(start.Line, end.Line) startY := min(start.Line, end.Line)
endY := max(start.Line, end.Line) endY := max(start.Line, end.Line)
cnt := m.Lines()[startY : endY+1] cnt := buf.Lines[startY : endY+1]
m.UpdateDefaultRegister(action.LinewiseRegister, cnt) m.UpdateDefaultRegister(action.LinewiseRegister, cnt)
} }
func yankVisualBlockMode(m action.Model, start, end action.Position) { func yankVisualBlockMode(m action.Model, start, end action.Position) {
buf := m.ActiveBuffer()
// Normalize so startY <= endY and startX <= endX // Normalize so startY <= endY and startX <= endX
startY := min(start.Line, end.Line) startY := min(start.Line, end.Line)
endY := max(start.Line, end.Line) endY := max(start.Line, end.Line)
@ -153,7 +166,7 @@ func yankVisualBlockMode(m action.Model, start, end action.Position) {
var content []string var content []string
for y := startY; y <= endY; y++ { for y := startY; y <= endY; y++ {
line := m.Line(y) line := buf.Lines[y]
// Handle lines shorter than the block selection // Handle lines shorter than the block selection
if startX >= len(line) { if startX >= len(line) {