Gim/internal/syntax/treesitter_sequences_test.go
Hayden Hargreaves 273be90d42 feat: HUGE refactor of colorschemes, untested.
Now we can load them in via JSON files at launch time. They are embded
in the final exe though...
2026-04-08 11:59:49 -07:00

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)))
}
}
}