1package vt
2
3import (
4 "testing"
5
6 renderer "github.com/bnema/vev-vt/ansi"
7)
8
9func TestZshAutosuggestionRepaintEmitsForwardDamage(t *testing.T) {
10 s := NewScreen(20, 2)
11 r := renderer.New(renderer.Capabilities{})
12
13 s.Write([]byte("❯ "))
14 if _, err := r.Draw(s.frame, s.Damage()); err != nil {
15 t.Fatal(err)
16 }
17 s.ClearDamage()
18
19 s.Write([]byte("h"))
20 if _, err := r.Draw(s.frame, s.Damage()); err != nil {
21 t.Fatal(err)
22 }
23 s.ClearDamage()
24
25 s.Write([]byte("\x1b[31mh\x1b[39m"))
26 s.Write([]byte("\x1b[38mello\x1b[39m\r \x1b[31mh\x1b[39m"))
27
28 for y := range s.frame.Height {
29 for x := range s.frame.Width {
30 r := s.frame.At(x, y).Rune
31 if r == '\r' || r == '\n' {
32 t.Fatalf("cell(%d,%d) contains control rune %q", x, y, r)
33 }
34 }
35 }
36
37 out, err := r.Draw(s.frame, s.Damage())
38 if err != nil {
39 t.Fatal(err)
40 }
41 for _, b := range out {
42 if b == '\r' || b == '\n' {
43 t.Fatalf("incremental output contains raw control byte %q: %q", b, string(out))
44 }
45 }
46}
47
48func TestIntegrationScenarios(t *testing.T) {
49 tests := []struct {
50 name string
51 run func(t *testing.T)
52 }{
53 {
54 name: "renderer stays in sync after VT edit damage",
55 run: func(t *testing.T) {
56 s := NewScreen(8, 2)
57 r := renderer.New(renderer.Capabilities{})
58 s.Write([]byte("abcdef"))
59 if _, err := r.Draw(s.frame, s.Damage()); err != nil {
60 t.Fatal(err)
61 }
62 s.ClearDamage()
63
64 s.Write([]byte("\x1b[1;3H\x1b[2@XY"))
65 if _, err := r.Draw(s.frame, s.Damage()); err != nil {
66 t.Fatal(err)
67 }
68 s.ClearDamage()
69
70 out, err := r.Draw(s.frame, nil)
71 if err != nil {
72 t.Fatal(err)
73 }
74 if len(out) != 0 {
75 t.Fatalf("renderer emitted stale follow-up output after VT edit damage: %q", string(out))
76 }
77 },
78 },
79 {
80 name: "DCS sequence terminated by ST is ignored",
81 run: func(t *testing.T) {
82 s := NewScreen(20, 2)
83 s.Write([]byte("\x1bP+q696e646e\x1b\\prompt"))
84
85 assertCell(t, s, 0, 0, 'p')
86 assertCell(t, s, 1, 0, 'r')
87 assertCell(t, s, 2, 0, 'o')
88 assertCell(t, s, 3, 0, 'm')
89 assertCell(t, s, 4, 0, 'p')
90 assertCell(t, s, 5, 0, 't')
91 if s.Col != 6 || s.Row != 0 {
92 t.Errorf("cursor at row=%d col=%d, want row=0 col=6", s.Row, s.Col)
93 }
94 },
95 },
96 {
97 name: "fish-like prompt redraw preserves typed characters",
98 run: func(t *testing.T) {
99 s := NewScreen(10, 2)
100 s.Write([]byte("> "))
101 s.Write([]byte("a\r\x1b[3C"))
102 s.Write([]byte("\x1b[91mb\x1b[39m\x1b[K\r\x1b[4C"))
103
104 assertCell(t, s, 0, 0, '>')
105 assertCell(t, s, 1, 0, ' ')
106 assertCell(t, s, 2, 0, 'a')
107 assertCell(t, s, 3, 0, 'b')
108 if s.Row != 0 || s.Col != 4 {
109 t.Errorf("cursor at row=%d col=%d, want row=0 col=4", s.Row, s.Col)
110 }
111 },
112 },
113 }
114
115 for _, tt := range tests {
116 t.Run(tt.name, tt.run)
117 }
118}