navigator_test.go RawHistoryFolder

1package copy
2
3import (
4	"testing"
5
6	renderer "github.com/bnema/vev-vt"
7	"github.com/stretchr/testify/require"
8)
9
10func navigatorDocument() *Document {
11	return NewDocument(NewSnapshotFromRows([][]renderer.Cell{
12		documentCells("abcdef"),
13		documentCells("xy"),
14		{{Rune: '界'}, {Continuation: true}, {Rune: 'z'}},
15		{},
16		documentCells("omega"),
17	}, 6, 2), " -_@")
18}
19
20func TestNavigatorHorizontalSkipsContinuations(t *testing.T) {
21	doc := navigatorDocument()
22
23	tests := []struct {
24		name string
25		move func(*Navigator, *Document) bool
26		from Pos
27		want Pos
28	}{
29		{"right skips wide continuation", (*Navigator).Right, Pos{Row: 2, Col: 0}, Pos{Row: 2, Col: 2}},
30		{"left skips wide continuation", (*Navigator).Left, Pos{Row: 2, Col: 2}, Pos{Row: 2, Col: 0}},
31	}
32	for _, tt := range tests {
33		t.Run(tt.name, func(t *testing.T) {
34			navigator := NewNavigator(tt.from)
35
36			require.True(t, tt.move(&navigator, doc))
37			require.Equal(t, tt.want, navigator.Pos)
38			require.Equal(t, tt.want.Col, navigator.PreferredCol)
39		})
40	}
41}
42
43func TestNavigatorVerticalRetainsPreferredColumn(t *testing.T) {
44	doc := navigatorDocument()
45	navigator := NewNavigator(Pos{Row: 0, Col: 5})
46
47	require.True(t, navigator.Down(doc))
48	require.Equal(t, Pos{Row: 1, Col: 1}, navigator.Pos)
49	require.Equal(t, 5, navigator.PreferredCol)
50
51	require.True(t, navigator.Down(doc))
52	require.Equal(t, Pos{Row: 2, Col: 2}, navigator.Pos)
53	require.Equal(t, 5, navigator.PreferredCol)
54
55	require.True(t, navigator.Down(doc))
56	require.Equal(t, Pos{Row: 3, Col: 0}, navigator.Pos)
57	require.Equal(t, 5, navigator.PreferredCol)
58
59	require.True(t, navigator.Down(doc))
60	require.Equal(t, Pos{Row: 4, Col: 4}, navigator.Pos)
61	require.Equal(t, 5, navigator.PreferredCol)
62
63	require.True(t, navigator.Up(doc))
64	require.Equal(t, Pos{Row: 3, Col: 0}, navigator.Pos)
65	require.Equal(t, 5, navigator.PreferredCol)
66
67	require.True(t, navigator.Up(doc))
68	require.Equal(t, Pos{Row: 2, Col: 2}, navigator.Pos)
69	require.Equal(t, 5, navigator.PreferredCol)
70}
71
72func TestNavigatorWordMotionsCrossRows(t *testing.T) {
73	doc := navigatorDocument()
74
75	tests := []struct {
76		name string
77		move func(*Navigator, *Document) bool
78		from Pos
79		want Pos
80	}{
81		{"word next", (*Navigator).WordNext, Pos{Row: 0, Col: 5}, Pos{Row: 1, Col: 0}},
82		{"word backward", (*Navigator).WordBackward, Pos{Row: 1, Col: 0}, Pos{Row: 0, Col: 0}},
83		{"word end", (*Navigator).WordEnd, Pos{Row: 1, Col: 1}, Pos{Row: 2, Col: 2}},
84	}
85	for _, tt := range tests {
86		t.Run(tt.name, func(t *testing.T) {
87			navigator := NewNavigator(tt.from)
88
89			require.True(t, tt.move(&navigator, doc))
90			require.Equal(t, tt.want, navigator.Pos)
91			require.Equal(t, tt.want.Col, navigator.PreferredCol)
92		})
93	}
94}
95
96func TestNavigatorEmptyTopBottomPageAndSet(t *testing.T) {
97	doc := navigatorDocument()
98
99	t.Run("empty row is stable", func(t *testing.T) {
100		navigator := NewNavigator(Pos{Row: 2, Col: 2})
101		require.True(t, navigator.Down(doc))
102		require.Equal(t, Pos{Row: 3, Col: 0}, navigator.Pos)
103		require.False(t, navigator.Right(doc))
104		require.Equal(t, Pos{Row: 3, Col: 0}, navigator.Pos)
105	})
106
107	t.Run("top and bottom reset the preferred column", func(t *testing.T) {
108		navigator := NewNavigator(Pos{Row: 0, Col: 5})
109		require.True(t, navigator.Down(doc))
110		require.Equal(t, Pos{Row: 1, Col: 1}, navigator.Pos)
111		require.Equal(t, 5, navigator.PreferredCol)
112		require.True(t, navigator.Top(doc))
113		require.Equal(t, Pos{Row: 0, Col: 1}, navigator.Pos)
114		require.Equal(t, 1, navigator.PreferredCol)
115		require.True(t, navigator.Bottom(doc))
116		require.Equal(t, Pos{Row: 4, Col: 1}, navigator.Pos)
117		require.Equal(t, 1, navigator.PreferredCol)
118	})
119
120	t.Run("page keeps preferred column", func(t *testing.T) {
121		navigator := NewNavigator(Pos{Row: 0, Col: 5})
122		require.True(t, navigator.Page(doc, 2))
123		require.Equal(t, Pos{Row: 2, Col: 2}, navigator.Pos)
124		require.Equal(t, 5, navigator.PreferredCol)
125		require.True(t, navigator.Page(doc, 2))
126		require.Equal(t, Pos{Row: 4, Col: 4}, navigator.Pos)
127		require.Equal(t, 5, navigator.PreferredCol)
128	})
129
130	t.Run("set normalizes continuation and updates preferred column", func(t *testing.T) {
131		navigator := NewNavigator(Pos{Row: 0, Col: 0})
132		require.True(t, navigator.Set(doc, Pos{Row: 2, Col: 1}))
133		require.Equal(t, Pos{Row: 2, Col: 0}, navigator.Pos)
134		require.Equal(t, 0, navigator.PreferredCol)
135		require.False(t, navigator.Set(doc, Pos{Row: 9, Col: 0}))
136		require.Equal(t, Pos{Row: 2, Col: 0}, navigator.Pos)
137	})
138}

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