v0.7.1 ff50ee4

scroll_multi_region_test.go RawHistoryFolder

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}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 13

↑↓ moveenter openesc close