1package ansi_test
2
3import (
4 "testing"
5
6 vt "github.com/bnema/vev-vt"
7 "github.com/bnema/vev-vt/ansi"
8 core "github.com/bnema/vev-vt/core"
9)
10
11// Two scroll regions in one damage batch cannot be expressed as one scroll
12// plus text spans; the renderer must still reproduce the source exactly.
13func TestTwoScrollRegionsInOneBatchReplayExactly(t *testing.T) {
14 for _, sourceKind := range []string{"screen", "frame", "pointer"} {
15 t.Run(sourceKind, func(t *testing.T) {
16 s := vt.NewScreen(10, 8)
17 s.Write([]byte("\x1b[1;1Ha0\r\na1\r\na2\r\na3\r\nb4\r\nb5\r\nb6\r\nb7"))
18 r := ansi.New(ansi.Capabilities{})
19 replay := vt.NewScreen(10, 8)
20 draw := func() {
21 var source core.CellSource = s
22 if sourceKind != "screen" {
23 frame := core.NewFrame(10, 8)
24 for y := range 8 {
25 for x := range 10 {
26 frame.Set(x, y, s.Cell(x, y))
27 }
28 }
29 source = frame
30 if sourceKind == "pointer" {
31 source = &frame
32 }
33 }
34 prepared, err := r.Prepare(source, s.Damage(), false)
35 if err != nil {
36 t.Fatal(err)
37 }
38 prepared.Commit()
39 replay.Write(prepared.Bytes())
40 s.ClearDamage()
41 }
42 draw()
43 s.Write([]byte("\x1b[1;4r\x1b[4;1H\nX\x1b[5;8r\x1b[8;1H\n\nY\x1b[r"))
44 draw()
45 requireReplayMatches(t, s, replay)
46 })
47 }
48}
49
50// Text damage recorded before a scroll can start on the right half of a wide
51// rune that the scroll moved there; the renderer must repaint the rune.
52func TestSpanStartingOnWideContinuationRepaintsHead(t *testing.T) {
53 s := vt.NewScreen(6, 3)
54 r := ansi.New(ansi.Capabilities{})
55 replay := vt.NewScreen(6, 3)
56 draw := func() {
57 prepared, err := r.Prepare(s, s.Damage(), false)
58 if err != nil {
59 t.Fatal(err)
60 }
61 prepared.Commit()
62 replay.Write(prepared.Bytes())
63 s.ClearDamage()
64 }
65 draw()
66 s.Write([]byte("\x1b[2;1H界"))
67 draw()
68 s.Write([]byte("\x1b[1;2Hab\x1b[1;2r\x1b[2;1H\n\x1b[r"))
69 draw()
70 requireReplayMatches(t, s, replay)
71}
72
73func requireReplayMatches(t *testing.T, source, replay *vt.Screen) {
74 t.Helper()
75 for y := range source.Rows() {
76 for x := range source.Columns() {
77 want, got := source.Cell(x, y), replay.Cell(x, y)
78 if want.Rune != got.Rune || want.Continuation != got.Continuation || !want.Style.Equal(got.Style) {
79 t.Fatalf("cell (%d,%d) = %+v, want %+v", x, y, got, want)
80 }
81 }
82 }
83}