v0.5.1 8e4df5c

scroll_down_test.go RawHistoryFolder

1package ansi_test
2
3import (
4	"bytes"
5	"testing"
6
7	vt "github.com/bnema/vev-vt"
8	"github.com/bnema/vev-vt/ansi"
9)
10
11func TestBidirectionalScrollReplay(t *testing.T) {
12	for _, down := range []bool{false, true} {
13		for _, count := range []int{1, 3} {
14			frame := vt.NewFrame(12, 10)
15			for y := range frame.Height {
16				frame.FillRow(y, 0, frame.Width, vt.Cell{Rune: rune('a' + y), Style: vt.Style{Foreground: y, Background: -1}})
17			}
18			r := ansi.New(ansi.Capabilities{})
19			terminal := vt.NewScreen(frame.Width, frame.Height)
20			initial, err := r.Draw(frame, nil)
21			if err != nil {
22				t.Fatal(err)
23			}
24			terminal.Write(initial)
25			kind, exposed := vt.DamageScrollUp, 8-count
26			if down {
27				kind, exposed = vt.DamageScrollDown, 2
28				frame.ScrollDown(2, 7, count)
29			} else {
30				frame.ScrollUp(2, 7, count)
31			}
32			for y := exposed; y < exposed+count; y++ {
33				frame.FillRow(y, 0, frame.Width, vt.Cell{Rune: 'X', Style: vt.DefaultStyle()})
34			}
35			damage := []vt.Damage{
36				{Kind: kind, Y: 2, Width: 12, Height: 6, Count: count},
37				{Kind: vt.DamageText, Y: exposed, Width: 12, Height: count},
38			}
39			prepared, err := r.Prepare(frame, damage, false)
40			if err != nil {
41				t.Fatal(err)
42			}
43			if !bytes.Contains(prepared.Bytes(), []byte("\x1b[3;8r")) {
44				t.Fatalf("missing scroll region: %q", prepared.Bytes())
45			}
46			terminal.Write(prepared.Bytes())
47			prepared.Commit()
48			for y := range frame.Height {
49				for x := range frame.Width {
50					if !frame.Cell(x, y).Equal(terminal.Cell(x, y)) {
51						t.Fatalf("down=%v count=%d cell %d,%d mismatch", down, count, x, y)
52					}
53				}
54			}
55			if err := frame.CheckInvariants(); err != nil {
56				t.Fatal(err)
57			}
58			unchanged, err := r.Draw(frame, nil)
59			if err != nil || len(unchanged) != 0 {
60				t.Fatalf("committed shadow differs: %q, %v", unchanged, err)
61			}
62		}
63	}
64}
65
66func TestDownwardScrollMismatchFallsBack(t *testing.T) {
67	committed := vt.NewFrame(10, 8)
68	frame := committed.Clone()
69	frame.Set(0, 4, vt.Cell{Rune: 'X', Style: vt.DefaultStyle()})
70	for _, width := range []int{9, 10} {
71		candidate, err := ansi.PlanDelta(frame, []vt.Damage{{Kind: vt.DamageScrollDown, Y: 1, Width: width, Height: 6, Count: 1}}, committed, false)
72		if err != nil {
73			t.Fatal(err)
74		}
75		if !candidate.Plan.Snapshot || candidate.Plan.Scroll.Height != 0 {
76			t.Fatalf("unsafe scroll accepted: %+v", candidate.Plan)
77		}
78	}
79}

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