Now we can load them in via JSON files at launch time. They are embded in the final exe though...
115 lines
3.1 KiB
Go
115 lines
3.1 KiB
Go
package syntax
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"git.gophernest.net/azpect/TextEditor/internal/core"
|
|
"git.gophernest.net/azpect/TextEditor/internal/theme"
|
|
"git.gophernest.net/azpect/TextEditor/internal/theme/themes"
|
|
)
|
|
|
|
type seqOp func(*core.Buffer, *core.Window)
|
|
|
|
func TestTreeSitterEngineEditSequences(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
lines []string
|
|
opList []seqOp
|
|
}{
|
|
{
|
|
name: "setline and insertline",
|
|
lines: []string{"package main", "func main() {", " x := 1", "}"},
|
|
opList: []seqOp{
|
|
func(b *core.Buffer, _ *core.Window) { b.SetLine(2, " x := 2") },
|
|
func(b *core.Buffer, _ *core.Window) { b.InsertLine(3, " println(x)") },
|
|
},
|
|
},
|
|
{
|
|
name: "delete middle line",
|
|
lines: []string{"package main", "func main() {", " x := 1", " y := 2", "}"},
|
|
opList: []seqOp{
|
|
func(b *core.Buffer, _ *core.Window) { b.DeleteLine(3) },
|
|
},
|
|
},
|
|
{
|
|
name: "multiline string evolve",
|
|
lines: []string{"package main", "func main() {", " s := `a", "b`", " _ = s", "}"},
|
|
opList: []seqOp{
|
|
func(b *core.Buffer, _ *core.Window) { b.SetLine(2, " s := `alpha") },
|
|
func(b *core.Buffer, _ *core.Window) { b.SetLine(3, "beta`") },
|
|
},
|
|
},
|
|
{
|
|
name: "undo redo sequence",
|
|
lines: []string{"package main", "func main() {", " v := 3", "}"},
|
|
opList: []seqOp{
|
|
func(b *core.Buffer, w *core.Window) {
|
|
b.UndoStack.BeginBlock(w.Cursor)
|
|
b.SetLine(2, " v := 9")
|
|
b.UndoStack.EndBlock(core.Position{Line: 2, Col: 8})
|
|
},
|
|
func(b *core.Buffer, w *core.Window) { _ = b.Undo(w) },
|
|
func(b *core.Buffer, w *core.Window) { _ = b.Redo(w) },
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
b := core.NewBufferBuilder().
|
|
WithFilename("seq.go").
|
|
WithFiletype("go").
|
|
WithLines(tc.lines).
|
|
Build()
|
|
buf := &b
|
|
|
|
w := core.NewWindowBuilder().WithBuffer(buf).WithDimensions(120, 40).Build()
|
|
win := &w
|
|
|
|
editorTheme := themes.NewDefaultTheme()
|
|
engine := NewTreeSitterEngine(editorTheme)
|
|
|
|
buf.OnChange = func(change core.BufferChange) {
|
|
if change.Edit != nil {
|
|
engine.ApplyEdit(buf, change.Edit)
|
|
} else {
|
|
engine.InvalidateBuffer(buf)
|
|
}
|
|
}
|
|
|
|
engine.PrepareBuffer(buf, editorTheme)
|
|
assertEngineInvariants(t, engine, buf, editorTheme, "initial")
|
|
|
|
for i, op := range tc.opList {
|
|
op(buf, win)
|
|
engine.PrepareBuffer(buf, editorTheme)
|
|
assertEngineInvariants(t, engine, buf, editorTheme, fmt.Sprintf("after op %d", i+1))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func assertEngineInvariants(t *testing.T, engine *TreeSitterEngine, buf *core.Buffer, editorTheme theme.EditorTheme, phase string) {
|
|
t.Helper()
|
|
|
|
bc := engine.getCache(buf)
|
|
if !bc.built {
|
|
t.Fatalf("%s: expected built cache", phase)
|
|
}
|
|
if bc.dirtyAll {
|
|
t.Fatalf("%s: expected dirtyAll=false after prepare", phase)
|
|
}
|
|
if len(bc.dirty) != 0 {
|
|
t.Fatalf("%s: expected no pending dirty ranges", phase)
|
|
}
|
|
|
|
for i := 0; i < buf.LineCount(); i++ {
|
|
line := buf.Line(i)
|
|
m := engine.LineStyleMap(buf, i, editorTheme)
|
|
if len(m) != len([]rune(line)) {
|
|
t.Fatalf("%s: line %d style length mismatch: got %d want %d", phase, i, len(m), len([]rune(line)))
|
|
}
|
|
}
|
|
}
|