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.
This commit is contained in:
Hayden Hargreaves 2026-02-26 23:18:18 -07:00
parent 9b1bf35a8e
commit b1b3edf810
32 changed files with 2469 additions and 2219 deletions

View File

@ -1,6 +1,8 @@
package main
import (
"fmt"
"git.gophernest.net/azpect/TextEditor/internal/action"
"git.gophernest.net/azpect/TextEditor/internal/editor"
tea "github.com/charmbracelet/bubbletea"
@ -20,16 +22,16 @@ func main() {
WithActiveWindowId(win.Id).
Build()
tea.NewProgram(model, tea.WithAltScreen()).Run()
m, _ := tea.NewProgram(model, tea.WithAltScreen()).Run()
// final, ok := m.(*editor.Model)
// if ok {
// fmt.Printf("PRINTING WINDOWS: %+v\n", final.Windows())
// fmt.Printf("PRINTING ACTIVE WINDOW: %+v\n", final.ActiveWindow())
// for _, win := range final.Windows() {
// fmt.Printf("\t%+v\n", *win.Buffer)
// }
// } else {
// fmt.Printf("PRINTING ALL: %+v\n", m)
// }
final, ok := m.(*editor.Model)
if ok {
fmt.Printf("PRINTING WINDOWS: %+v\n", final.Windows())
fmt.Printf("PRINTING ACTIVE WINDOW: %+v\n", final.ActiveWindow())
for _, win := range final.Windows() {
fmt.Printf("\t%+v\n", *win.Buffer)
}
} else {
fmt.Printf("PRINTING ALL: %+v\n", m)
}
}

View File

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

View File

@ -8,11 +8,14 @@ type DeleteChar struct {
}
func (a DeleteChar) Execute(m Model) tea.Cmd {
pos := m.CursorX()
line := m.Line(m.CursorY())
win := m.ActiveWindow()
buf := m.ActiveBuffer()
pos := win.Cursor.Col
line := buf.Lines[win.Cursor.Line]
for i := 0; i < a.Count && pos < len(line); i++ {
line = line[:pos] + line[pos+1:]
m.SetLine(m.CursorY(), line)
buf.SetLine(win.Cursor.Line, line)
}
return nil
@ -27,46 +30,47 @@ type DeleteToEndOfLine struct {
}
func (a DeleteToEndOfLine) Execute(m Model) tea.Cmd {
// Delete to end of line
pos := m.CursorX()
line := m.Line(m.CursorY())
win := m.ActiveWindow()
buf := m.ActiveBuffer()
m.SetLine(m.CursorY(), line[:pos])
m.SetCursorX(pos - 1)
// Delete to end of line
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
initY := m.CursorY()
initY := win.Cursor.Line
if a.Count > 1 {
// 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
m.SetCursorY(initY + 1)
win.SetCursorLine(initY + 1)
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
if y == initY {
break
}
m.DeleteLine(y)
buf.DeleteLine(y)
if m.LineCount() == 0 {
m.InsertLine(0, "")
if buf.LineCount() == 0 {
buf.InsertLine(0, "")
}
if y >= m.LineCount() {
y = m.LineCount() - 1
if y >= buf.LineCount() {
y = buf.LineCount() - 1
}
m.SetCursorY(y)
m.ClampCursorX()
win.SetCursorLine(y)
}
}
m.SetCursorY(initY)
m.ClampCursorX()
win.SetCursorLine(initY)
return nil
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,8 @@ import (
"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
func sendKeys(tm *teatest.TestModel, keys ...string) {
for _, key := range keys {
@ -94,12 +96,31 @@ func newTestModel(t *testing.T, opts ...TestModelOption) *teatest.TestModel {
opt(&cfg)
}
// Create model
m := NewModel(cfg.lines, cfg.pos)
buf := action.NewBufferBuilder().
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 {
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))

View File

@ -13,8 +13,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "ello" {
t.Errorf("lines[0] = %q, want 'ello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ello" {
t.Errorf("lines[0] = %q, want 'ello'", m.ActiveBuffer().Lines[0])
}
})
@ -24,8 +24,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0])
}
})
@ -35,8 +35,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "hell" {
t.Errorf("lines[0] = %q, want 'hell'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hell" {
t.Errorf("lines[0] = %q, want 'hell'", m.ActiveBuffer().Lines[0])
}
})
@ -46,8 +46,8 @@ func TestDeleteChar(t *testing.T) {
sendKeys(tm, "x", "x")
m := getFinalModel(t, tm)
if m.Line(0) != "llo" {
t.Errorf("lines[0] = %q, want 'llo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "llo" {
t.Errorf("lines[0] = %q, want 'llo'", m.ActiveBuffer().Lines[0])
}
})
}
@ -59,8 +59,8 @@ func TestDeleteCharWithCount(t *testing.T) {
sendKeys(tm, "3", "x")
m := getFinalModel(t, tm)
if m.Line(0) != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "lo" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -81,8 +81,8 @@ func TestDeleteCharWithCount(t *testing.T) {
sendKeys(tm, "2", "x")
m := getFinalModel(t, tm)
if m.Line(0) != "hlo" {
t.Errorf("lines[0] = %q, want 'hlo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hlo" {
t.Errorf("lines[0] = %q, want 'hlo'", m.ActiveBuffer().Lines[0])
}
})
}
@ -94,11 +94,11 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -108,8 +108,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -119,8 +119,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0])
}
})
@ -130,8 +130,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "ab c" {
t.Errorf("Line(0) = %q, want 'ab c'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ab c" {
t.Errorf("Line(0) = %q, want 'ab c'", m.ActiveBuffer().Lines[0])
}
})
@ -141,11 +141,11 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "world" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "lo" {
t.Errorf("Line(0) = %q, want 'lo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "lo" {
t.Errorf("Line(0) = %q, want 'lo'", m.ActiveBuffer().Lines[0])
}
})
@ -166,8 +166,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "ab" {
t.Errorf("Line(0) = %q, want 'ab'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ab" {
t.Errorf("Line(0) = %q, want 'ab'", m.ActiveBuffer().Lines[0])
}
})
@ -177,8 +177,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "5", "x")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -188,8 +188,8 @@ func TestDeleteCharEdgeCases(t *testing.T) {
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.Line(0) != "abde" {
t.Errorf("Line(0) = %q, want 'abde'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "abde" {
t.Errorf("Line(0) = %q, want 'abde'", m.ActiveBuffer().Lines[0])
}
})
}
@ -201,8 +201,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
})
@ -212,8 +212,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -223,8 +223,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.ActiveBuffer().Lines[0])
}
})
@ -235,8 +235,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
m := getFinalModel(t, tm)
// Cursor should move to last character of remaining text
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -246,8 +246,8 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -257,14 +257,14 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "2", "D")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %q, want '3'", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %q, want '3'", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "hi" {
t.Errorf("Line(1) = %q, want 'hi'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "hi" {
t.Errorf("Line(1) = %q, want 'hi'", m.ActiveBuffer().Lines[1])
}
})
@ -274,11 +274,11 @@ func TestDeleteToEndOfLine(t *testing.T) {
sendKeys(tm, "8", "D")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %q, want '1'", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %q, want '1'", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0])
}
})
}
@ -290,8 +290,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -301,11 +301,11 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
}
})
@ -315,11 +315,11 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.ActiveBuffer().Lines[0])
}
if m.Line(2) != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.ActiveBuffer().Lines[2])
}
})
@ -329,12 +329,12 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0])
}
// Cursor should clamp to last char
if m.CursorX() != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX())
if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
}
})
@ -344,8 +344,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -355,8 +355,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != " " {
t.Errorf("Line(0) = %q, want ' '", m.Line(0))
if m.ActiveBuffer().Lines[0] != " " {
t.Errorf("Line(0) = %q, want ' '", m.ActiveBuffer().Lines[0])
}
})
@ -366,8 +366,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
})
@ -377,8 +377,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0])
}
})
@ -388,8 +388,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(1) != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1])
}
})
@ -399,11 +399,11 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.Line(0) != "first" {
t.Errorf("Line(0) = %q, want 'first'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "first" {
t.Errorf("Line(0) = %q, want 'first'", m.ActiveBuffer().Lines[0])
}
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
})
@ -413,8 +413,8 @@ func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "Xhello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heXllo" {
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")
m := getFinalModel(t, tm)
if m.CursorX() != 2 {
t.Errorf("cursor.x = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hXello" {
t.Errorf("lines[0] = %q, want 'hXello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hXello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "helXlo" {
t.Errorf("lines[0] = %q, want 'helXlo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helXlo" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "Xhello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "Xhello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "helloX" {
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helloX" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "helloX" {
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helloX" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "new" {
t.Errorf("lines[1] = %q, want 'new'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "new" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.LineCount())
if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.ActiveBuffer().LineCount())
}
if m.Line(2) != "new" {
t.Errorf("lines[2] = %q, want 'new'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "new" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(2) != "new" {
t.Errorf("lines[2] = %q, want 'new'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "new" {
t.Errorf("lines[2] = %q, want 'new'", m.ActiveBuffer().Lines[2])
}
})
@ -186,11 +186,11 @@ func TestOpenLineBelow(t *testing.T) {
sendKeys(tm, "o", "esc")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("cursor.y = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("cursor.y = %d, want 1", m.ActiveWindow().Cursor.Line)
}
if m.CursorX() != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.LineCount())
if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.ActiveBuffer().LineCount())
}
for i := 1; i <= 3; i++ {
if m.Line(i) != "x" {
t.Errorf("lines[%d] = %q, want 'x'", i, m.Line(i))
if m.ActiveBuffer().Lines[i] != "x" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "ab" {
t.Errorf("lines[1] = %q, want 'ab'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "ab" {
t.Errorf("lines[1] = %q, want 'ab'", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "ab" {
t.Errorf("lines[2] = %q, want 'ab'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "ab" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "new" {
t.Errorf("lines[1] = %q, want 'new'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "new" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("len(lines) = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "new" {
t.Errorf("lines[0] = %q, want 'new'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "new" {
t.Errorf("lines[0] = %q, want 'new'", m.ActiveBuffer().Lines[0])
}
})
@ -265,8 +265,8 @@ func TestOpenLineAbove(t *testing.T) {
sendKeys(tm, "O", "esc")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.LineCount())
if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("len(lines) = %d, want 4", m.ActiveBuffer().LineCount())
}
for i := 0; i < 3; i++ {
if m.Line(i) != "x" {
t.Errorf("lines[%d] = %q, want 'x'", i, m.Line(i))
if m.ActiveBuffer().Lines[i] != "x" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != " world" {
t.Errorf("lines[1] = %q, want ' world'", m.Line(1))
if m.ActiveBuffer().Lines[1] != " world" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("lines[1] = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[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")
m := getFinalModel(t, tm)
if m.LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("len(lines) = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "hello" {
t.Errorf("lines[1] = %q, want 'hello'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "hello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helo" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helloworld" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "he" {
t.Errorf("lines[0] = %q, want 'he'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "he" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "word" {
t.Errorf("lines[0] = %q, want 'word'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "word" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helloworld" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("len(lines) = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "world" {
t.Errorf("lines[0] = %q, want 'world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "world" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "ho" {
t.Errorf("lines[0] = %q, want 'he'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ho" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heXllo" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heXllo" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "world" {
t.Errorf("lines[1] = %q, want 'world'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "world" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "woXrld" {
t.Errorf("lines[1] = %q, want 'woXrld'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "woXrld" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "Xhello" {
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "Xhello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "helloX" {
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helloX" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heXllo" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "heXllo" {
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heXllo" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hiX" {
t.Errorf("lines[0] = %q, want 'hiX'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hiX" {
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")
m := getFinalModel(t, tm)
if m.Line(1) != "hiX" {
t.Errorf("lines[1] = %q, want 'hiX'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "hiX" {
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")
m := getFinalModel(t, tm)
if m.Line(1) != "woXrld" {
t.Errorf("lines[1] = %q, want 'woXrld'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "woXrld" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello " {
t.Errorf("lines[0] = %q, want 'hello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("lines[0] = %q, want 'hello '", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 5 {
t.Errorf("CursorX() = %d, want '5'", m.CursorX())
if m.ActiveWindow().Cursor.Col != 5 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want '0'", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello wo" {
t.Errorf("lines[0] = %q, want 'hello wo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello wo" {
t.Errorf("lines[0] = %q, want 'hello wo'", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 7 {
t.Errorf("CursorX() = %d, want '7'", m.CursorX())
if m.ActiveWindow().Cursor.Col != 7 {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want '1'", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want '1'", m.ActiveBuffer().LineCount())
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want '0'", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want '0'", m.ActiveWindow().Cursor.Col)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want '0'", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want '1'", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want '1'", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %s, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %s, want ''", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want '0'", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want '0'", m.ActiveWindow().Cursor.Col)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want '0'", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("lines[0] = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "..." {
t.Errorf("lines[0] = %q, want '...'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "..." {
t.Errorf("lines[0] = %q, want '...'", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello\t" {
t.Errorf("lines[0] = %q, want 'hello\\t'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello\t" {
t.Errorf("lines[0] = %q, want 'hello\\t'", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 5 {
t.Errorf("CursorX() = %d, want 5", m.CursorX())
if m.ActiveWindow().Cursor.Col != 5 {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "helloworld" {
t.Errorf("lines[0] = %q, want 'helloworld'", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "" {
t.Errorf("lines[0] = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
}

View File

@ -12,8 +12,8 @@ func TestMoveDown(t *testing.T) {
sendKeys(tm, "j")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("cursor.y = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 4 {
t.Errorf("cursor.y = %d, want 4", m.CursorY())
if m.ActiveWindow().Cursor.Line != 4 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 5 {
t.Errorf("cursor.y = %d, want 5", m.CursorY())
if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("cursor.y = %d, want 5", m.ActiveWindow().Cursor.Line)
}
})
}
@ -44,8 +44,8 @@ func TestMoveDownWithCount(t *testing.T) {
sendKeys(tm, "3", "j")
m := getFinalModel(t, tm)
if m.CursorY() != 3 {
t.Errorf("cursor.y = %d, want 3", m.CursorY())
if m.ActiveWindow().Cursor.Line != 3 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 5 {
t.Errorf("cursor.y = %d, want 5", m.CursorY())
if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("cursor.y = %d, want 5", m.ActiveWindow().Cursor.Line)
}
})
}
@ -69,8 +69,8 @@ func TestMoveDownWithOverflow(t *testing.T) {
m := getFinalModel(t, tm)
want := len(lines[1])
if m.CursorX() != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != 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")
m := getFinalModel(t, tm)
if m.CursorX() != 3 {
t.Errorf("cursor.x = %d, want 3", m.CursorX())
if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("cursor.x = %d, want 3", m.ActiveWindow().Cursor.Col)
}
})
}
@ -91,8 +91,8 @@ func TestMoveUp(t *testing.T) {
sendKeys(tm, "k")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("cursor.y = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("cursor.y = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("cursor.y = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("cursor.y = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
}
@ -123,8 +123,8 @@ func TestMoveUpWithCount(t *testing.T) {
sendKeys(tm, "3", "k")
m := getFinalModel(t, tm)
if m.CursorY() != 2 {
t.Errorf("cursor.y = %d, want 2", m.CursorY())
if m.ActiveWindow().Cursor.Line != 2 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("cursor.y = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("cursor.y = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
}
@ -148,8 +148,8 @@ func TestMoveUpWithOverflow(t *testing.T) {
m := getFinalModel(t, tm)
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != 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")
m := getFinalModel(t, tm)
if m.CursorX() != 3 {
t.Errorf("cursor.x = %d, want 3", m.CursorX())
if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("cursor.x = %d, want 3", m.ActiveWindow().Cursor.Col)
}
})
}
@ -170,8 +170,8 @@ func TestMoveRight(t *testing.T) {
sendKeys(tm, "l")
m := getFinalModel(t, tm)
if m.CursorX() != 1 {
t.Errorf("cursor.x = %d, want 1", m.CursorX())
if m.ActiveWindow().Cursor.Col != 1 {
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")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("cursor.x = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("cursor.x = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -192,8 +192,8 @@ func TestMoveRight(t *testing.T) {
m := getFinalModel(t, tm)
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != 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")
m := getFinalModel(t, tm)
if m.CursorX() != 3 {
t.Errorf("cursor.x = %d, want 3", m.CursorX())
if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("cursor.x = %d, want 3", m.ActiveWindow().Cursor.Col)
}
})
@ -216,8 +216,8 @@ func TestMoveRightWithCount(t *testing.T) {
m := getFinalModel(t, tm)
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != 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")
m := getFinalModel(t, tm)
if m.CursorX() != 2 {
t.Errorf("cursor.x = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
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")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("cursor.x = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
}
@ -260,8 +260,8 @@ func TestMoveLeftWithCount(t *testing.T) {
sendKeys(tm, "3", "h")
m := getFinalModel(t, tm)
if m.CursorX() != 2 {
t.Errorf("cursor.x = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
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")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("cursor.x = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY())
if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
}
})
@ -24,8 +24,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G")
m := getFinalModel(t, tm)
if m.CursorY() != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY())
if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
}
})
@ -34,8 +34,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G")
m := getFinalModel(t, tm)
if m.CursorY() != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY())
if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
}
})
@ -45,12 +45,12 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
}
want := len(lines[1])
if m.CursorX() != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
}
})
@ -60,8 +60,8 @@ func TestMoveToBottom(t *testing.T) {
sendKeys(tm, "G")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
}
@ -72,8 +72,8 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -82,8 +82,8 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -92,8 +92,8 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -103,12 +103,12 @@ func TestMoveToTop(t *testing.T) {
sendKeys(tm, "g", "g")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
}
})
}
@ -121,8 +121,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -132,8 +132,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -142,8 +142,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -153,8 +153,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -163,8 +163,8 @@ func TestMoveToLineStart(t *testing.T) {
sendKeys(tm, "0")
m := getFinalModel(t, tm)
if m.CursorY() != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY())
if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
}
})
}
@ -177,8 +177,8 @@ func TestMoveToLineEnd(t *testing.T) {
m := getFinalModel(t, tm)
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != 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)
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != 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)
want := len(lines[0])
if m.CursorX() != want {
t.Errorf("CursorX() = %d, want %d", m.CursorX(), want)
if m.ActiveWindow().Cursor.Col != want {
t.Errorf("CursorX() = %d, want %d", m.ActiveWindow().Cursor.Col, want)
}
})
@ -212,8 +212,8 @@ func TestMoveToLineEnd(t *testing.T) {
sendKeys(tm, "$")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -222,8 +222,8 @@ func TestMoveToLineEnd(t *testing.T) {
sendKeys(tm, "$")
m := getFinalModel(t, tm)
if m.CursorY() != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY())
if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
}
})
}
@ -235,8 +235,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -246,8 +246,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -257,8 +257,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -268,8 +268,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -279,8 +279,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -290,8 +290,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -301,8 +301,8 @@ func TestMoveToLineContentStart(t *testing.T) {
sendKeys(tm, "_")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
}
@ -314,8 +314,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -325,8 +325,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -336,8 +336,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -347,8 +347,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -358,8 +358,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -369,8 +369,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -380,8 +380,8 @@ func TestMoveToLineContentStartAlias(t *testing.T) {
sendKeys(tm, "^")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
}
@ -400,8 +400,8 @@ func TestMoveToColumn(t *testing.T) {
m := getFinalModel(t, tm)
// | with no count = 1| = column 1 = index 0
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -411,8 +411,8 @@ func TestMoveToColumn(t *testing.T) {
sendKeys(tm, "1", "|")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -423,8 +423,8 @@ func TestMoveToColumn(t *testing.T) {
m := getFinalModel(t, tm)
// Column 5 = index 4 (the 'o' in hello)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -435,8 +435,8 @@ func TestMoveToColumn(t *testing.T) {
m := getFinalModel(t, tm)
// Column 10 = index 9 (the 'l' in world)
if m.CursorX() != 9 {
t.Errorf("CursorX() = %d, want 9", m.CursorX())
if m.ActiveWindow().Cursor.Col != 9 {
t.Errorf("CursorX() = %d, want 9", m.ActiveWindow().Cursor.Col)
}
})
@ -446,8 +446,8 @@ func TestMoveToColumn(t *testing.T) {
sendKeys(tm, "|")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -457,8 +457,8 @@ func TestMoveToColumn(t *testing.T) {
sendKeys(tm, "5", "|")
m := getFinalModel(t, tm)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
}
@ -471,8 +471,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm)
// Column 20 exceeds line length, should clamp to last char (index 4)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -483,8 +483,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm)
// Should clamp to last char (index 10)
if m.CursorX() != 10 {
t.Errorf("CursorX() = %d, want 10", m.CursorX())
if m.ActiveWindow().Cursor.Col != 10 {
t.Errorf("CursorX() = %d, want 10", m.ActiveWindow().Cursor.Col)
}
})
@ -495,8 +495,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm)
// Column 6 = index 5, but line only has 5 chars (max index 4)
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -506,8 +506,8 @@ func TestMoveToColumnClamp(t *testing.T) {
sendKeys(tm, "|")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -517,8 +517,8 @@ func TestMoveToColumnClamp(t *testing.T) {
sendKeys(tm, "5", "|")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -529,8 +529,8 @@ func TestMoveToColumnClamp(t *testing.T) {
m := getFinalModel(t, tm)
// Column 3 = index 2, but line only has 2 chars (max index 1)
if m.CursorX() != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX())
if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
}
})
}
@ -542,8 +542,8 @@ func TestMoveToColumnPreservesLine(t *testing.T) {
sendKeys(tm, "|")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
}
})
@ -553,8 +553,8 @@ func TestMoveToColumnPreservesLine(t *testing.T) {
sendKeys(tm, "5", "|")
m := getFinalModel(t, tm)
if m.CursorY() != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY())
if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
}
})
@ -564,11 +564,11 @@ func TestMoveToColumnPreservesLine(t *testing.T) {
sendKeys(tm, "|")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
}
@ -581,8 +581,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm)
// Column 5 = index 4 = 'h' in " hello"
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -593,8 +593,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm)
// Column 3 = index 2 = third space
if m.CursorX() != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
}
})
@ -605,8 +605,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm)
// | goes to column 1 = index 0 = the tab
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -617,8 +617,8 @@ func TestMoveToColumnWithWhitespace(t *testing.T) {
m := getFinalModel(t, tm)
// Column 2 = index 1 = 'h' in "\thello"
if m.CursorX() != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX())
if m.ActiveWindow().Cursor.Col != 1 {
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
// Result depends on inclusive/exclusive behavior
// In Vim: d| from col 5 deletes chars 0-4, leaving " world"
if m.Line(0) != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
}
})
@ -646,8 +646,8 @@ func TestMoveToColumnWithOperator(t *testing.T) {
m := getFinalModel(t, tm)
// Deletes from cursor (0) to column 5 (index 4), so "hell" deleted
// Result: "o world"
if m.Line(0) != "o world" {
t.Errorf("Line(0) = %q, want 'o world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "o world" {
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", "|")
m := getFinalModel(t, tm)
if m.AnchorX() != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
}
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -705,11 +705,11 @@ func TestMoveToColumnInVisualMode(t *testing.T) {
sendKeys(tm, "v", "|")
m := getFinalModel(t, tm)
if m.AnchorX() != 5 {
t.Errorf("AnchorX() = %d, want 5", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 5 {
t.Errorf("AnchorX() = %d, want 5", m.ActiveWindow().Anchor.Col)
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -720,8 +720,8 @@ func TestMoveToColumnInVisualMode(t *testing.T) {
m := getFinalModel(t, tm)
// Visual selection from 0 to 4 inclusive, delete "hello"
if m.Line(0) != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
// First line should be empty (ready for insert)
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "line three" {
t.Errorf("Line(2) = %q, want 'line three'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line three" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -123,11 +123,11 @@ func TestChangeLine(t *testing.T) {
m := getFinalModel(t, tm)
// Cursor should be at column 0 on the empty line
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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())
}
// Should have 3 lines: empty + line three + line four
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "line three" {
t.Errorf("Line(1) = %q, want 'line three'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "line three" {
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())
}
// Should have 3 lines: one + empty + five
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "one" {
t.Errorf("Line(0) = %q, want 'one'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "one" {
t.Errorf("Line(0) = %q, want 'one'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "five" {
t.Errorf("Line(2) = %q, want 'five'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "five" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "ello world" {
t.Errorf("Line(0) = %q, want 'ello world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ello world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "llo world" {
t.Errorf("Line(0) = %q, want 'llo world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "llo world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "hell world" {
t.Errorf("Line(0) = %q, want 'hell world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hell world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello " {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "world" {
t.Errorf("Line(0) = %q, want 'world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "world" {
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
// Delete positions 3-7 ("hello"), leaving " " + " world" = " world"
if m.Line(0) != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "world" {
t.Errorf("Line(0) = %q, want 'world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "heworld" {
t.Errorf("Line(0) = %q, want 'heworld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "heworld" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "world" {
t.Errorf("Line(0) = %q, want 'world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "three four" {
t.Errorf("Line(0) = %q, want 'three four'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "three four" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "next" {
t.Errorf("Line(0) = %q, want 'next'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "next" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != " next" {
t.Errorf("Line(0) = %q, want ' next'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " next" {
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())
}
// Should have empty line + line three
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "line three" {
t.Errorf("Line(1) = %q, want 'line three'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "line three" {
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())
}
// Should have empty line + line three
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "line three" {
t.Errorf("Line(1) = %q, want 'line three'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "line three" {
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())
}
// Should have empty + four + five
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "four" {
t.Errorf("Line(1) = %q, want 'four'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "four" {
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())
}
// All lines should be replaced with one empty line
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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())
}
// All lines should be replaced with one empty line
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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())
}
// Should have line one + empty
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello " {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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())
}
// Should delete last char
if m.Line(0) != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hell" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "ello" {
t.Errorf("Line(0) = %q, want 'ello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ello" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "llo" {
t.Errorf("Line(0) = %q, want 'llo'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "llo" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hell" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
})
@ -740,14 +740,14 @@ func TestSubstituteLine(t *testing.T) {
sendKeys(tm, "S")
m := getFinalModel(t, tm)
if m.Line(0) != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "line three" {
t.Errorf("Line(2) = %q, want 'line three'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line three" {
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())
}
// Should have empty + three + four
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[0] != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "three" {
t.Errorf("Line(1) = %q, want 'three'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "three" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "ello world" {
t.Errorf("Line(0) = %q, want 'ello world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ello world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " world" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello " {
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())
}
// Should merge lines with selection removed
if m.LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.LineCount())
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
})
@ -875,11 +875,11 @@ func TestVisualLineModeChange(t *testing.T) {
if m.Mode() != action.InsertMode {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[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())
}
// Should have: line one, empty, line four
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line one" {
t.Errorf("Line(0) = %q, want 'line one'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "" {
t.Errorf("Line(1) = %q, want ''", m.Line(1))
if m.ActiveBuffer().Lines[1] != "" {
t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "line four" {
t.Errorf("Line(2) = %q, want 'line four'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line four" {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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())
}
// cw on last word should change to end of line
if m.Line(0) != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello " {
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 {
t.Errorf("Mode() = %v, want InsertMode", m.Mode())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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
m := getFinalModel(t, tm)
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
})
@ -45,14 +45,14 @@ func TestScrollBasic(t *testing.T) {
}
m := getFinalModel(t, tm)
if m.CursorY() != 15 {
t.Errorf("CursorY() = %d, want 15", m.CursorY())
if m.ActiveWindow().Cursor.Line != 15 {
t.Errorf("CursorY() = %d, want 15", m.ActiveWindow().Cursor.Line)
}
// With scrollOff=8, viewport=19, cursor at 15 means:
// cursor should be at position 10 from top (19-1-8=10)
// so scrollY = 15 - 10 = 5
if m.ScrollY() < 1 {
t.Errorf("ScrollY() = %d, want > 0 (should have scrolled)", m.ScrollY())
if m.ActiveWindow().ScrollY < 1 {
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)
if m.CursorY() != 5 {
t.Errorf("CursorY() = %d, want 5", m.CursorY())
if m.ActiveWindow().Cursor.Line != 5 {
t.Errorf("CursorY() = %d, want 5", m.ActiveWindow().Cursor.Line)
}
// Cursor at line 5 with scrollOff=8 means scrollY should be 0
// (can't scroll negative, and cursor is within safe zone from top)
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
})
@ -84,13 +84,13 @@ func TestScrollBasic(t *testing.T) {
sendKeys(tm, "G")
m := getFinalModel(t, tm)
if m.CursorY() != 99 {
t.Errorf("CursorY() = %d, want 99", m.CursorY())
if m.ActiveWindow().Cursor.Line != 99 {
t.Errorf("CursorY() = %d, want 99", m.ActiveWindow().Cursor.Line)
}
// With 100 lines and viewport 18 (height - 2 for status + command bar),
// max scrollY = 100 - 18 = 82
if m.ScrollY() != 82 {
t.Errorf("ScrollY() = %d, want 82", m.ScrollY())
if m.ActiveWindow().ScrollY != 82 {
t.Errorf("ScrollY() = %d, want 82", m.ActiveWindow().ScrollY)
}
})
@ -100,11 +100,11 @@ func TestScrollBasic(t *testing.T) {
sendKeys(tm, "g", "g")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
})
}
@ -120,8 +120,8 @@ func TestScrollEdgeCases(t *testing.T) {
}
m := getFinalModel(t, tm)
if m.ScrollY() < 0 {
t.Errorf("ScrollY() = %d, want >= 0", m.ScrollY())
if m.ActiveWindow().ScrollY < 0 {
t.Errorf("ScrollY() = %d, want >= 0", m.ActiveWindow().ScrollY)
}
})
@ -133,8 +133,8 @@ func TestScrollEdgeCases(t *testing.T) {
m := getFinalModel(t, tm)
// 30 lines, viewport 18 (height - 2) -> maxScroll = 30 - 18 = 12
maxScroll := 30 - 18
if m.ScrollY() > maxScroll {
t.Errorf("ScrollY() = %d, want <= %d", m.ScrollY(), maxScroll)
if m.ActiveWindow().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)
// Cursor should still be visible
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)",
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")
m := getFinalModel(t, tm)
if m.ScrollY() != 14 {
t.Errorf("ScrollY() = %d, want 14", m.ScrollY())
if m.ActiveWindow().ScrollY != 14 {
t.Errorf("ScrollY() = %d, want 14", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 29 {
t.Errorf("CursorY() = %d, want 29", m.CursorY())
if m.ActiveWindow().Cursor.Line != 29 {
t.Errorf("CursorY() = %d, want 29", m.ActiveWindow().Cursor.Line)
}
})
@ -181,7 +181,7 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm)
relY := m.CursorY() - m.ScrollY()
relY := m.ActiveWindow().Cursor.Line - m.ActiveWindow().ScrollY
if relY != 15 {
t.Errorf("relative position = %d, want 15", relY)
}
@ -195,11 +195,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm)
if m.ScrollY() != 14 {
t.Errorf("ScrollY() = %d, want 14", m.ScrollY())
if m.ActiveWindow().ScrollY != 14 {
t.Errorf("ScrollY() = %d, want 14", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 22 {
t.Errorf("CursorY() = %d, want 22", m.CursorY())
if m.ActiveWindow().Cursor.Line != 22 {
t.Errorf("CursorY() = %d, want 22", m.ActiveWindow().Cursor.Line)
}
})
@ -213,11 +213,11 @@ func TestHalfPageScrollDown(t *testing.T) {
m := getFinalModel(t, tm)
maxScroll := 40 - 28
if m.ScrollY() > maxScroll {
t.Errorf("ScrollY() = %d, want <= %d", m.ScrollY(), maxScroll)
if m.ActiveWindow().ScrollY > maxScroll {
t.Errorf("ScrollY() = %d, want <= %d", m.ActiveWindow().ScrollY, maxScroll)
}
if m.CursorY() != 31 {
t.Errorf("CursorY() = %d, want 31", m.CursorY())
if m.ActiveWindow().Cursor.Line != 31 {
t.Errorf("CursorY() = %d, want 31", m.ActiveWindow().Cursor.Line)
}
})
@ -229,11 +229,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm)
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 8 {
t.Errorf("CursorY() = %d, want 8", m.CursorY())
if m.ActiveWindow().Cursor.Line != 8 {
t.Errorf("CursorY() = %d, want 8", m.ActiveWindow().Cursor.Line)
}
})
@ -253,11 +253,11 @@ func TestHalfPageScrollDown(t *testing.T) {
sendKeys(tm, "ctrl+d")
m := getFinalModel(t, tm)
if m.CursorY() != 22 {
t.Errorf("CursorY() = %d, want 22", m.CursorY())
if m.ActiveWindow().Cursor.Line != 22 {
t.Errorf("CursorY() = %d, want 22", m.ActiveWindow().Cursor.Line)
}
if m.CursorX() > len(m.Line(m.CursorY())) {
t.Errorf("CursorX() = %d exceeds line length %d", 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.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")
m := getFinalModel(t, tm)
if m.ScrollY() != 28 {
t.Errorf("ScrollY() = %d, want 28", m.ScrollY())
if m.ActiveWindow().ScrollY != 28 {
t.Errorf("ScrollY() = %d, want 28", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 43 {
t.Errorf("CursorY() = %d, want 43", m.CursorY())
if m.ActiveWindow().Cursor.Line != 43 {
t.Errorf("CursorY() = %d, want 43", m.ActiveWindow().Cursor.Line)
}
})
}
@ -288,11 +288,11 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm)
if m.ScrollY() != 17 {
t.Errorf("ScrollY() = %d, want 17", m.ScrollY())
if m.ActiveWindow().ScrollY != 17 {
t.Errorf("ScrollY() = %d, want 17", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 36 {
t.Errorf("CursorY() = %d, want 36", m.CursorY())
if m.ActiveWindow().Cursor.Line != 36 {
t.Errorf("CursorY() = %d, want 36", m.ActiveWindow().Cursor.Line)
}
})
@ -303,7 +303,7 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm)
relY := m.CursorY() - m.ScrollY()
relY := m.ActiveWindow().Cursor.Line - m.ActiveWindow().ScrollY
if relY != 19 {
t.Errorf("relative position = %d, want 19", relY)
}
@ -317,14 +317,14 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm)
if m.ScrollY() < 0 {
t.Errorf("ScrollY() = %d, want >= 0", m.ScrollY())
if m.ActiveWindow().ScrollY < 0 {
t.Errorf("ScrollY() = %d, want >= 0", m.ActiveWindow().ScrollY)
}
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 10 {
t.Errorf("CursorY() = %d, want 10", m.CursorY())
if m.ActiveWindow().Cursor.Line != 10 {
t.Errorf("CursorY() = %d, want 10", m.ActiveWindow().Cursor.Line)
}
})
@ -336,11 +336,11 @@ func TestHalfPageScrollUp(t *testing.T) {
sendKeys(tm, "ctrl+u")
m := getFinalModel(t, tm)
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 8 {
t.Errorf("CursorY() = %d, want 8", m.CursorY())
if m.ActiveWindow().Cursor.Line != 8 {
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")
m := getFinalModel(t, tm)
if m.ScrollY() != 33 {
t.Errorf("ScrollY() = %d, want 33", m.ScrollY())
if m.ActiveWindow().ScrollY != 33 {
t.Errorf("ScrollY() = %d, want 33", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 52 {
t.Errorf("CursorY() = %d, want 52", m.CursorY())
if m.ActiveWindow().Cursor.Line != 52 {
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")
m := getFinalModel(t, tm)
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 15 {
t.Errorf("CursorY() = %d, want 15", m.CursorY())
if m.ActiveWindow().Cursor.Line != 15 {
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")
m := getFinalModel(t, tm)
if m.ScrollY() != 31 {
t.Errorf("ScrollY() = %d, want 31", m.ScrollY())
if m.ActiveWindow().ScrollY != 31 {
t.Errorf("ScrollY() = %d, want 31", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 50 {
t.Errorf("CursorY() = %d, want 50", m.CursorY())
if m.ActiveWindow().Cursor.Line != 50 {
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")
m := getFinalModel(t, tm)
if m.ScrollY() != 0 {
t.Errorf("ScrollY() = %d, want 0 after 2 round trips", m.ScrollY())
if m.ActiveWindow().ScrollY != 0 {
t.Errorf("ScrollY() = %d, want 0 after 2 round trips", m.ActiveWindow().ScrollY)
}
if m.CursorY() != 15 {
t.Errorf("CursorY() = %d, want 15 after 2 round trips", m.CursorY())
if m.ActiveWindow().Cursor.Line != 15 {
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
m := getFinalModel(t, tm)
if m.CursorY() != 15 {
t.Errorf("CursorY() = %d, want 15", m.CursorY())
if m.ActiveWindow().Cursor.Line != 15 {
t.Errorf("CursorY() = %d, want 15", m.ActiveWindow().Cursor.Line)
}
// Should have scrolled since we moved past the safe zone
if m.ScrollY() == 0 {
t.Errorf("ScrollY() = %d, want > 0", m.ScrollY())
if m.ActiveWindow().ScrollY == 0 {
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
m := getFinalModel(t, tm)
if m.CursorY() != 10 {
t.Errorf("CursorY() = %d, want 10", m.CursorY())
if m.ActiveWindow().Cursor.Line != 10 {
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 {
t.Errorf("Mode() = %v, want VisualMode", m.Mode())
}
if m.AnchorX() != 3 {
t.Errorf("AnchorX() = %d, want 3", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 3 {
t.Errorf("AnchorX() = %d, want 3", m.ActiveWindow().Anchor.Col)
}
if m.AnchorY() != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
}
})
@ -34,11 +34,11 @@ func TestVisualModeSelectionState(t *testing.T) {
sendKeys(tm, "v", "l")
m := getFinalModel(t, tm)
if m.AnchorX() != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
}
if m.CursorX() != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX())
if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
}
})
@ -48,11 +48,11 @@ func TestVisualModeSelectionState(t *testing.T) {
sendKeys(tm, "v", "h")
m := getFinalModel(t, tm)
if m.AnchorX() != 3 {
t.Errorf("AnchorX() = %d, want 3", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 3 {
t.Errorf("AnchorX() = %d, want 3", m.ActiveWindow().Anchor.Col)
}
if m.CursorX() != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
}
})
@ -62,14 +62,14 @@ func TestVisualModeSelectionState(t *testing.T) {
sendKeys(tm, "v", "j")
m := getFinalModel(t, tm)
if m.AnchorX() != 2 {
t.Errorf("AnchorX() = %d, want 2", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 2 {
t.Errorf("AnchorX() = %d, want 2", m.ActiveWindow().Anchor.Col)
}
if m.AnchorY() != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
}
if m.CursorY() != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
}
})
@ -82,8 +82,8 @@ func TestVisualModeSelectionState(t *testing.T) {
if m.Mode() != action.VisualLineMode {
t.Errorf("Mode() = %v, want VisualLineMode", m.Mode())
}
if m.AnchorY() != 1 {
t.Errorf("AnchorY() = %d, want 1", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 1 {
t.Errorf("AnchorY() = %d, want 1", m.ActiveWindow().Anchor.Line)
}
})
@ -96,11 +96,11 @@ func TestVisualModeSelectionState(t *testing.T) {
if m.Mode() != action.VisualBlockMode {
t.Errorf("Mode() = %v, want VisualBlockMode", m.Mode())
}
if m.AnchorX() != 2 {
t.Errorf("AnchorX() = %d, want 2", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 2 {
t.Errorf("AnchorX() = %d, want 2", m.ActiveWindow().Anchor.Col)
}
if m.AnchorY() != 1 {
t.Errorf("AnchorY() = %d, want 1", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 1 {
t.Errorf("AnchorY() = %d, want 1", m.ActiveWindow().Anchor.Line)
}
})
@ -125,11 +125,11 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "v", "d")
m := getFinalModel(t, tm)
if m.Line(0) != "ello" {
t.Errorf("Line(0) = %q, want \"ello\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ello" {
t.Errorf("Line(0) = %q, want \"ello\"", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "o world" {
t.Errorf("Line(0) = %q, want \"o world\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "o world" {
t.Errorf("Line(0) = %q, want \"o world\"", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
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"
m := getFinalModel(t, tm)
if m.Line(0) != "ho" {
t.Errorf("Line(0) = %q, want \"ho\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ho" {
t.Errorf("Line(0) = %q, want \"ho\"", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 1 {
t.Errorf("CursorX() = %d, want 1", m.CursorX())
if m.ActiveWindow().Cursor.Col != 1 {
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"
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "held" {
t.Errorf("Line(0) = %q, want \"held\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "held" {
t.Errorf("Line(0) = %q, want \"held\"", m.ActiveBuffer().Lines[0])
}
if m.CursorX() != 2 {
t.Errorf("CursorX() = %d, want 2", m.CursorX())
if m.ActiveWindow().Cursor.Col != 2 {
t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -189,14 +189,14 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "V", "d")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "world" {
t.Errorf("Line(0) = %q, want \"world\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "world" {
t.Errorf("Line(0) = %q, want \"world\"", m.ActiveBuffer().Lines[0])
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -206,14 +206,14 @@ func TestVisualModeDelete(t *testing.T) {
sendKeys(tm, "V", "j", "d")
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "testing" {
t.Errorf("Line(0) = %q, want \"testing\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "testing" {
t.Errorf("Line(0) = %q, want \"testing\"", m.ActiveBuffer().Lines[0])
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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
m := getFinalModel(t, tm)
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "hello" {
t.Errorf("Line(0) = %q, want \"hello\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello" {
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"
// "world"[:0]+"world"[2:] = "rld"
m := getFinalModel(t, tm)
if m.Line(0) != "llo" {
t.Errorf("Line(0) = %q, want \"llo\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "llo" {
t.Errorf("Line(0) = %q, want \"llo\"", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "rld" {
t.Errorf("Line(1) = %q, want \"rld\"", m.Line(1))
if m.ActiveBuffer().Lines[1] != "rld" {
t.Errorf("Line(1) = %q, want \"rld\"", m.ActiveBuffer().Lines[1])
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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"
// "world"[:1]+"world"[4:] = "w"+"d" = "wd"
m := getFinalModel(t, tm)
if m.Line(0) != "ho" {
t.Errorf("Line(0) = %q, want \"ho\"", m.Line(0))
if m.ActiveBuffer().Lines[0] != "ho" {
t.Errorf("Line(0) = %q, want \"ho\"", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "wd" {
t.Errorf("Line(1) = %q, want \"wd\"", m.Line(1))
if m.ActiveBuffer().Lines[1] != "wd" {
t.Errorf("Line(1) = %q, want \"wd\"", m.ActiveBuffer().Lines[1])
}
})
}
@ -284,12 +284,12 @@ func TestVisualModeWordMotions(t *testing.T) {
sendKeys(tm, "v", "w")
m := getFinalModel(t, tm)
if m.AnchorX() != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
}
// w moves to start of "world" at col 6
if m.CursorX() != 6 {
t.Errorf("CursorX() = %d, want 6", m.CursorX())
if m.ActiveWindow().Cursor.Col != 6 {
t.Errorf("CursorX() = %d, want 6", m.ActiveWindow().Cursor.Col)
}
})
@ -302,8 +302,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm)
// Deletes from 0 to 6 inclusive = "hello w", leaves "orld"
if m.Line(0) != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.ActiveBuffer().Lines[0])
}
})
@ -315,12 +315,12 @@ func TestVisualModeWordMotions(t *testing.T) {
sendKeys(tm, "v", "e")
m := getFinalModel(t, tm)
if m.AnchorX() != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
}
// e moves to end of "hello" at col 4
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -333,8 +333,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm)
// Deletes "hello"
if m.Line(0) != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != " world" {
t.Errorf("Line(0) = %q, want ' world'", m.ActiveBuffer().Lines[0])
}
})
@ -346,12 +346,12 @@ func TestVisualModeWordMotions(t *testing.T) {
sendKeys(tm, "v", "b")
m := getFinalModel(t, tm)
if m.AnchorX() != 6 {
t.Errorf("AnchorX() = %d, want 6", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 6 {
t.Errorf("AnchorX() = %d, want 6", m.ActiveWindow().Anchor.Col)
}
// b moves to start of "hello" at col 0
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -364,8 +364,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm)
// Deletes from "h" (0) to "w" (6) inclusive
if m.Line(0) != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.ActiveBuffer().Lines[0])
}
})
@ -378,8 +378,8 @@ func TestVisualModeWordMotions(t *testing.T) {
m := getFinalModel(t, tm)
// 2w moves past "one " and "two " to start of "three" at col 8
if m.CursorX() != 8 {
t.Errorf("CursorX() = %d, want 8", m.CursorX())
if m.ActiveWindow().Cursor.Col != 8 {
t.Errorf("CursorX() = %d, want 8", m.ActiveWindow().Cursor.Col)
}
})
}
@ -395,12 +395,12 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "$")
m := getFinalModel(t, tm)
if m.AnchorX() != 0 {
t.Errorf("AnchorX() = %d, want 0", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 0 {
t.Errorf("AnchorX() = %d, want 0", m.ActiveWindow().Anchor.Col)
}
// $ moves past end of line
if m.CursorX() != 11 {
t.Errorf("CursorX() = %d, want 11", m.CursorX())
if m.ActiveWindow().Cursor.Col != 11 {
t.Errorf("CursorX() = %d, want 11", m.ActiveWindow().Cursor.Col)
}
})
@ -412,8 +412,8 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "$", "d")
m := getFinalModel(t, tm)
if m.Line(0) != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello " {
t.Errorf("Line(0) = %q, want 'hello '", m.ActiveBuffer().Lines[0])
}
})
@ -425,11 +425,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "0")
m := getFinalModel(t, tm)
if m.AnchorX() != 6 {
t.Errorf("AnchorX() = %d, want 6", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 6 {
t.Errorf("AnchorX() = %d, want 6", m.ActiveWindow().Anchor.Col)
}
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -442,8 +442,8 @@ func TestVisualModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm)
// Deletes from 'h' (0) to 'w' (6) inclusive
if m.Line(0) != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "orld" {
t.Errorf("Line(0) = %q, want 'orld'", m.ActiveBuffer().Lines[0])
}
})
@ -455,12 +455,12 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "_")
m := getFinalModel(t, tm)
if m.AnchorX() != 10 {
t.Errorf("AnchorX() = %d, want 10", m.AnchorX())
if m.ActiveWindow().Anchor.Col != 10 {
t.Errorf("AnchorX() = %d, want 10", m.ActiveWindow().Anchor.Col)
}
// _ moves to first non-ws at col 4
if m.CursorX() != 4 {
t.Errorf("CursorX() = %d, want 4", m.CursorX())
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
@ -472,11 +472,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
sendKeys(tm, "v", "G")
m := getFinalModel(t, tm)
if m.AnchorY() != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
}
if m.CursorY() != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY())
if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
}
})
@ -490,11 +490,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm)
// 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"
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "lin 3" {
t.Errorf("Line(0) = %q, want 'lin 3'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "lin 3" {
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")
m := getFinalModel(t, tm)
if m.AnchorY() != 2 {
t.Errorf("AnchorY() = %d, want 2", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 2 {
t.Errorf("AnchorY() = %d, want 2", m.ActiveWindow().Anchor.Line)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -524,11 +524,11 @@ func TestVisualModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm)
// gg goes to first line at same col, deletes selection
// Keeps "lin" from first line + " 3" from last line = "lin 3"
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "lin 3" {
t.Errorf("Line(0) = %q, want 'lin 3'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "lin 3" {
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")
m := getFinalModel(t, tm)
if m.AnchorY() != 0 {
t.Errorf("AnchorY() = %d, want 0", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 0 {
t.Errorf("AnchorY() = %d, want 0", m.ActiveWindow().Anchor.Line)
}
if m.CursorY() != 2 {
t.Errorf("CursorY() = %d, want 2", m.CursorY())
if m.ActiveWindow().Cursor.Line != 2 {
t.Errorf("CursorY() = %d, want 2", m.ActiveWindow().Cursor.Line)
}
})
@ -561,11 +561,11 @@ func TestVisualLineModeJumpMotions(t *testing.T) {
m := getFinalModel(t, tm)
// All lines deleted, should have empty buffer
if m.LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.LineCount())
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %d, want 1", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "" {
t.Errorf("Line(0) = %q, want ''", m.Line(0))
if m.ActiveBuffer().Lines[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")
m := getFinalModel(t, tm)
if m.AnchorY() != 2 {
t.Errorf("AnchorY() = %d, want 2", m.AnchorY())
if m.ActiveWindow().Anchor.Line != 2 {
t.Errorf("AnchorY() = %d, want 2", m.ActiveWindow().Anchor.Line)
}
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "line 2" {
t.Errorf("Line(1) = %q, want 'line 2'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "line 2" {
t.Errorf("Line(1) = %q, want 'line 2'", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line 3" {
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")
m := getFinalModel(t, tm)
if m.CursorY() != 1 {
t.Errorf("CursorY() = %d, want 1", m.CursorY())
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
}
if m.CursorX() != 3 {
t.Errorf("CursorX() = %d, want 3", m.CursorX())
if m.ActiveWindow().Cursor.Col != 3 {
t.Errorf("CursorX() = %d, want 3", m.ActiveWindow().Cursor.Col)
}
})
@ -174,8 +174,8 @@ func TestYankLineWithCount(t *testing.T) {
sendKeys(tm, "3", "y", "y")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
})
}
@ -376,8 +376,8 @@ func TestYankWithLinewiseMotions(t *testing.T) {
sendKeys(tm, "y", "j")
m := getFinalModel(t, tm)
if m.CursorY() != 0 {
t.Errorf("CursorY() = %d, want 0", m.CursorY())
if m.ActiveWindow().Cursor.Line != 0 {
t.Errorf("CursorY() = %d, want 0", m.ActiveWindow().Cursor.Line)
}
})
@ -389,8 +389,8 @@ func TestYankWithLinewiseMotions(t *testing.T) {
sendKeys(tm, "y", "G")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
})
}
@ -570,8 +570,8 @@ func TestYankWithCharwiseMotions(t *testing.T) {
sendKeys(tm, "y", "w")
m := getFinalModel(t, tm)
if m.CursorX() != 0 {
t.Errorf("CursorX() = %d, want 0", m.CursorX())
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
@ -583,8 +583,8 @@ func TestYankWithCharwiseMotions(t *testing.T) {
sendKeys(tm, "y", "w")
m := getFinalModel(t, tm)
if m.Line(0) != "hello world" {
t.Errorf("Line(0) = %q, want 'hello world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello world" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello world" {
t.Errorf("Line(0) = %q, want 'hello world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello world" {
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
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(1) != "to copy" {
t.Errorf("Line(1) = %q, want 'to copy'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "to copy" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello worldhello" {
t.Errorf("Line(0) = %q, want 'hello worldhello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello worldhello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "worldhello world" {
t.Errorf("Line(0) = %q, want 'worldhello world'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "worldhello world" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 4 {
t.Errorf("LineCount() = %d, want 4", m.LineCount())
if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("LineCount() = %d, want 4", m.ActiveBuffer().LineCount())
}
if m.Line(2) != "line 1" {
t.Errorf("Line(2) = %q, want 'line 1'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line 1" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 6 {
t.Errorf("LineCount() = %d, want 6", m.LineCount())
if m.ActiveBuffer().LineCount() != 6 {
t.Errorf("LineCount() = %d, want 6", m.ActiveBuffer().LineCount())
}
if m.Line(4) != "line 1" {
t.Errorf("Line(4) = %q, want 'line 1'", m.Line(4))
if m.ActiveBuffer().Lines[4] != "line 1" {
t.Errorf("Line(4) = %q, want 'line 1'", m.ActiveBuffer().Lines[4])
}
if m.Line(5) != "line 2" {
t.Errorf("Line(5) = %q, want 'line 2'", m.Line(5))
if m.ActiveBuffer().Lines[5] != "line 2" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 4 {
t.Errorf("LineCount() = %d, want 4", m.LineCount())
if m.ActiveBuffer().LineCount() != 4 {
t.Errorf("LineCount() = %d, want 4", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "line 3" {
t.Errorf("Line(0) = %q, want 'line 3'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line 3" {
t.Errorf("Line(0) = %q, want 'line 3'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "original" {
t.Errorf("Line(0) = %q, want 'original'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "original" {
t.Errorf("Line(0) = %q, want 'original'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "original" {
t.Errorf("Line(1) = %q, want 'original'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "original" {
t.Errorf("Line(1) = %q, want 'original'", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "other" {
t.Errorf("Line(2) = %q, want 'other'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "other" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "original" {
t.Errorf("Line(0) = %q, want 'original'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "original" {
t.Errorf("Line(0) = %q, want 'original'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "other" {
t.Errorf("Line(1) = %q, want 'other'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "other" {
t.Errorf("Line(1) = %q, want 'other'", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "other" {
t.Errorf("Line(2) = %q, want 'other'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "other" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello worldhello " {
t.Errorf("Line(0) = %q, want 'hello worldhello '", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello worldhello " {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "hello worldhello" {
t.Errorf("Line(0) = %q, want 'hello worldhello'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "hello worldhello" {
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")
m := getFinalModel(t, tm)
if m.Line(0) != "abcdefghcde" {
t.Errorf("Line(0) = %q, want 'abcdefghcde'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "abcdefghcde" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.LineCount())
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
if m.Line(0) != "line 2" {
t.Errorf("Line(0) = %q, want 'line 2'", m.Line(0))
if m.ActiveBuffer().Lines[0] != "line 2" {
t.Errorf("Line(0) = %q, want 'line 2'", m.ActiveBuffer().Lines[0])
}
if m.Line(1) != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line 3" {
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")
m := getFinalModel(t, tm)
if m.LineCount() != 7 {
t.Errorf("LineCount() = %d, want 7", m.LineCount())
if m.ActiveBuffer().LineCount() != 7 {
t.Errorf("LineCount() = %d, want 7", m.ActiveBuffer().LineCount())
}
// Original + 2 copies of 2 lines = 3 + 4 = 7
if m.Line(1) != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.Line(1))
if m.ActiveBuffer().Lines[1] != "line 1" {
t.Errorf("Line(1) = %q, want 'line 1'", m.ActiveBuffer().Lines[1])
}
if m.Line(2) != "line 2" {
t.Errorf("Line(2) = %q, want 'line 2'", m.Line(2))
if m.ActiveBuffer().Lines[2] != "line 2" {
t.Errorf("Line(2) = %q, want 'line 2'", m.ActiveBuffer().Lines[2])
}
if m.Line(3) != "line 1" {
t.Errorf("Line(3) = %q, want 'line 1'", m.Line(3))
if m.ActiveBuffer().Lines[3] != "line 1" {
t.Errorf("Line(3) = %q, want 'line 1'", m.ActiveBuffer().Lines[3])
}
if m.Line(4) != "line 2" {
t.Errorf("Line(4) = %q, want 'line 2'", m.Line(4))
if m.ActiveBuffer().Lines[4] != "line 2" {
t.Errorf("Line(4) = %q, want 'line 2'", m.ActiveBuffer().Lines[4])
}
})
}

View File

@ -44,6 +44,9 @@ type Model struct {
// Registers
registers map[rune]action.Register // name -> register
// Visual styles
styles Styles
}
// Model.Init: Initialize the model and start any commands that may need to run. Required
@ -285,6 +288,16 @@ func (m *Model) SetSettings(s action.Settings) {
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
// ==================================================

View File

@ -28,6 +28,7 @@ func NewModelBuilder() *ModelBuilder {
commandOutput: "",
settings: action.NewDefaultSettings(),
registers: action.DefaultRegisters(),
styles: DefaultStyles(),
},
}
}
@ -126,6 +127,12 @@ func (mb *ModelBuilder) WithCommandOutput(output string) *ModelBuilder {
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"
)
func (m Model) cursorStyle() lipgloss.Style {
switch m.mode {
case action.NormalMode,
action.VisualMode,
action.VisualBlockMode,
action.VisualLineMode:
// Block cursor for normal mode
return lipgloss.NewStyle().Reverse(true)
// Styles holds all the visual styling for the editor.
// Passed to Window.View() so windows can render themselves.
type Styles struct {
// Cursor styles by mode
CursorNormal lipgloss.Style
CursorInsert lipgloss.Style
CursorCommand lipgloss.Style
// 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:
// Bar/underline for insert mode
return lipgloss.NewStyle().Underline(true)
return s.CursorInsert
case action.CommandMode:
return lipgloss.NewStyle().Reverse(true)
return s.CursorCommand
default:
return lipgloss.NewStyle().Reverse(true)
return s.CursorNormal
}
}
// DEBUGGING STYLE
func (m Model) visualAnchorStyle() lipgloss.Style {
bg := lipgloss.Color("#a89020")
return lipgloss.NewStyle().Background(bg)
}
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)
}
// ==================================================
// Deprecated
// ==================================================
// func (m Model) cursorStyle() lipgloss.Style {
// switch m.mode {
// case action.NormalMode,
// action.VisualMode,
// action.VisualBlockMode,
// action.VisualLineMode:
// // Block cursor for normal mode
// return lipgloss.NewStyle().Reverse(true)
// case action.InsertMode:
// // Bar/underline for insert mode
// return lipgloss.NewStyle().Underline(true)
// case action.CommandMode:
// return lipgloss.NewStyle().Reverse(true)
// default:
// return lipgloss.NewStyle().Reverse(true)
// }
// }
//
// // DEBUGGING STYLE
// func (m Model) visualAnchorStyle() lipgloss.Style {
// bg := lipgloss.Color("#a89020")
// return lipgloss.NewStyle().Background(bg)
// }
//
// 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
m.AdjustScroll()
win := m.ActiveWindow()
win.AdjustScroll()
return m, cmd
}

View File

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

View File

@ -14,11 +14,6 @@ const (
StateMotionCount
)
// PositionGetter is used to get cursor position for operator ranges
type PositionGetter interface {
GetCursorPosition() *action.Position
}
type Handler struct {
state InputState
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 {
count := h.effectiveCount()
win := m.ActiveWindow()
// dd, yy, cc - same operator key pressed twice
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)
}
// Get range and motion type
pg := m.(PositionGetter)
start := pg.GetCursorPosition()
start := win.Cursor
mot.Execute(m)
end := pg.GetCursorPosition()
cmd := h.operator.Operate(m, *start, *end, mot.Type())
end := win.Cursor
cmd := h.operator.Operate(m, start, end, mot.Type())
h.Reset()
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) {
a := action.Position{Line: m.AnchorY(), Col: m.AnchorX()}
c := action.Position{Line: m.CursorY(), Col: m.CursorX()}
win := m.ActiveWindow()
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) {
return a, c
}

View File

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

View File

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

View File

@ -16,8 +16,8 @@ func isWordPunctuation(c byte) bool {
return c != ' ' && c != '\t' && !isWordChar(c)
}
func nextWordStart(m action.Model, x, y int) (int, int) {
line := m.Line(y)
func nextWordStart(buf *action.Buffer, x, y int) (int, int) {
line := buf.Lines[y]
// Skip current class
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 y+1 >= m.LineCount() {
if y+1 >= buf.LineCount() {
return x, y
}
// Move to first char of next line
y++
line = m.Line(y)
line = buf.Lines[y]
x = 0
// 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
}
func nextWORDStart(m action.Model, x, y int) (int, int) {
line := m.Line(y)
func nextWORDStart(buf *action.Buffer, x, y int) (int, int) {
line := buf.Lines[y]
// Skip current WORD (all non-whitespace is one class for W)
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 y+1 >= m.LineCount() {
if y+1 >= buf.LineCount() {
return x, y
}
// Move to first char of next line
y++
line = m.Line(y)
line = buf.Lines[y]
x = 0
// 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
}
func nextWordEnd(m action.Model, x, y int) (int, int) {
line := m.Line(y)
func nextWordEnd(buf *action.Buffer, x, y int) (int, int) {
line := buf.Lines[y]
// Advance once to avoid being stuck on the current end
x++
if x >= len(line) {
// 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
}
// Otherwise, move to next line
y++
x = 0
line = m.Line(y)
line = buf.Lines[y]
}
// 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 y+1 >= m.LineCount() {
if y+1 >= buf.LineCount() {
return x, y
}
// Move to first char of next line
y++
line = m.Line(y)
line = buf.Lines[y]
x = 0
}
@ -160,21 +160,21 @@ func nextWordEnd(m action.Model, x, y int) (int, int) {
return x, y
}
func nextWORDEnd(m action.Model, x, y int) (int, int) {
line := m.Line(y)
func nextWORDEnd(buf *action.Buffer, x, y int) (int, int) {
line := buf.Lines[y]
// Advance once to avoid being stuck on the current end
x++
if x >= len(line) {
// 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
}
// Otherwise, move to next line
y++
x = 0
line = m.Line(y)
line = buf.Lines[y]
}
// 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 y+1 >= m.LineCount() {
if y+1 >= buf.LineCount() {
return x, y
}
// Move to first char of next line
y++
line = m.Line(y)
line = buf.Lines[y]
x = 0
}
@ -208,8 +208,8 @@ func nextWORDEnd(m action.Model, x, y int) (int, int) {
return x, y
}
func prevWordStart(m action.Model, x, y int) (int, int) {
line := m.Line(y)
func prevWordStart(buf *action.Buffer, x, y int) (int, int) {
line := buf.Lines[y]
// Back one to avoid being stuck on the current start
x--
@ -218,7 +218,7 @@ func prevWordStart(m action.Model, x, y int) (int, int) {
return 0, 0 // beginning of file, stay put
}
y--
line = m.Line(y)
line = buf.Lines[y]
x = len(line) - 1
if x < 0 {
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
}
y--
line = m.Line(y)
line = buf.Lines[y]
x = len(line) - 1
if len(line) == 0 {
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 {
x := m.CursorX()
y := m.CursorY()
win := m.ActiveWindow()
buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ {
x, y = nextWordStart(m, x, y)
x, y = nextWordStart(buf, x, y)
}
m.SetCursorX(x)
m.SetCursorY(y)
win.SetCursorCol(x)
win.SetCursorLine(y)
return nil
}
@ -286,13 +289,16 @@ type MoveForwardWORD struct {
}
func (a MoveForwardWORD) Execute(m action.Model) tea.Cmd {
x := m.CursorX()
y := m.CursorY()
win := m.ActiveWindow()
buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ {
x, y = nextWORDStart(m, x, y)
x, y = nextWORDStart(buf, x, y)
}
m.SetCursorX(x)
m.SetCursorY(y)
win.SetCursorCol(x)
win.SetCursorLine(y)
return nil
}
@ -308,13 +314,16 @@ type MoveForwardWordEnd struct {
}
func (a MoveForwardWordEnd) Execute(m action.Model) tea.Cmd {
x := m.CursorX()
y := m.CursorY()
win := m.ActiveWindow()
buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ {
x, y = nextWordEnd(m, x, y)
x, y = nextWordEnd(buf, x, y)
}
m.SetCursorX(x)
m.SetCursorY(y)
win.SetCursorCol(x)
win.SetCursorLine(y)
return nil
}
@ -330,13 +339,16 @@ type MoveForwardWORDEnd struct {
}
func (a MoveForwardWORDEnd) Execute(m action.Model) tea.Cmd {
x := m.CursorX()
y := m.CursorY()
win := m.ActiveWindow()
buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ {
x, y = nextWORDEnd(m, x, y)
x, y = nextWORDEnd(buf, x, y)
}
m.SetCursorX(x)
m.SetCursorY(y)
win.SetCursorCol(x)
win.SetCursorLine(y)
return nil
}
@ -352,13 +364,16 @@ type MoveBackwardWord struct {
}
func (a MoveBackwardWord) Execute(m action.Model) tea.Cmd {
x := m.CursorX()
y := m.CursorY()
win := m.ActiveWindow()
buf := m.ActiveBuffer()
x := win.Cursor.Col
y := win.Cursor.Line
for i := 0; i < a.Count; i++ {
x, y = prevWordStart(m, x, y)
x, y = prevWordStart(buf, x, y)
}
m.SetCursorX(x)
m.SetCursorY(y)
win.SetCursorCol(x)
win.SetCursorLine(y)
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) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var deletedText string
if start.Line == end.Line {
line := m.Line(start.Line)
line := buf.Lines[start.Line]
endCol := min(end.Col+1, len(line))
deletedText = line[start.Col:endCol]
m.SetLine(start.Line, line[:start.Col]+line[endCol:])
buf.SetLine(start.Line, line[:start.Col]+line[endCol:])
} else {
startLine := m.Line(start.Line)
endLine := m.Line(end.Line)
startLine := buf.Lines[start.Line]
endLine := buf.Lines[end.Line]
// Extract deleted text
deletedText = startLine[start.Col:] + "\n"
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))
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
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)
m.SetCursorX(start.Col)
m.ClampCursorX()
win.SetCursorLine(start.Line)
win.SetCursorCol(start.Col)
m.SetMode(action.InsertMode)
// 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) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var lines []string
for i := end.Line; i >= start.Line; i-- {
lines = append([]string{m.Line(i)}, lines...)
m.DeleteLine(i)
lines = append([]string{buf.Lines[i]}, lines...)
buf.DeleteLine(i)
}
// Insert an empty line for editing
insertY := min(start.Line, m.LineCount())
m.InsertLine(insertY, "")
insertY := min(start.Line, buf.LineCount())
buf.InsertLine(insertY, "")
m.SetCursorY(insertY)
m.SetCursorX(0)
win.SetCursorLine(insertY)
win.SetCursorCol(0)
m.SetMode(action.InsertMode)
// Update registers
@ -120,21 +125,23 @@ func changeLineSelection(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)
endCol := max(start.Col, end.Col)
for y := start.Line; y <= end.Line; y++ {
line := m.Line(y)
line := buf.Lines[y]
if startCol >= len(line) {
continue
}
ec := min(endCol+1, len(line))
m.SetLine(y, line[:startCol]+line[ec:])
buf.SetLine(y, line[:startCol]+line[ec:])
}
m.SetCursorY(start.Line)
m.SetCursorX(startCol)
m.ClampCursorX()
win.SetCursorLine(start.Line)
win.SetCursorCol(startCol)
m.SetMode(action.InsertMode)
}
@ -143,17 +150,20 @@ var _ action.DoublePresser = ChangeOperator{}
// Double press handles cc - change the entire line
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
opCount := min(count, m.LineCount()-startY)
opCount := min(count, buf.LineCount()-startY)
var lines []string
// Collect lines to delete (always delete at startY since lines shift up)
for range opCount {
lines = append(lines, m.Line(startY))
m.DeleteLine(startY)
lines = append(lines, buf.Lines[startY])
buf.DeleteLine(startY)
}
// 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
// If we deleted everything, startY might be past end, so clamp it
insertY := min(startY, m.LineCount())
m.InsertLine(insertY, "")
insertY := min(startY, buf.LineCount())
buf.InsertLine(insertY, "")
// Position cursor on the new empty line
m.SetCursorY(insertY)
m.SetCursorX(0)
win.SetCursorLine(insertY)
win.SetCursorCol(0)
m.SetMode(action.InsertMode)
return nil

View File

@ -27,27 +27,29 @@ var _ action.DoublePresser = DeleteOperator{}
// Double press handles dd - delete the entire line
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
opCount := min(count, m.LineCount()-m.CursorY())
opCount := min(count, buf.LineCount()-win.Cursor.Line)
var lines []string
for range opCount {
y := m.CursorY()
lines = append(lines, m.Line(y))
y := win.Cursor.Line
lines = append(lines, buf.Lines[y])
m.DeleteLine(y)
buf.DeleteLine(y)
if m.LineCount() == 0 {
m.InsertLine(0, "")
if buf.LineCount() == 0 {
buf.InsertLine(0, "")
}
if y >= m.LineCount() {
y = m.LineCount() - 1
if y >= buf.LineCount() {
y = buf.LineCount() - 1
}
m.SetCursorY(y)
m.ClampCursorX()
win.SetCursorLine(y)
}
// 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) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
if start.Line == end.Line {
line := m.Line(start.Line)
line := buf.Lines[start.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 {
startLine := m.Line(start.Line)
endLine := m.Line(end.Line)
startLine := buf.Lines[start.Line]
endLine := buf.Lines[end.Line]
prefix := startLine[:start.Col]
suffix := ""
@ -105,54 +110,57 @@ func deleteCharSelection(m action.Model, start, end action.Position) {
// Delete from end back to start to preserve indices
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)
m.SetCursorX(start.Col)
m.ClampCursorX()
win.SetCursorLine(start.Line)
win.SetCursorCol(start.Col)
}
func deleteLineSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
var lines []string
for i := end.Line; i >= start.Line; i-- {
lines = append(lines, m.Line(i))
m.DeleteLine(i)
lines = append(lines, buf.Lines[i])
buf.DeleteLine(i)
}
if m.LineCount() == 0 {
m.InsertLine(0, "")
if buf.LineCount() == 0 {
buf.InsertLine(0, "")
}
y := start.Line
if y >= m.LineCount() {
y = m.LineCount() - 1
if y >= buf.LineCount() {
y = buf.LineCount() - 1
}
m.SetCursorY(y)
m.ClampCursorX()
win.SetCursorLine(y)
// Update registers
m.UpdateDefaultRegister(action.LinewiseRegister, lines)
}
func deleteBlockSelection(m action.Model, start, end action.Position) {
win := m.ActiveWindow()
buf := m.ActiveBuffer()
startCol := min(start.Col, end.Col)
endCol := max(start.Col, end.Col)
for y := start.Line; y <= end.Line; y++ {
line := m.Line(y)
line := buf.Lines[y]
if startCol >= len(line) {
continue
}
ec := min(endCol+1, len(line))
m.SetLine(y, line[:startCol]+line[ec:])
buf.SetLine(y, line[:startCol]+line[ec:])
}
m.SetCursorY(start.Line)
m.SetCursorX(startCol)
m.ClampCursorX()
win.SetCursorLine(start.Line)
win.SetCursorCol(startCol)
}

View File

@ -11,6 +11,8 @@ import (
type YankOperator struct{}
func (o YankOperator) Operate(m action.Model, start, end action.Position, mtype action.MotionType) tea.Cmd {
win := m.ActiveWindow()
switch m.Mode() {
case action.VisualMode:
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.SetCursorX(start.Col)
m.SetCursorY(start.Line)
win.SetCursorCol(start.Col)
win.SetCursorLine(start.Line)
return nil
}
@ -33,15 +35,18 @@ func (o YankOperator) Operate(m action.Model, start, end action.Position, mtype
var _ action.DoublePresser = YankOperator{}
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
opCount := min(count, m.LineCount()-y)
opCount := min(count, buf.LineCount()-y)
var lines []string
for i := range opCount {
lines = append(lines, m.Line(y+i))
lines = append(lines, buf.Lines[y+i])
}
// 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) {
buf := m.ActiveBuffer()
switch {
case mtype.IsCharwise():
// This shouldn't happen
@ -59,7 +66,7 @@ func yankNormalMode(m action.Model, start, end action.Position, mtype action.Mot
return
}
line := m.Line(start.Line)
line := buf.Lines[start.Line]
startX := min(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)
endY := max(start.Line, end.Line)
cnt := m.Lines()[startY : endY+1]
cnt := buf.Lines[startY : endY+1]
m.UpdateDefaultRegister(action.LinewiseRegister, cnt)
}
}
func yankVisualMode(m action.Model, start, end action.Position) {
buf := m.ActiveBuffer()
// Normalize so start is before end
if start.Line > end.Line || (start.Line == end.Line && start.Col > end.Col) {
start, end = end, start
@ -98,7 +107,7 @@ func yankVisualMode(m action.Model, start, end action.Position) {
// Single line selection
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
startCol := min(start.Col, len(line))
cnt := line[startCol:endCol]
@ -110,17 +119,17 @@ func yankVisualMode(m action.Model, start, end action.Position) {
var content []string
// 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))
content = append(content, firstLine[startCol:])
// Middle lines: entire lines
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)
lastLine := m.Line(end.Line)
lastLine := buf.Lines[end.Line]
endCol := min(end.Col+1, len(lastLine))
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) {
buf := m.ActiveBuffer()
// This shouldn't happen
if start.Col != end.Col {
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)
endY := max(start.Line, end.Line)
cnt := m.Lines()[startY : endY+1]
cnt := buf.Lines[startY : endY+1]
m.UpdateDefaultRegister(action.LinewiseRegister, cnt)
}
func yankVisualBlockMode(m action.Model, start, end action.Position) {
buf := m.ActiveBuffer()
// Normalize so startY <= endY and startX <= endX
startY := min(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
for y := startY; y <= endY; y++ {
line := m.Line(y)
line := buf.Lines[y]
// Handle lines shorter than the block selection
if startX >= len(line) {