wip: first initial commit. Not sure if I like this
This commit is contained in:
parent
65f96a5089
commit
3339dd4409
@ -8,17 +8,21 @@ import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func generateLines(n int) []string {
|
||||
lines := make([]string, n)
|
||||
for i := range n {
|
||||
lines[i] = fmt.Sprintf("line %d", i+1)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func main() {
|
||||
tea.NewProgram(
|
||||
editor.NewModel(generateLines(64), action.Position{Line: 0, Col: 0}),
|
||||
m, _ := tea.NewProgram(
|
||||
editor.NewModel([]string{""}, action.Position{Line: 0, Col: 0}),
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
80
internal/action/buffer.go
Normal file
80
internal/action/buffer.go
Normal file
@ -0,0 +1,80 @@
|
||||
package action
|
||||
|
||||
type BufferOptions struct {
|
||||
// tabstop expandtab
|
||||
}
|
||||
|
||||
type Buffer struct {
|
||||
// Buffer data
|
||||
Id int
|
||||
|
||||
// File data
|
||||
Filename string
|
||||
Filetype string
|
||||
Lines []string
|
||||
|
||||
// Flags (not used yet)
|
||||
Modified bool
|
||||
Loaded bool
|
||||
Listed bool
|
||||
|
||||
// Options BufferOptions
|
||||
// UndoTree TODO: This will be big
|
||||
}
|
||||
|
||||
// Not great, but maybe the best way
|
||||
var CurrentBufferId int = 1
|
||||
|
||||
func NewEmptyBuffer(lines []string) *Buffer {
|
||||
buf := Buffer{
|
||||
Id: CurrentBufferId,
|
||||
Filename: "",
|
||||
Filetype: "",
|
||||
Lines: lines,
|
||||
Modified: false,
|
||||
Loaded: true,
|
||||
Listed: true,
|
||||
}
|
||||
|
||||
CurrentBufferId++
|
||||
|
||||
return &buf
|
||||
}
|
||||
|
||||
// Get the line at an index
|
||||
func (b *Buffer) Line(idx int) string {
|
||||
if idx < 0 || idx >= len(b.Lines) {
|
||||
return ""
|
||||
}
|
||||
return b.Lines[idx]
|
||||
}
|
||||
|
||||
// Set the content at an index.
|
||||
func (b *Buffer) SetLine(idx int, content string) {
|
||||
if idx >= 0 && idx < len(b.Lines) {
|
||||
b.Lines[idx] = content
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a line with content at an index
|
||||
func (b *Buffer) InsertLine(idx int, content string) {
|
||||
if idx < 0 {
|
||||
idx = 0
|
||||
}
|
||||
if idx > len(b.Lines) {
|
||||
idx = len(b.Lines)
|
||||
}
|
||||
b.Lines = append(b.Lines[:idx], append([]string{content}, b.Lines[idx:]...)...)
|
||||
}
|
||||
|
||||
// Delete a line at an index
|
||||
func (b *Buffer) DeleteLine(idx int) {
|
||||
if idx >= 0 && idx < len(b.Lines) {
|
||||
b.Lines = append(b.Lines[:idx], b.Lines[idx+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the number of lines in the buffer
|
||||
func (b *Buffer) LineCount() int {
|
||||
return len(b.Lines)
|
||||
}
|
||||
@ -21,6 +21,11 @@ type Model interface {
|
||||
SetCursorY(y int)
|
||||
ClampCursorX()
|
||||
|
||||
// Windows
|
||||
Windows() []*Window
|
||||
ActiveWindowId() int
|
||||
ActiveWindow() *Window
|
||||
|
||||
// Window
|
||||
ScrollY() int
|
||||
SetScrollY(y int)
|
||||
|
||||
56
internal/action/window.go
Normal file
56
internal/action/window.go
Normal file
@ -0,0 +1,56 @@
|
||||
package action
|
||||
|
||||
// TODO: No more global settings, window-wide settings
|
||||
type WinOptions struct {
|
||||
// Number bool
|
||||
// Wrap bool
|
||||
// Relnumber bool
|
||||
}
|
||||
|
||||
type Window struct {
|
||||
Id int
|
||||
Number int // Ignored for now, will be used when splits come into play
|
||||
Buffer *Buffer
|
||||
|
||||
Cursor Position
|
||||
Anchor Position
|
||||
|
||||
ScrollY int
|
||||
Width int
|
||||
Height int
|
||||
// Folds // TODO
|
||||
// Options WinOptions
|
||||
}
|
||||
|
||||
// Not great, but maybe the best way
|
||||
var CurrentWindowId int = 1000
|
||||
|
||||
func NewEmptyWindow(lines []string, w, h int) *Window {
|
||||
win := &Window{
|
||||
Id: CurrentWindowId,
|
||||
Number: 1, // Ignored for now
|
||||
|
||||
Buffer: NewEmptyBuffer(lines),
|
||||
|
||||
Cursor: Position{Line: 0, Col: 0},
|
||||
Anchor: Position{Line: 0, Col: 0},
|
||||
|
||||
ScrollY: 0,
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
|
||||
// Increment
|
||||
CurrentWindowId++
|
||||
|
||||
return win
|
||||
}
|
||||
|
||||
func (w *Window) ClampCursorX() {
|
||||
lineLen := len(w.Buffer.Lines[w.Cursor.Line])
|
||||
if lineLen == 0 {
|
||||
w.Cursor.Col = 0
|
||||
} else if w.Cursor.Col >= lineLen {
|
||||
w.Cursor.Col = lineLen
|
||||
}
|
||||
}
|
||||
BIN
internal/editor/gim
Executable file
BIN
internal/editor/gim
Executable file
Binary file not shown.
@ -19,8 +19,8 @@ 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))
|
||||
if len(m.Lines()) != 2 {
|
||||
t.Errorf("expected 2 lines, got %d", len(m.Lines()))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -123,8 +123,8 @@ func newTestModelWithTermSize(t *testing.T, lines []string, pos action.Position,
|
||||
}
|
||||
|
||||
// getFinalModel extracts the final model state (sends ctrl+c to quit first)
|
||||
func getFinalModel(t *testing.T, tm *teatest.TestModel) Model {
|
||||
func getFinalModel(t *testing.T, tm *teatest.TestModel) *Model {
|
||||
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlC})
|
||||
fm := tm.FinalModel(t, teatest.WithFinalTimeout(time.Second))
|
||||
return fm.(Model)
|
||||
return fm.(*Model)
|
||||
}
|
||||
|
||||
@ -13,8 +13,8 @@ func TestDeleteChar(t *testing.T) {
|
||||
sendKeys(tm, "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "ello" {
|
||||
t.Errorf("lines[0] = %q, want 'ello'", m.lines[0])
|
||||
if m.Line(0) != "ello" {
|
||||
t.Errorf("lines[0] = %q, want 'ello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -24,8 +24,8 @@ func TestDeleteChar(t *testing.T) {
|
||||
sendKeys(tm, "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "helo" {
|
||||
t.Errorf("lines[0] = %q, want 'helo'", m.lines[0])
|
||||
if m.Line(0) != "helo" {
|
||||
t.Errorf("lines[0] = %q, want 'helo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -35,8 +35,8 @@ func TestDeleteChar(t *testing.T) {
|
||||
sendKeys(tm, "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hell" {
|
||||
t.Errorf("lines[0] = %q, want 'hell'", m.lines[0])
|
||||
if m.Line(0) != "hell" {
|
||||
t.Errorf("lines[0] = %q, want 'hell'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -46,8 +46,8 @@ func TestDeleteChar(t *testing.T) {
|
||||
sendKeys(tm, "x", "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "llo" {
|
||||
t.Errorf("lines[0] = %q, want 'llo'", m.lines[0])
|
||||
if m.Line(0) != "llo" {
|
||||
t.Errorf("lines[0] = %q, want 'llo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -59,8 +59,8 @@ func TestDeleteCharWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "lo" {
|
||||
t.Errorf("lines[0] = %q, want 'lo'", m.lines[0])
|
||||
if m.Line(0) != "lo" {
|
||||
t.Errorf("lines[0] = %q, want 'lo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -70,8 +70,8 @@ func TestDeleteCharWithCount(t *testing.T) {
|
||||
sendKeys(tm, "1", "0", "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.lines[0])
|
||||
if m.Line(0) != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -81,8 +81,8 @@ func TestDeleteCharWithCount(t *testing.T) {
|
||||
sendKeys(tm, "2", "x")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hlo" {
|
||||
t.Errorf("lines[0] = %q, want 'hlo'", m.lines[0])
|
||||
if m.Line(0) != "hlo" {
|
||||
t.Errorf("lines[0] = %q, want 'hlo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -25,8 +25,8 @@ func TestEnterInsert(t *testing.T) {
|
||||
sendKeys(tm, "i", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||
if m.Line(0) != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -36,8 +36,8 @@ func TestEnterInsert(t *testing.T) {
|
||||
sendKeys(tm, "i", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||
if m.Line(0) != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -47,8 +47,8 @@ func TestEnterInsert(t *testing.T) {
|
||||
sendKeys(tm, "i", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 2 {
|
||||
t.Errorf("cursor.x = %d, want 2", m.cursor.x)
|
||||
if m.CursorX() != 2 {
|
||||
t.Errorf("cursor.x = %d, want 2", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -70,8 +70,8 @@ func TestEnterInsertAfter(t *testing.T) {
|
||||
sendKeys(tm, "a", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hXello" {
|
||||
t.Errorf("lines[0] = %q, want 'hXello'", m.lines[0])
|
||||
if m.Line(0) != "hXello" {
|
||||
t.Errorf("lines[0] = %q, want 'hXello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -81,8 +81,8 @@ func TestEnterInsertAfter(t *testing.T) {
|
||||
sendKeys(tm, "a", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "helXlo" {
|
||||
t.Errorf("lines[0] = %q, want 'helXlo'", m.lines[0])
|
||||
if m.Line(0) != "helXlo" {
|
||||
t.Errorf("lines[0] = %q, want 'helXlo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -94,8 +94,8 @@ func TestEnterInsertLineStart(t *testing.T) {
|
||||
sendKeys(tm, "I", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||
if m.Line(0) != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -105,8 +105,8 @@ func TestEnterInsertLineStart(t *testing.T) {
|
||||
sendKeys(tm, "I", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||
if m.Line(0) != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -118,8 +118,8 @@ func TestEnterInsertLineEnd(t *testing.T) {
|
||||
sendKeys(tm, "A", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "helloX" {
|
||||
t.Errorf("lines[0] = %q, want 'helloX'", m.lines[0])
|
||||
if m.Line(0) != "helloX" {
|
||||
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -129,8 +129,8 @@ func TestEnterInsertLineEnd(t *testing.T) {
|
||||
sendKeys(tm, "A", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "helloX" {
|
||||
t.Errorf("lines[0] = %q, want 'helloX'", m.lines[0])
|
||||
if m.Line(0) != "helloX" {
|
||||
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -144,11 +144,11 @@ func TestOpenLineBelow(t *testing.T) {
|
||||
sendKeys(tm, "o", "n", "e", "w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||
if m.LineCount() != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", m.LineCount())
|
||||
}
|
||||
if m.lines[1] != "new" {
|
||||
t.Errorf("lines[1] = %q, want 'new'", m.lines[1])
|
||||
if m.Line(1) != "new" {
|
||||
t.Errorf("lines[1] = %q, want 'new'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -158,11 +158,11 @@ func TestOpenLineBelow(t *testing.T) {
|
||||
sendKeys(tm, "o", "n", "e", "w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 4 {
|
||||
t.Errorf("len(lines) = %d, want 4", len(m.lines))
|
||||
if m.LineCount() != 4 {
|
||||
t.Errorf("len(lines) = %d, want 4", m.LineCount())
|
||||
}
|
||||
if m.lines[2] != "new" {
|
||||
t.Errorf("lines[2] = %q, want 'new'", m.lines[2])
|
||||
if m.Line(2) != "new" {
|
||||
t.Errorf("lines[2] = %q, want 'new'", m.Line(2))
|
||||
}
|
||||
})
|
||||
|
||||
@ -172,11 +172,11 @@ func TestOpenLineBelow(t *testing.T) {
|
||||
sendKeys(tm, "o", "n", "e", "w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||
if m.LineCount() != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", m.LineCount())
|
||||
}
|
||||
if m.lines[2] != "new" {
|
||||
t.Errorf("lines[2] = %q, want 'new'", m.lines[2])
|
||||
if m.Line(2) != "new" {
|
||||
t.Errorf("lines[2] = %q, want 'new'", m.Line(2))
|
||||
}
|
||||
})
|
||||
|
||||
@ -186,11 +186,11 @@ func TestOpenLineBelow(t *testing.T) {
|
||||
sendKeys(tm, "o", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
||||
if m.CursorY() != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.CursorY())
|
||||
}
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -202,12 +202,12 @@ func TestOpenLineBelowWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "o", "x", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 4 {
|
||||
t.Errorf("len(lines) = %d, want 4", len(m.lines))
|
||||
if m.LineCount() != 4 {
|
||||
t.Errorf("len(lines) = %d, want 4", m.LineCount())
|
||||
}
|
||||
for i := 1; i <= 3; i++ {
|
||||
if m.lines[i] != "x" {
|
||||
t.Errorf("lines[%d] = %q, want 'x'", i, m.lines[i])
|
||||
if m.Line(i) != "x" {
|
||||
t.Errorf("lines[%d] = %q, want 'x'", i, m.Line(i))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -218,14 +218,14 @@ func TestOpenLineBelowWithCount(t *testing.T) {
|
||||
sendKeys(tm, "2", "o", "a", "b", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||
if m.LineCount() != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", m.LineCount())
|
||||
}
|
||||
if m.lines[1] != "ab" {
|
||||
t.Errorf("lines[1] = %q, want 'ab'", m.lines[1])
|
||||
if m.Line(1) != "ab" {
|
||||
t.Errorf("lines[1] = %q, want 'ab'", m.Line(1))
|
||||
}
|
||||
if m.lines[2] != "ab" {
|
||||
t.Errorf("lines[2] = %q, want 'ab'", m.lines[2])
|
||||
if m.Line(2) != "ab" {
|
||||
t.Errorf("lines[2] = %q, want 'ab'", m.Line(2))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -237,11 +237,11 @@ func TestOpenLineAbove(t *testing.T) {
|
||||
sendKeys(tm, "O", "n", "e", "w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||
if m.LineCount() != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", m.LineCount())
|
||||
}
|
||||
if m.lines[1] != "new" {
|
||||
t.Errorf("lines[1] = %q, want 'new'", m.lines[1])
|
||||
if m.Line(1) != "new" {
|
||||
t.Errorf("lines[1] = %q, want 'new'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -251,11 +251,11 @@ func TestOpenLineAbove(t *testing.T) {
|
||||
sendKeys(tm, "O", "n", "e", "w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||
if m.LineCount() != 3 {
|
||||
t.Errorf("len(lines) = %d, want 3", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "new" {
|
||||
t.Errorf("lines[0] = %q, want 'new'", m.lines[0])
|
||||
if m.Line(0) != "new" {
|
||||
t.Errorf("lines[0] = %q, want 'new'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -265,8 +265,8 @@ func TestOpenLineAbove(t *testing.T) {
|
||||
sendKeys(tm, "O", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -278,12 +278,12 @@ func TestOpenLineAboveWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "O", "x", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 4 {
|
||||
t.Errorf("len(lines) = %d, want 4", len(m.lines))
|
||||
if m.LineCount() != 4 {
|
||||
t.Errorf("len(lines) = %d, want 4", m.LineCount())
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if m.lines[i] != "x" {
|
||||
t.Errorf("lines[%d] = %q, want 'x'", i, m.lines[i])
|
||||
if m.Line(i) != "x" {
|
||||
t.Errorf("lines[%d] = %q, want 'x'", i, m.Line(i))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -298,14 +298,14 @@ func TestInsertModeEnter(t *testing.T) {
|
||||
sendKeys(tm, "i", "enter", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 2 {
|
||||
t.Errorf("len(lines) = %d, want 2", len(m.lines))
|
||||
if m.LineCount() != 2 {
|
||||
t.Errorf("len(lines) = %d, want 2", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
if m.lines[1] != " world" {
|
||||
t.Errorf("lines[1] = %q, want ' world'", m.lines[1])
|
||||
if m.Line(1) != " world" {
|
||||
t.Errorf("lines[1] = %q, want ' world'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -315,14 +315,14 @@ func TestInsertModeEnter(t *testing.T) {
|
||||
sendKeys(tm, "i", "enter", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 2 {
|
||||
t.Errorf("len(lines) = %d, want 2", len(m.lines))
|
||||
if m.LineCount() != 2 {
|
||||
t.Errorf("len(lines) = %d, want 2", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
if m.lines[1] != "" {
|
||||
t.Errorf("lines[1] = %q, want ''", m.lines[1])
|
||||
if m.Line(1) != "" {
|
||||
t.Errorf("lines[1] = %q, want ''", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -332,14 +332,14 @@ func TestInsertModeEnter(t *testing.T) {
|
||||
sendKeys(tm, "i", "enter", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 2 {
|
||||
t.Errorf("len(lines) = %d, want 2", len(m.lines))
|
||||
if m.LineCount() != 2 {
|
||||
t.Errorf("len(lines) = %d, want 2", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.lines[0])
|
||||
if m.Line(0) != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.Line(0))
|
||||
}
|
||||
if m.lines[1] != "hello" {
|
||||
t.Errorf("lines[1] = %q, want 'hello'", m.lines[1])
|
||||
if m.Line(1) != "hello" {
|
||||
t.Errorf("lines[1] = %q, want 'hello'", m.Line(1))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -351,8 +351,8 @@ func TestInsertModeBackspace(t *testing.T) {
|
||||
sendKeys(tm, "i", "backspace", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "helo" {
|
||||
t.Errorf("lines[0] = %q, want 'helo'", m.lines[0])
|
||||
if m.Line(0) != "helo" {
|
||||
t.Errorf("lines[0] = %q, want 'helo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -362,11 +362,11 @@ func TestInsertModeBackspace(t *testing.T) {
|
||||
sendKeys(tm, "i", "backspace", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 1 {
|
||||
t.Errorf("len(lines) = %d, want 1", len(m.lines))
|
||||
if m.LineCount() != 1 {
|
||||
t.Errorf("len(lines) = %d, want 1", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "helloworld" {
|
||||
t.Errorf("lines[0] = %q, want 'helloworld'", m.lines[0])
|
||||
if m.Line(0) != "helloworld" {
|
||||
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -376,8 +376,8 @@ func TestInsertModeBackspace(t *testing.T) {
|
||||
sendKeys(tm, "i", "backspace", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -387,8 +387,8 @@ func TestInsertModeBackspace(t *testing.T) {
|
||||
sendKeys(tm, "i", "backspace", "backspace", "backspace", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "he" {
|
||||
t.Errorf("lines[0] = %q, want 'he'", m.lines[0])
|
||||
if m.Line(0) != "he" {
|
||||
t.Errorf("lines[0] = %q, want 'he'", m.Line(0))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -400,8 +400,8 @@ func TestInsertModeDelete(t *testing.T) {
|
||||
sendKeys(tm, "i", "delete", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "word" {
|
||||
t.Errorf("lines[0] = %q, want 'word'", m.lines[0])
|
||||
if m.Line(0) != "word" {
|
||||
t.Errorf("lines[0] = %q, want 'word'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -411,11 +411,11 @@ func TestInsertModeDelete(t *testing.T) {
|
||||
sendKeys(tm, "i", "delete", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 1 {
|
||||
t.Errorf("len(lines) = %d, want 1", len(m.lines))
|
||||
if m.LineCount() != 1 {
|
||||
t.Errorf("len(lines) = %d, want 1", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "helloworld" {
|
||||
t.Errorf("lines[0] = %q, want 'helloworld'", m.lines[0])
|
||||
if m.Line(0) != "helloworld" {
|
||||
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -425,11 +425,11 @@ func TestInsertModeDelete(t *testing.T) {
|
||||
sendKeys(tm, "i", "delete", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if len(m.lines) != 1 {
|
||||
t.Errorf("len(lines) = %d, want 1", len(m.lines))
|
||||
if m.LineCount() != 1 {
|
||||
t.Errorf("len(lines) = %d, want 1", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "world" {
|
||||
t.Errorf("lines[0] = %q, want 'world'", m.lines[0])
|
||||
if m.Line(0) != "world" {
|
||||
t.Errorf("lines[0] = %q, want 'world'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -439,8 +439,8 @@ func TestInsertModeDelete(t *testing.T) {
|
||||
sendKeys(tm, "i", "delete", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -450,8 +450,8 @@ func TestInsertModeDelete(t *testing.T) {
|
||||
sendKeys(tm, "i", "delete", "delete", "delete", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "ho" {
|
||||
t.Errorf("lines[0] = %q, want 'he'", m.lines[0])
|
||||
if m.Line(0) != "ho" {
|
||||
t.Errorf("lines[0] = %q, want 'he'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -464,8 +464,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "left", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||
if m.Line(0) != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -475,8 +475,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "right", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||
if m.Line(0) != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -486,11 +486,11 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "up", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||
if m.Line(0) != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
|
||||
}
|
||||
if m.lines[1] != "world" {
|
||||
t.Errorf("lines[1] = %q, want 'world'", m.lines[1])
|
||||
if m.Line(1) != "world" {
|
||||
t.Errorf("lines[1] = %q, want 'world'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -500,11 +500,11 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "down", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
if m.lines[1] != "woXrld" {
|
||||
t.Errorf("lines[1] = %q, want 'woXrld'", m.lines[1])
|
||||
if m.Line(1) != "woXrld" {
|
||||
t.Errorf("lines[1] = %q, want 'woXrld'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -514,8 +514,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "left", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||
if m.Line(0) != "Xhello" {
|
||||
t.Errorf("lines[0] = %q, want 'Xhello'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -525,8 +525,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "a", "right", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "helloX" {
|
||||
t.Errorf("lines[0] = %q, want 'helloX'", m.lines[0])
|
||||
if m.Line(0) != "helloX" {
|
||||
t.Errorf("lines[0] = %q, want 'helloX'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -536,8 +536,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "up", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||
if m.Line(0) != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -547,8 +547,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "down", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||
if m.Line(0) != "heXllo" {
|
||||
t.Errorf("lines[0] = %q, want 'heXllo'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -558,8 +558,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "up", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hiX" {
|
||||
t.Errorf("lines[0] = %q, want 'hiX'", m.lines[0])
|
||||
if m.Line(0) != "hiX" {
|
||||
t.Errorf("lines[0] = %q, want 'hiX'", m.Line(0))
|
||||
}
|
||||
})
|
||||
|
||||
@ -569,8 +569,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "down", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[1] != "hiX" {
|
||||
t.Errorf("lines[1] = %q, want 'hiX'", m.lines[1])
|
||||
if m.Line(1) != "hiX" {
|
||||
t.Errorf("lines[1] = %q, want 'hiX'", m.Line(1))
|
||||
}
|
||||
})
|
||||
|
||||
@ -580,8 +580,8 @@ func TestInsertModeArrowKeys(t *testing.T) {
|
||||
sendKeys(tm, "i", "right", "right", "down", "X", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[1] != "woXrld" {
|
||||
t.Errorf("lines[1] = %q, want 'woXrld'", m.lines[1])
|
||||
if m.Line(1) != "woXrld" {
|
||||
t.Errorf("lines[1] = %q, want 'woXrld'", m.Line(1))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -593,8 +593,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "a", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello " {
|
||||
t.Errorf("lines[0] = %q, want 'hello '", m.lines[0])
|
||||
if m.Line(0) != "hello " {
|
||||
t.Errorf("lines[0] = %q, want 'hello '", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 5 {
|
||||
t.Errorf("CursorX() = %d, want '5'", m.CursorX())
|
||||
@ -607,8 +607,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "a", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.lines[0])
|
||||
if m.Line(0) != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want '0'", m.CursorX())
|
||||
@ -621,8 +621,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "a", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello wo" {
|
||||
t.Errorf("lines[0] = %q, want 'hello wo'", m.lines[0])
|
||||
if m.Line(0) != "hello wo" {
|
||||
t.Errorf("lines[0] = %q, want 'hello wo'", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 7 {
|
||||
t.Errorf("CursorX() = %d, want '7'", m.CursorX())
|
||||
@ -672,8 +672,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "i", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||
if m.Line(0) != "hello" {
|
||||
t.Errorf("lines[0] = %q, want 'hello'", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
@ -686,8 +686,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "i", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "lo" {
|
||||
t.Errorf("lines[0] = %q, want 'lo'", m.lines[0])
|
||||
if m.Line(0) != "lo" {
|
||||
t.Errorf("lines[0] = %q, want 'lo'", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
@ -700,8 +700,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "a", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "..." {
|
||||
t.Errorf("lines[0] = %q, want '...'", m.lines[0])
|
||||
if m.Line(0) != "..." {
|
||||
t.Errorf("lines[0] = %q, want '...'", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 2 {
|
||||
t.Errorf("CursorX() = %d, want 2", m.CursorX())
|
||||
@ -714,8 +714,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "a", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "hello\t" {
|
||||
t.Errorf("lines[0] = %q, want 'hello\\t'", m.lines[0])
|
||||
if m.Line(0) != "hello\t" {
|
||||
t.Errorf("lines[0] = %q, want 'hello\\t'", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 5 {
|
||||
t.Errorf("CursorX() = %d, want 5", m.CursorX())
|
||||
@ -731,8 +731,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
if m.LineCount() != 1 {
|
||||
t.Errorf("LineCount() = %d, want 1", m.LineCount())
|
||||
}
|
||||
if m.lines[0] != "helloworld" {
|
||||
t.Errorf("lines[0] = %q, want 'helloworld'", m.lines[0])
|
||||
if m.Line(0) != "helloworld" {
|
||||
t.Errorf("lines[0] = %q, want 'helloworld'", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("CursorX() = %d, want 4", m.CursorX())
|
||||
@ -748,8 +748,8 @@ func TestInsertModeDeletePreviousWord(t *testing.T) {
|
||||
sendKeys(tm, "a", "ctrl+w", "esc")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.lines[0] != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.lines[0])
|
||||
if m.Line(0) != "" {
|
||||
t.Errorf("lines[0] = %q, want ''", m.Line(0))
|
||||
}
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("CursorX() = %d, want 0", m.CursorX())
|
||||
|
||||
@ -12,8 +12,8 @@ func TestMoveDown(t *testing.T) {
|
||||
sendKeys(tm, "j")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
||||
if m.CursorY() != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -22,8 +22,8 @@ func TestMoveDown(t *testing.T) {
|
||||
sendKeys(tm, "j", "j", "j", "j")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 4 {
|
||||
t.Errorf("cursor.y = %d, want 4", m.cursor.y)
|
||||
if m.CursorY() != 4 {
|
||||
t.Errorf("cursor.y = %d, want 4", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -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.cursor.y != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||
if m.CursorY() != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -44,8 +44,8 @@ func TestMoveDownWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "j")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 3 {
|
||||
t.Errorf("cursor.y = %d, want 3", m.cursor.y)
|
||||
if m.CursorY() != 3 {
|
||||
t.Errorf("cursor.y = %d, want 3", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -54,8 +54,8 @@ func TestMoveDownWithCount(t *testing.T) {
|
||||
sendKeys(tm, "1", "0", "j")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||
if m.CursorY() != 5 {
|
||||
t.Errorf("cursor.y = %d, want 5", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -69,8 +69,8 @@ func TestMoveDownWithOverflow(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[1])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
|
||||
@ -79,8 +79,8 @@ func TestMoveDownWithOverflow(t *testing.T) {
|
||||
sendKeys(tm, "j")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 3 {
|
||||
t.Errorf("cursor.x = %d, want 3", m.cursor.x)
|
||||
if m.CursorX() != 3 {
|
||||
t.Errorf("cursor.x = %d, want 3", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -91,8 +91,8 @@ func TestMoveUp(t *testing.T) {
|
||||
sendKeys(tm, "k")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
||||
if m.CursorY() != 1 {
|
||||
t.Errorf("cursor.y = %d, want 1", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -101,8 +101,8 @@ func TestMoveUp(t *testing.T) {
|
||||
sendKeys(tm, "k", "k", "k", "k")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -111,8 +111,8 @@ func TestMoveUp(t *testing.T) {
|
||||
sendKeys(tm, "k", "k", "k")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -123,8 +123,8 @@ func TestMoveUpWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "k")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 2 {
|
||||
t.Errorf("cursor.y = %d, want 2", m.cursor.y)
|
||||
if m.CursorY() != 2 {
|
||||
t.Errorf("cursor.y = %d, want 2", m.CursorY())
|
||||
}
|
||||
})
|
||||
|
||||
@ -133,8 +133,8 @@ func TestMoveUpWithCount(t *testing.T) {
|
||||
sendKeys(tm, "1", "0", "k")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.y != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||
if m.CursorY() != 0 {
|
||||
t.Errorf("cursor.y = %d, want 0", m.CursorY())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -148,8 +148,8 @@ func TestMoveUpWithOverflow(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
|
||||
@ -158,8 +158,8 @@ func TestMoveUpWithOverflow(t *testing.T) {
|
||||
sendKeys(tm, "k")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 3 {
|
||||
t.Errorf("cursor.x = %d, want 3", m.cursor.x)
|
||||
if m.CursorX() != 3 {
|
||||
t.Errorf("cursor.x = %d, want 3", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -170,8 +170,8 @@ func TestMoveRight(t *testing.T) {
|
||||
sendKeys(tm, "l")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 1 {
|
||||
t.Errorf("cursor.x = %d, want 1", m.cursor.x)
|
||||
if m.CursorX() != 1 {
|
||||
t.Errorf("cursor.x = %d, want 1", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -180,8 +180,8 @@ func TestMoveRight(t *testing.T) {
|
||||
sendKeys(tm, "l", "l", "l", "l")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 4 {
|
||||
t.Errorf("cursor.x = %d, want 4", m.cursor.x)
|
||||
if m.CursorX() != 4 {
|
||||
t.Errorf("cursor.x = %d, want 4", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -192,8 +192,8 @@ func TestMoveRight(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -204,8 +204,8 @@ func TestMoveRightWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "l")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 3 {
|
||||
t.Errorf("cursor.x = %d, want 3", m.cursor.x)
|
||||
if m.CursorX() != 3 {
|
||||
t.Errorf("cursor.x = %d, want 3", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -216,8 +216,8 @@ func TestMoveRightWithCount(t *testing.T) {
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
want := len(lines[0])
|
||||
if m.cursor.x != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||
if m.CursorX() != want {
|
||||
t.Errorf("cursor.x = %d, want %d", m.CursorX(), want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -228,8 +228,8 @@ func TestMoveLeft(t *testing.T) {
|
||||
sendKeys(tm, "h")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 2 {
|
||||
t.Errorf("cursor.x = %d, want 2", m.cursor.x)
|
||||
if m.CursorX() != 2 {
|
||||
t.Errorf("cursor.x = %d, want 2", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -238,8 +238,8 @@ func TestMoveLeft(t *testing.T) {
|
||||
sendKeys(tm, "h", "h", "h", "h")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -248,8 +248,8 @@ func TestMoveLeft(t *testing.T) {
|
||||
sendKeys(tm, "h", "h", "h")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -260,8 +260,8 @@ func TestMoveLeftWithCount(t *testing.T) {
|
||||
sendKeys(tm, "3", "h")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 2 {
|
||||
t.Errorf("cursor.x = %d, want 2", m.cursor.x)
|
||||
if m.CursorX() != 2 {
|
||||
t.Errorf("cursor.x = %d, want 2", m.CursorX())
|
||||
}
|
||||
})
|
||||
|
||||
@ -270,8 +270,8 @@ func TestMoveLeftWithCount(t *testing.T) {
|
||||
sendKeys(tm, "1", "0", "h")
|
||||
|
||||
m := getFinalModel(t, tm)
|
||||
if m.cursor.x != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||
if m.CursorX() != 0 {
|
||||
t.Errorf("cursor.x = %d, want 0", m.CursorX())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,20 +9,19 @@ import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type cursor struct {
|
||||
x int
|
||||
y int
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
lines []string
|
||||
cursor cursor
|
||||
anchor cursor // starting point for visual modes
|
||||
scrollY int
|
||||
mode action.Mode
|
||||
win_h int
|
||||
win_w int
|
||||
input *input.Handler
|
||||
// lines []string
|
||||
// cursor cursor
|
||||
// anchor cursor // starting point for visual modes
|
||||
// scrollY int
|
||||
mode action.Mode
|
||||
win_h int
|
||||
win_w int
|
||||
|
||||
activeWindow int
|
||||
windows []*action.Window
|
||||
|
||||
input *input.Handler
|
||||
|
||||
// Insert repetition
|
||||
insertCount int
|
||||
@ -42,20 +41,30 @@ type Model struct {
|
||||
registers map[rune]action.Register // name -> register
|
||||
}
|
||||
|
||||
func NewModel(lines []string, pos action.Position) Model {
|
||||
return Model{
|
||||
lines: lines,
|
||||
cursor: cursor{
|
||||
x: pos.Col,
|
||||
y: pos.Line,
|
||||
},
|
||||
scrollY: 0,
|
||||
func NewModel(lines []string, pos action.Position) *Model {
|
||||
m := Model{
|
||||
// lines: lines,
|
||||
// cursor: cursor{
|
||||
// x: pos.Col,
|
||||
// y: pos.Line,
|
||||
// },
|
||||
// scrollY: 0,
|
||||
mode: action.NormalMode,
|
||||
command: "",
|
||||
input: input.NewHandler(),
|
||||
settings: action.NewDefaultSettings(),
|
||||
registers: action.DefaultRegisters(),
|
||||
|
||||
windows: []*action.Window{},
|
||||
}
|
||||
|
||||
// Temporary
|
||||
win := action.NewEmptyWindow(lines, 0, 0)
|
||||
win.Cursor = pos // Set initial cursor position
|
||||
m.windows = append(m.windows, win)
|
||||
m.activeWindow = win.Id
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
func (m Model) Init() tea.Cmd {
|
||||
@ -65,73 +74,74 @@ func (m Model) Init() tea.Cmd {
|
||||
// Implement action.Model interface
|
||||
|
||||
func (m *Model) Lines() []string {
|
||||
return m.lines
|
||||
win := m.ActiveWindow()
|
||||
return win.Buffer.Lines
|
||||
}
|
||||
|
||||
func (m *Model) Line(idx int) string {
|
||||
if idx < 0 || idx >= len(m.lines) {
|
||||
return ""
|
||||
}
|
||||
return m.lines[idx]
|
||||
win := m.ActiveWindow()
|
||||
return win.Buffer.Line(idx)
|
||||
}
|
||||
|
||||
func (m *Model) SetLine(idx int, content string) {
|
||||
if idx >= 0 && idx < len(m.lines) {
|
||||
m.lines[idx] = content
|
||||
}
|
||||
win := m.ActiveWindow()
|
||||
win.Buffer.SetLine(idx, content)
|
||||
}
|
||||
|
||||
func (m *Model) InsertLine(idx int, content string) {
|
||||
if idx < 0 {
|
||||
idx = 0
|
||||
}
|
||||
if idx > len(m.lines) {
|
||||
idx = len(m.lines)
|
||||
}
|
||||
m.lines = append(m.lines[:idx], append([]string{content}, m.lines[idx:]...)...)
|
||||
win := m.ActiveWindow()
|
||||
win.Buffer.InsertLine(idx, content)
|
||||
}
|
||||
|
||||
func (m *Model) DeleteLine(idx int) {
|
||||
if idx >= 0 && idx < len(m.lines) {
|
||||
m.lines = append(m.lines[:idx], m.lines[idx+1:]...)
|
||||
}
|
||||
win := m.ActiveWindow()
|
||||
win.Buffer.DeleteLine(idx)
|
||||
}
|
||||
|
||||
func (m *Model) LineCount() int {
|
||||
return len(m.lines)
|
||||
win := m.ActiveWindow()
|
||||
return win.Buffer.LineCount()
|
||||
}
|
||||
|
||||
func (m *Model) CursorX() int {
|
||||
return m.cursor.x
|
||||
win := m.ActiveWindow()
|
||||
return win.Cursor.Col
|
||||
}
|
||||
|
||||
func (m *Model) CursorY() int {
|
||||
return m.cursor.y
|
||||
win := m.ActiveWindow()
|
||||
return win.Cursor.Line
|
||||
}
|
||||
|
||||
func (m *Model) SetCursorX(x int) {
|
||||
m.cursor.x = x
|
||||
win := m.ActiveWindow()
|
||||
win.Cursor.Col = x
|
||||
}
|
||||
|
||||
func (m *Model) SetCursorY(y int) {
|
||||
m.cursor.y = y
|
||||
win := m.ActiveWindow()
|
||||
win.Cursor.Line = y
|
||||
}
|
||||
|
||||
// Anchor methods
|
||||
func (m *Model) AnchorX() int {
|
||||
return m.anchor.x
|
||||
win := m.ActiveWindow()
|
||||
return win.Anchor.Col
|
||||
}
|
||||
|
||||
func (m *Model) AnchorY() int {
|
||||
return m.anchor.y
|
||||
win := m.ActiveWindow()
|
||||
return win.Anchor.Line
|
||||
}
|
||||
|
||||
func (m *Model) SetAnchorX(x int) {
|
||||
m.anchor.x = x
|
||||
win := m.ActiveWindow()
|
||||
win.Anchor.Col = x
|
||||
}
|
||||
|
||||
func (m *Model) SetAnchorY(y int) {
|
||||
m.anchor.y = y
|
||||
win := m.ActiveWindow()
|
||||
win.Anchor.Line = y
|
||||
}
|
||||
|
||||
// Insert methods
|
||||
@ -226,32 +236,33 @@ func (m *Model) UpdateDefaultRegister(t action.RegisterType, cnt []string) {
|
||||
|
||||
// Window
|
||||
func (m *Model) ScrollY() int {
|
||||
return m.scrollY
|
||||
win := m.ActiveWindow()
|
||||
return win.ScrollY
|
||||
}
|
||||
|
||||
func (m *Model) SetScrollY(y int) {
|
||||
m.scrollY = y
|
||||
win := m.ActiveWindow()
|
||||
win.ScrollY = y
|
||||
}
|
||||
|
||||
func (m *Model) WinH() int {
|
||||
return m.win_h
|
||||
win := m.ActiveWindow()
|
||||
return win.Height
|
||||
}
|
||||
|
||||
func (m *Model) WinW() int {
|
||||
return m.win_w
|
||||
win := m.ActiveWindow()
|
||||
return win.Width
|
||||
}
|
||||
|
||||
func (m *Model) ViewPortH() int {
|
||||
return m.win_h - 2 // -2 for status bar and commmand bar
|
||||
win := m.ActiveWindow()
|
||||
return win.Height - 2
|
||||
}
|
||||
|
||||
func (m *Model) ClampCursorX() {
|
||||
lineLen := len(m.lines[m.cursor.y])
|
||||
if lineLen == 0 {
|
||||
m.cursor.x = 0
|
||||
} else if m.cursor.x >= lineLen {
|
||||
m.cursor.x = lineLen
|
||||
}
|
||||
win := m.ActiveWindow()
|
||||
win.ClampCursorX()
|
||||
}
|
||||
|
||||
// AdjustScroll ensures the cursor stays within the viewport with scrollOff margins.
|
||||
@ -280,6 +291,25 @@ func (m *Model) AdjustScroll() {
|
||||
m.SetScrollY(max(0, min(m.ScrollY(), maxScroll)))
|
||||
}
|
||||
|
||||
// Windows
|
||||
func (m *Model) Windows() []*action.Window {
|
||||
return m.windows
|
||||
}
|
||||
|
||||
func (m *Model) ActiveWindowId() int {
|
||||
return m.activeWindow
|
||||
}
|
||||
|
||||
func (m *Model) ActiveWindow() *action.Window {
|
||||
winId := m.ActiveWindowId()
|
||||
for i := range m.Windows() {
|
||||
if m.windows[i].Id == winId {
|
||||
return m.windows[i]
|
||||
}
|
||||
}
|
||||
panic("Could not find window")
|
||||
}
|
||||
|
||||
func (m *Model) Mode() action.Mode {
|
||||
return m.mode
|
||||
}
|
||||
@ -294,24 +324,29 @@ func (m *Model) SetInsertRecording(count int, act action.Action) {
|
||||
m.insertAction = act
|
||||
}
|
||||
|
||||
func (m *Model) GetCursorPosition() action.Position {
|
||||
return action.Position{Line: m.cursor.y, Col: m.cursor.x}
|
||||
func (m *Model) GetCursorPosition() *action.Position {
|
||||
// Return a copy of the position
|
||||
win := m.ActiveWindow()
|
||||
pos := win.Cursor
|
||||
return &pos
|
||||
}
|
||||
|
||||
func (m *Model) replayInsert() {
|
||||
win := m.ActiveWindow()
|
||||
|
||||
// Replay (count - 1) more times
|
||||
for i := 1; i < m.insertCount; i++ {
|
||||
// For 'o' and 'O', we need to create a new line first
|
||||
switch m.insertAction.(type) {
|
||||
case action.OpenLineBelow:
|
||||
pos := m.cursor.y
|
||||
m.lines = append(m.lines[:pos+1], append([]string{""}, m.lines[pos+1:]...)...)
|
||||
m.cursor.y++
|
||||
m.cursor.x = 0
|
||||
pos := win.Cursor.Line
|
||||
win.Buffer.Lines = append(win.Buffer.Lines[:pos+1], append([]string{""}, win.Buffer.Lines[pos+1:]...)...)
|
||||
win.Cursor.Line++
|
||||
win.Cursor.Col = 0
|
||||
case action.OpenLineAbove:
|
||||
pos := m.cursor.y
|
||||
m.lines = append(m.lines[:pos], append([]string{""}, m.lines[pos:]...)...)
|
||||
m.cursor.x = 0
|
||||
pos := win.Cursor.Line
|
||||
win.Buffer.Lines = append(win.Buffer.Lines[:pos], append([]string{""}, win.Buffer.Lines[pos:]...)...)
|
||||
win.Cursor.Col = 0
|
||||
// 'i' and 'a' don't need setup - just replay keys
|
||||
}
|
||||
|
||||
@ -323,11 +358,12 @@ func (m *Model) replayInsert() {
|
||||
}
|
||||
|
||||
func (m *Model) ExitInsertMode() {
|
||||
win := m.ActiveWindow()
|
||||
if m.insertCount > 1 {
|
||||
m.replayInsert()
|
||||
}
|
||||
if m.cursor.x > 0 {
|
||||
m.cursor.x--
|
||||
if win.Cursor.Col > 0 {
|
||||
win.Cursor.Col--
|
||||
}
|
||||
m.mode = action.NormalMode
|
||||
m.insertCount = 0
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
@ -13,13 +13,19 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.win_h = msg.Height
|
||||
m.win_w = msg.Width
|
||||
|
||||
// TODO: Temp, this is lame
|
||||
for i := range m.windows {
|
||||
m.windows[i].Height = msg.Height
|
||||
m.windows[i].Width = msg.Width
|
||||
}
|
||||
|
||||
case tea.KeyMsg:
|
||||
// TODO: This needs to be removed, but for now its required for the tests.
|
||||
// Ctrl+C always quits regardless of mode
|
||||
if msg.Type == tea.KeyCtrlC {
|
||||
return m, tea.Quit
|
||||
}
|
||||
cmd = m.input.Handle(&m, msg.String())
|
||||
cmd = m.input.Handle(m, msg.String())
|
||||
}
|
||||
|
||||
// Keep cursor in view after any update
|
||||
|
||||
@ -16,7 +16,7 @@ const (
|
||||
|
||||
// PositionGetter is used to get cursor position for operator ranges
|
||||
type PositionGetter interface {
|
||||
GetCursorPosition() action.Position
|
||||
GetCursorPosition() *action.Position
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
@ -205,7 +205,7 @@ func (h *Handler) handleAfterOperator(m action.Model, kind string, binding any,
|
||||
start := pg.GetCursorPosition()
|
||||
mot.Execute(m)
|
||||
end := pg.GetCursorPosition()
|
||||
cmd := h.operator.Operate(m, start, end, mot.Type())
|
||||
cmd := h.operator.Operate(m, *start, *end, mot.Type())
|
||||
h.Reset()
|
||||
return cmd
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user