capabilities.go RawHistoryFolder

1// Package terminalcap owns pure terminal capability values and detection policy.
2package terminalcap
3
4import "strings"
5
6// ColorMode is the color output mode selected for one attachment.
7type ColorMode uint8
8
9const (
10	// TrueColor is the zero value so manually constructed attachments retain the
11	// historical renderer behavior; live Hello paths always use the detector.
12	TrueColor ColorMode = iota
13	Indexed256
14)
15
16// Source records how confidently a terminal capability was selected.
17type Source uint8
18
19const (
20	SourceUnknown Source = iota
21	SourceHeuristic
22	SourceDeclared
23)
24
25// Application identifies a known terminal application when its environment
26// provides a trustworthy origin signal.
27type Application uint8
28
29const (
30	ApplicationUnknown Application = iota
31	ApplicationKitty
32)
33
34// Capabilities describes the output features selected for one client attachment.
35type Capabilities struct {
36	ColorMode     ColorMode
37	ColorSource   Source
38	Application   Application
39	KittyGraphics bool
40}
41
42// SupportsKittyGraphics reports whether the active outer-terminal probe
43// accepted the Kitty graphics protocol. Environment detection never sets it.
44func (c Capabilities) SupportsKittyGraphics() bool { return c.KittyGraphics }
45
46// TrueColor reports whether this attachment can receive RGB ANSI output.
47func (c Capabilities) TrueColor() bool { return c.ColorMode == TrueColor }
48
49// Detect derives conservative attachment capabilities from a client environment.
50func Detect(env []string) Capabilities {
51	values := environmentValues(env)
52	term := strings.ToLower(strings.TrimSpace(values["TERM"]))
53	colorTerm := strings.ToLower(strings.TrimSpace(values["COLORTERM"]))
54	caps := Capabilities{ColorMode: Indexed256}
55
56	if values["KITTY_WINDOW_ID"] != "" || values["KITTY_PID"] != "" || values["KITTY_LISTEN_ON"] != "" {
57		caps.Application = ApplicationKitty
58	}
59
60	kittyIdentity := term == "xterm-kitty" && caps.Application == ApplicationKitty
61	switch colorTerm {
62	case "truecolor", "24bit":
63		caps.ColorMode = TrueColor
64		caps.ColorSource = SourceDeclared
65	}
66	if term == "xterm-direct" || strings.HasSuffix(term, "-direct") {
67		caps.ColorMode = TrueColor
68		caps.ColorSource = SourceDeclared
69	}
70	if kittyIdentity {
71		if caps.ColorSource == SourceUnknown {
72			caps.ColorSource = SourceHeuristic
73		}
74		caps.ColorMode = TrueColor
75		return caps
76	}
77	if caps.ColorSource == SourceDeclared {
78		return caps
79	}
80	if strings.Contains(term, "256color") || term == "dumb" {
81		caps.ColorSource = SourceDeclared
82	}
83	return caps
84}
85
86func environmentValues(env []string) map[string]string {
87	values := make(map[string]string, len(env))
88	for _, entry := range env {
89		key, value, ok := strings.Cut(entry, "=")
90		if ok {
91			values[key] = value
92		}
93	}
94	return values
95}
96
97// DetectTrueColor reports whether the supplied terminal environment advertises
98// direct color support. Explicit TERM/COLORTERM values override env entries.
99func DetectTrueColor(termEnv, colorTerm string, env []string) bool {
100	detectionEnv := make([]string, 0, len(env)+2)
101	detectionEnv = append(detectionEnv, env...)
102	detectionEnv = append(detectionEnv, "TERM="+termEnv, "COLORTERM="+colorTerm)
103	return Detect(detectionEnv).TrueColor()
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 12

Tags 11

↑↓ moveenter openesc close