v0.24.0 3dbf466

theme_inherited_test.go RawHistoryFolder

1package tui
2
3import (
4	"bytes"
5	"strings"
6	"testing"
7)
8
9func TestDetectTrueColor(t *testing.T) {
10	tests := []struct {
11		name      string
12		term      string
13		colorTerm string
14		want      bool
15	}{
16		{name: "COLORTERM truecolor", term: "screen", colorTerm: "truecolor", want: true},
17		{name: "COLORTERM 24bit", term: "screen", colorTerm: "24bit", want: true},
18		{name: "direct TERM", term: "xterm-direct", want: true},
19		{name: "256 color TERM", term: "xterm-256color", want: false},
20	}
21	for _, tt := range tests {
22		t.Run(tt.name, func(t *testing.T) {
23			if got := DetectTrueColor(tt.term, tt.colorTerm); got != tt.want {
24				t.Fatalf("DetectTrueColor(%q, %q) = %v, want %v", tt.term, tt.colorTerm, got, tt.want)
25			}
26		})
27	}
28}
29
30func TestDetectColorDepth(t *testing.T) {
31	for _, tt := range []struct {
32		term, colorTerm string
33		want            ColorDepth
34	}{
35		{"xterm", "", ColorDepthANSI16},
36		{"xterm-256color", "", ColorDepthIndexed256},
37		{"screen", "truecolor", ColorDepthTrueColor},
38	} {
39		if got := DetectColorDepth(tt.term, tt.colorTerm); got != tt.want {
40			t.Fatalf("DetectColorDepth(%q, %q) = %v, want %v", tt.term, tt.colorTerm, got, tt.want)
41		}
42	}
43}
44
45func terminalTestProfile(depth ColorDepth) TerminalProfile {
46	profile := TerminalProfile{
47		Foreground:    ColorRGB(220, 210, 200),
48		Background:    ColorRGB(12, 18, 24),
49		HasForeground: true,
50		HasBackground: true,
51		Depth:         depth,
52	}
53	profile.Palette[10] = ColorRGB(20, 220, 80)
54	profile.Palette[12] = ColorRGB(40, 100, 240)
55	profile.Palette[13] = ColorRGB(220, 70, 210)
56	profile.PaletteKnown = 1<<10 | 1<<12 | 1<<13
57	return profile
58}
59
60func TestTerminalThemeUsesTerminalDefaultsAndPaletteSlots(t *testing.T) {
61	th := TerminalTheme(terminalTestProfile(ColorDepthTrueColor))
62	if th.Background != nil {
63		t.Fatal("terminal theme painted a full-row background")
64	}
65	if th.FG != TerminalDefault() || th.Accent != TerminalPaletteSlot(12) {
66		t.Fatalf("terminal roles = fg %#v accent %#v", th.FG, th.Accent)
67	}
68	if got := th.FGColor(th.FG, "x"); got != "\x1b[39mx\x1b[0m" {
69		t.Fatalf("default foreground = %q", got)
70	}
71	if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;40;100;240m") {
72		t.Fatalf("accent did not use reported palette: %q", got)
73	}
74}
75
76func TestTerminalThemeUnknownProfileUsesANSI(t *testing.T) {
77	th := TerminalTheme(TerminalProfile{Depth: ColorDepthANSI16})
78	if th.FG == Dark.FG || th.FG == Light.FG {
79		t.Fatal("unknown auto profile selected a fixed built-in theme")
80	}
81	if got := th.FGColor(th.Accent, "x"); got != "\x1b[94mx\x1b[0m" {
82		t.Fatalf("terminal palette fallback = %q", got)
83	}
84}
85
86func TestTerminalPaletteSlotsDoNotAliasExplicitIndexedColors(t *testing.T) {
87	profile := terminalTestProfile(ColorDepthTrueColor)
88	th := TerminalTheme(profile)
89	if got := th.FGColor(TerminalPaletteSlot(12), "x"); !strings.Contains(got, "40;100;240") {
90		t.Fatalf("terminal slot = %q", got)
91	}
92	if got := th.FGColor(Color256(12), "x"); !strings.Contains(got, "0;0;255") {
93		t.Fatalf("explicit xterm index adopted terminal palette: %q", got)
94	}
95}
96
97func TestTerminalThemeRendererInvalidationDoesNotClearScrollback(t *testing.T) {
98	t.Setenv("TERM_PROGRAM", "")
99	var buf bytes.Buffer
100	r := NewRenderer(&buf)
101	r.Resize(20, 2)
102	buf.Reset()
103	r.SetTheme(TerminalTheme(terminalTestProfile(ColorDepthTrueColor)))
104	r.Invalidate()
105	if strings.Contains(buf.String(), SeqClearScrollback) {
106		t.Fatalf("theme invalidation cleared scrollback: %q", buf.String())
107	}
108}

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 1

Tags 476

↑↓ moveenter openesc close