v0.1.0 7deb448

damage_plan_test.go RawHistoryFolder

1package renderer
2
3import (
4	"math"
5	"reflect"
6	"testing"
7)
8
9func TestBuildDamagePlan(t *testing.T) {
10	tests := []struct {
11		name   string
12		frame  Frame
13		damage []Damage
14		want   []damageSpan
15		full   bool
16	}{
17		{
18			name:  "merges reverse overlaps",
19			frame: NewFrame(10, 2),
20			damage: []Damage{
21				{Kind: DamageText, X: 4, Y: 0, Width: 5, Height: 1},
22				{Kind: DamageText, X: 0, Y: 0, Width: 5, Height: 1},
23			},
24			want: []damageSpan{{y: 0, x: 0, width: 9}},
25		},
26		{
27			name:  "merges text and clear",
28			frame: NewFrame(10, 1),
29			damage: []Damage{
30				{Kind: DamageClear, X: 5, Y: 0, Width: 4, Height: 1},
31				{Kind: DamageText, X: 0, Y: 0, Width: 5, Height: 1},
32			},
33			want: []damageSpan{{y: 0, x: 0, width: 9}},
34		},
35		{
36			name:  "orders multi-row spans",
37			frame: NewFrame(10, 3),
38			damage: []Damage{
39				{Kind: DamageText, X: 5, Y: 2, Width: 2, Height: 1},
40				{Kind: DamageText, X: 4, Y: 0, Width: 2, Height: 2},
41				{Kind: DamageText, X: 1, Y: 0, Width: 2, Height: 2},
42				{Kind: DamageScrollUp, X: 0, Y: 0, Width: 10, Height: 3, Count: 1},
43			},
44			want: []damageSpan{
45				{y: 0, x: 1, width: 2}, {y: 0, x: 4, width: 2},
46				{y: 1, x: 1, width: 2}, {y: 1, x: 4, width: 2},
47				{y: 2, x: 5, width: 2},
48			},
49		},
50		{
51			name:  "clamps rectangles",
52			frame: NewFrame(10, 3),
53			damage: []Damage{
54				{Kind: DamageText, X: -2, Y: -1, Width: 5, Height: 3},
55				{Kind: DamageClear, X: 8, Y: 1, Width: 5, Height: 3},
56			},
57			want: []damageSpan{{y: 0, x: 0, width: 3}, {y: 1, x: 0, width: 3}, {y: 1, x: 8, width: 2}, {y: 2, x: 8, width: 2}},
58		},
59		{
60			name:  "does not mutate input",
61			frame: NewFrame(10, 2),
62			damage: []Damage{
63				{Kind: DamageText, X: 5, Y: 1, Width: 2, Height: 1},
64				{Kind: DamageText, X: 1, Y: 0, Width: 2, Height: 1},
65			},
66			want: []damageSpan{{y: 0, x: 1, width: 2}, {y: 1, x: 5, width: 2}},
67		},
68		{
69			name:   "exceeding budget requests full redraw",
70			frame:  NewFrame(1, maxPlannedDamageSpans+1),
71			damage: []Damage{{Kind: DamageText, X: 0, Y: 0, Width: 1, Height: maxPlannedDamageSpans + 1}},
72			want:   nil,
73			full:   true,
74		},
75	}
76
77	for _, tt := range tests {
78		t.Run(tt.name, func(t *testing.T) {
79			original := append([]Damage(nil), tt.damage...)
80			got, full := buildDamagePlan(tt.frame, tt.damage, nil)
81			if full != tt.full || !reflect.DeepEqual(got, tt.want) {
82				t.Fatalf("buildDamagePlan() = %#v, full = %v; want %#v, %v", got, full, tt.want, tt.full)
83			}
84			if !reflect.DeepEqual(tt.damage, original) {
85				t.Fatalf("buildDamagePlan mutated damage: got %#v, want %#v", tt.damage, original)
86			}
87		})
88	}
89}
90
91func TestClampRectRejectsOverflowingBounds(t *testing.T) {
92	frame := NewFrame(10, 10)
93	if _, _, _, _, ok := clampRect(frame, math.MaxInt-1, 0, 4, 1); ok {
94		t.Fatal("clampRect accepted overflowing x bound")
95	}
96	if _, _, _, _, ok := clampRect(frame, 0, math.MaxInt-1, 1, 4); ok {
97		t.Fatal("clampRect accepted overflowing y bound")
98	}
99}
100
101func TestSyncRectRejectsOverflowingBounds(t *testing.T) {
102	r := New(Capabilities{})
103	frame := NewFrame(2, 1)
104	r.replaceShadow(frame)
105	before := append([]Cell(nil), r.shadow...)
106	r.syncRect(frame, math.MaxInt-1, 0, 4, 1)
107	if !reflect.DeepEqual(r.shadow, before) {
108		t.Fatal("syncRect changed shadow for overflowing bounds")
109	}
110}

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 12

Tags 11

↑↓ moveenter openesc close