v0.5.0 31affde

style_test.go RawHistoryFolder

1package core
2
3import (
4	"testing"
5	"testing/quick"
6)
7
8func TestStyleCanonicalClearsInactiveColorPayloads(t *testing.T) {
9	style := Style{
10		Foreground:           7,
11		Background:           8,
12		HasForegroundRGB:     true,
13		ForegroundRGB:        RGB{R: 1, G: 2, B: 3},
14		BackgroundRGB:        RGB{R: 4, G: 5, B: 6},
15		UnderlineColor:       9,
16		UnderlineColorRGB:    RGB{R: 7, G: 8, B: 9},
17		HasUnderlineColorRGB: true,
18	}
19
20	got := style.Canonical()
21	if got.Foreground != 0 {
22		t.Fatalf("inactive indexed foreground = %d, want 0", got.Foreground)
23	}
24	if got.BackgroundRGB != (RGB{}) {
25		t.Fatalf("inactive RGB background = %+v, want zero", got.BackgroundRGB)
26	}
27	if got.UnderlineColor != 0 || got.HasUnderlineColor {
28		t.Fatalf("inactive indexed underline = (%d, %t), want zero and false", got.UnderlineColor, got.HasUnderlineColor)
29	}
30}
31
32func TestStyleCanonicalCollapsesEveryInactiveVariant(t *testing.T) {
33	tests := []struct {
34		name  string
35		left  Style
36		right Style
37	}{
38		{
39			name: "indexed colors ignore RGB payloads and absent underline payloads",
40			left: Style{Foreground: 1, Background: 2},
41			right: Style{
42				Foreground:        1,
43				ForegroundRGB:     RGB{R: 1, G: 2, B: 3},
44				Background:        2,
45				BackgroundRGB:     RGB{R: 4, G: 5, B: 6},
46				UnderlineColor:    3,
47				UnderlineColorRGB: RGB{R: 7, G: 8, B: 9},
48			},
49		},
50		{
51			name: "RGB colors ignore indexed payloads",
52			left: Style{
53				HasForegroundRGB:     true,
54				ForegroundRGB:        RGB{R: 1, G: 2, B: 3},
55				HasBackgroundRGB:     true,
56				BackgroundRGB:        RGB{R: 4, G: 5, B: 6},
57				HasUnderlineColorRGB: true,
58				UnderlineColorRGB:    RGB{R: 7, G: 8, B: 9},
59			},
60			right: Style{
61				Foreground:           1,
62				Background:           2,
63				HasForegroundRGB:     true,
64				ForegroundRGB:        RGB{R: 1, G: 2, B: 3},
65				HasBackgroundRGB:     true,
66				BackgroundRGB:        RGB{R: 4, G: 5, B: 6},
67				HasUnderlineColor:    true,
68				UnderlineColor:       3,
69				HasUnderlineColorRGB: true,
70				UnderlineColorRGB:    RGB{R: 7, G: 8, B: 9},
71			},
72		},
73	}
74
75	for _, test := range tests {
76		t.Run(test.name, func(t *testing.T) {
77			if !test.left.Equal(test.right) {
78				t.Fatal("fixture styles must be semantically equal")
79			}
80			if test.left.Canonical() != test.right.Canonical() {
81				t.Fatalf("canonical styles differ: %+v != %+v", test.left.Canonical(), test.right.Canonical())
82			}
83		})
84	}
85}
86
87func TestStyleCanonicalExactlyMatchesEqual(t *testing.T) {
88	property := func(a, b Style) bool {
89		return a.Equal(b) == (a.Canonical() == b.Canonical())
90	}
91	if err := quick.Check(property, &quick.Config{MaxCount: 10_000}); err != nil {
92		t.Fatal(err)
93	}
94}
95
96func TestStyleCanonicalIsIdempotent(t *testing.T) {
97	property := func(style Style) bool {
98		canonical := style.Canonical()
99		return canonical.Canonical() == canonical
100	}
101	if err := quick.Check(property, &quick.Config{MaxCount: 10_000}); err != nil {
102		t.Fatal(err)
103	}
104}
105
106func TestZeroAndDefaultStylesRemainDistinct(t *testing.T) {
107	zero := Style{}
108	defaultStyle := DefaultStyle()
109	if zero.Equal(defaultStyle) {
110		t.Fatal("zero Style unexpectedly equals DefaultStyle")
111	}
112	if zero.Canonical() == defaultStyle.Canonical() {
113		t.Fatal("canonicalization collapsed indexed color zero into unset default colors")
114	}
115}

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