detached fdd661a

layout_policy_test.go RawHistoryFolder

1package core
2
3import "testing"
4
5func TestWorkspaceStepFollowsWorkspaceAxis(t *testing.T) {
6	for _, tc := range []struct {
7		name       string
8		overflow   Overflow
9		vertical   int
10		horizontal int
11	}{
12		{"scroll", OverflowScroll, 1, 0},
13		{"fixed", OverflowFixed, 1, 0},
14		{"cascade", OverflowCascade, 0, 1},
15	} {
16		t.Run(tc.name, func(t *testing.T) {
17			w := &Workspace{Overflow: tc.overflow}
18			p := w.policy()
19			for _, dir := range []int{-1, 1} {
20				if got := p.workspaceStep(verticalAxis, dir); got != dir*tc.vertical {
21					t.Errorf("vertical step %d = %d, want %d", dir, got, dir*tc.vertical)
22				}
23				if got := p.workspaceStep(horizontalAxis, dir); got != dir*tc.horizontal {
24					t.Errorf("horizontal step %d = %d, want %d", dir, got, dir*tc.horizontal)
25				}
26			}
27		})
28	}
29}
30
31// oldValidSpans is the reference implementation validSpans must match.
32func oldValidSpans(w *Workspace, first, last int) bool {
33	if first > last || w.Overflow == OverflowFixed && !w.laneRow() {
34		return false
35	}
36	stamp := w.Columns[first].spanStamp
37	if stamp == 0 {
38		return false
39	}
40	total, count := 0, 0
41	for i := first; i <= last; i++ {
42		if w.Columns[i].Span <= 0 || w.Columns[i].spanStamp != stamp {
43			return false
44		}
45		total += w.Columns[i].Span
46	}
47	for _, c := range w.Columns {
48		if c.spanStamp == stamp {
49			count++
50		}
51	}
52	return count == last-first+1 && (!w.policy().equalCells || total == 10000)
53}
54
55func TestScrollWidthsMatchPerColumnValidation(t *testing.T) {
56	for _, n := range []int{1, 2, 5, 9} {
57		for _, state := range []string{"unstamped", "stamped", "stale", "foreign", "zero"} {
58			w := spanWorkspace(OverflowScroll, n)
59			switch state {
60			case "stamped":
61				stampSpans(w, 0, n-1)
62			case "stale":
63				stampSpans(w, 0, n-1)
64				w.Columns[n-1].spanStamp = 99
65			case "foreign":
66				stampSpans(w, 0, n-1)
67				w.Columns = append(w.Columns, Column{Windows: []WindowID{100}, Span: 5, spanStamp: w.Columns[0].spanStamp})
68			case "zero":
69				stampSpans(w, 0, n-1)
70				w.Columns[0].Span = 0
71			}
72			last := len(w.Columns) - 1
73			if got, want := w.validSpans(0, last), oldValidSpans(w, 0, last); got != want {
74				t.Fatal(n, state, got, want)
75			}
76			valid := w.scrollSpansValid()
77			xs, widths := w.columnEdges()
78			rs := w.columnRects()
79			for i := range w.Columns {
80				if widths[i] != w.scrollWidth(i, oldValidSpans(w, 0, last)) || valid != oldValidSpans(w, 0, last) {
81					t.Fatal(n, state, i, "width")
82				}
83				if xs[i] != w.columnX(i) || widths[i] != w.columnWidth(i) || rs[i].W != widths[i] {
84					t.Fatal(n, state, i, "edges")
85				}
86			}
87		}
88	}
89}
90
91func TestDropStaleSpansKeepsValidLanes(t *testing.T) {
92	w := spanWorkspace(OverflowScroll, 4)
93	// An unstamped workspace returns before any lane is measured.
94	if n := testing.AllocsPerRun(10, w.dropStaleSpans); n != 0 {
95		t.Fatalf("unstamped workspace allocates %v", n)
96	}
97	if w.Columns[0].Span != 0 || w.Columns[0].spanStamp != 0 {
98		t.Fatal("unstamped workspace changed")
99	}
100	stampSpans(w, 0, 3)
101	spans := []int{w.Columns[0].Span, w.Columns[3].Span}
102	if n := testing.AllocsPerRun(10, w.dropStaleSpans); n != 0 {
103		t.Fatalf("valid lane allocates %v", n)
104	}
105	if w.Columns[0].Span != spans[0] || w.Columns[3].Span != spans[1] {
106		t.Fatal("valid lane dropped")
107	}
108	w.Columns[2].spanStamp = 77
109	w.dropStaleSpans()
110	for i, c := range w.Columns {
111		if c.Span != 0 || c.spanStamp != 0 {
112			t.Fatal("stale lane kept", i)
113		}
114	}
115}
116
117// TestColumnEdgesMatchColumnRects checks columnEdges against columnRects, an
118// independent path that builds the same row with the view shift applied.
119func TestColumnEdgesMatchColumnRects(t *testing.T) {
120	for _, tc := range []struct {
121		name  string
122		mode  Overflow
123		setup func(w *Workspace)
124		// xs is compared where the rects keep the row's x (not cascade bands,
125		// nor the focused maximized column of fixed overflow).
126		xs bool
127	}{
128		{"scroll plain", OverflowScroll, func(w *Workspace) {}, true},
129		{"scroll stamped", OverflowScroll, func(w *Workspace) { stampSpans(w, 0, len(w.Columns)-1) }, true},
130		{"scroll full width", OverflowScroll, func(w *Workspace) { w.Columns[1].FullWidth = true }, true},
131		{"scroll fullscreen", OverflowScroll, func(w *Workspace) { w.SetFullscreen(w.Columns[2].Windows[0], true) }, true},
132		{"scroll viewed", OverflowScroll, func(w *Workspace) { w.View = 137 }, true},
133		{"fixed", OverflowFixed, func(w *Workspace) {}, true},
134		{"fixed full width", OverflowFixed, func(w *Workspace) { w.Columns[1].FullWidth = true; w.Focus = 0 }, true},
135		{"fixed focused full width", OverflowFixed, func(w *Workspace) { w.Columns[1].FullWidth = true; w.Focus = 1 }, false},
136		{"fixed fullscreen", OverflowFixed, func(w *Workspace) { w.SetFullscreen(w.Columns[2].Windows[0], true) }, true},
137		{"fixed stamped", OverflowFixed, func(w *Workspace) { stampSpans(w, 0, len(w.Columns)-1) }, true},
138		{"cascade", OverflowCascade, func(w *Workspace) {}, false},
139		{"cascade full width", OverflowCascade, func(w *Workspace) { w.Columns[1].FullWidth = true }, false},
140		{"cascade stamped", OverflowCascade, func(w *Workspace) { stampSpans(w, 0, len(w.Columns)-1) }, false},
141	} {
142		t.Run(tc.name, func(t *testing.T) {
143			w := spanWorkspace(tc.mode, 3)
144			tc.setup(w)
145			if tc.mode != OverflowScroll && w.scrollSpansValid() {
146				t.Fatal("equal-cell workspace must not take the scroll span path")
147			}
148			xs, ws := w.columnEdges()
149			rs := w.columnRectsAt(nil, false, 0)
150			if len(xs) != len(rs) || len(ws) != len(rs) {
151				t.Fatal("length", len(xs), len(ws), len(rs))
152			}
153			for i, r := range rs {
154				if ws[i] != r.W {
155					t.Errorf("column %d width %d, rect %d", i, ws[i], r.W)
156				}
157				if tc.xs && xs[i] != r.X+w.View {
158					t.Errorf("column %d x %d, rect %d + view %d", i, xs[i], r.X, w.View)
159				}
160			}
161		})
162	}
163}

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 23

Tags 10

↑↓ moveenter openesc close