main 7a3b92c

app_test.go RawHistoryFolder

1package app
2
3import (
4	"encoding/binary"
5	"testing"
6)
7
8func state(vals ...uint32) []byte {
9	var b []byte
10	for _, v := range vals {
11		b = binary.NativeEndian.AppendUint32(b, v)
12	}
13	return b
14}
15
16// open maps a window: its properties and its state, then the done that applies them.
17func open(t *Tracker, h uint32, id, title string, st ...uint32) {
18	t.ID(h, id)
19	t.Title(h, title)
20	t.State(h, state(st...))
21	t.Done(h)
22}
23
24func TestNothingFocusedIsTheZeroWindow(t *testing.T) {
25	tr := NewTracker()
26	if tr.Focused() != (Window{}) {
27		t.Fatal("an empty tracker must have no focus")
28	}
29	open(tr, 1, "a", "A") // mapped, not activated
30	if tr.Focused() != (Window{}) {
31		t.Fatalf("a window without the activated state has no focus: %+v", tr.Focused())
32	}
33}
34
35func TestFocusFollowsTheActivatedState(t *testing.T) {
36	tr := NewTracker()
37	open(tr, 1, "org.mozilla.firefox", "Docs", 0, stateActivated) // maximized + activated
38	open(tr, 2, "kitty", "~")
39	if got := tr.Focused(); got != (Window{"org.mozilla.firefox", "Docs"}) {
40		t.Fatalf("focused = %+v", got)
41	}
42	// Focus moves: 1 loses it, 2 gets it.
43	open(tr, 1, "org.mozilla.firefox", "Docs", 0)
44	open(tr, 2, "kitty", "~", stateActivated)
45	if got := tr.Focused(); got != (Window{"kitty", "~"}) {
46		t.Fatalf("after the focus moved: %+v", got)
47	}
48}
49
50func TestATitleChangeAppliesOnlyAtDone(t *testing.T) {
51	tr := NewTracker()
52	open(tr, 1, "kitty", "one", stateActivated)
53	tr.Title(1, "two")
54	if got := tr.Focused().Title; got != "one" {
55		t.Fatalf("title changed before done: %q", got)
56	}
57	tr.Done(1)
58	if got := tr.Focused().Title; got != "two" {
59		t.Fatalf("title after done: %q", got)
60	}
61}
62
63func TestClosingTheFocusedWindowClearsTheFocus(t *testing.T) {
64	tr := NewTracker()
65	open(tr, 1, "kitty", "~", stateActivated)
66	tr.Closed(1)
67	if tr.Focused() != (Window{}) {
68		t.Fatalf("a closed window still has the focus: %+v", tr.Focused())
69	}
70}
71
72func TestTheWindowThatGotTheFocusLastWins(t *testing.T) {
73	tr := NewTracker()
74	open(tr, 1, "a", "A", stateActivated)
75	open(tr, 2, "b", "B", stateActivated) // two seats, two focused windows
76	if got := tr.Focused().ID; got != "b" {
77		t.Fatalf("focused = %q, want b (the newest)", got)
78	}
79	open(tr, 1, "a", "A2", stateActivated) // still active, only its title changed
80	if got := tr.Focused().ID; got != "b" {
81		t.Fatalf("a title change must not steal the focus: %q", got)
82	}
83}
84
85func TestCleanRemovesControlCharacters(t *testing.T) {
86	in := "fire\x1b[2Jfox\n\ttab\x07 ok \u00e9"
87	if got, want := Clean(in), "fire[2Jfoxtab ok \u00e9"; got != want {
88		t.Fatalf("Clean = %q, want %q", got, want)
89	}
90}
91
92func TestNameIsTheLastPartOfTheID(t *testing.T) {
93	for id, want := range map[string]string{
94		"com.github.bnema.dumber": "dumber",
95		"org.mozilla.firefox":     "firefox",
96		"kitty":                   "kitty",
97		"":                        "",
98		"trailing.":               "trailing.",
99	} {
100		if got := Name(id); got != want {
101			t.Errorf("Name(%q) = %q, want %q", id, got, want)
102		}
103	}
104}

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 5

Tags 4

↑↓ moveenter openesc close