v0.3.36 086a9fe

layout.go RawHistoryFolder

1package tui
2
3import "strings"
4
5const (
6	InputStylePlain = "plain"
7	InputStyleLines = "lines"
8	InputStyleBlock = "block"
9
10	StatusPositionAboveInput = "above_input"
11	StatusPositionBelowInput = "below_input"
12
13	WorkingPositionAboveInput = "above_input"
14	WorkingPositionBelowInput = "below_input"
15)
16
17func NormalizeInputStyle(v string) string {
18	switch strings.ToLower(strings.TrimSpace(v)) {
19	case InputStyleLines, "line":
20		return InputStyleLines
21	case InputStyleBlock, "bubble", "boxed", "box":
22		return InputStyleBlock
23	default:
24		return InputStylePlain
25	}
26}
27
28func NormalizeStatusPosition(v string) string {
29	switch strings.ToLower(strings.TrimSpace(v)) {
30	case StatusPositionBelowInput, "below", "bottom":
31		return StatusPositionBelowInput
32	default:
33		return StatusPositionAboveInput
34	}
35}
36
37func NormalizeWorkingPosition(v string) string {
38	switch strings.ToLower(strings.TrimSpace(v)) {
39	case WorkingPositionBelowInput, "below", "bottom":
40		return WorkingPositionBelowInput
41	default:
42		return WorkingPositionAboveInput
43	}
44}
45
46func InputLines(th Theme, lines []string, width int) []string {
47	if width < 1 {
48		width = 1
49	}
50	rule := th.FG256(th.Muted, strings.Repeat("─", width))
51	out := make([]string, 0, len(lines)+2)
52	out = append(out, rule)
53	out = append(out, lines...)
54	out = append(out, rule)
55	return out
56}
57
58func InputBlock(th Theme, lines []string, width int) []string {
59	if width < 1 {
60		width = 1
61	}
62	bubbleW := width - 2
63	if bubbleW < 1 {
64		bubbleW = 1
65	}
66	row := func(content string) string {
67		visible := visibleWidth(content)
68		if visible < bubbleW {
69			content += strings.Repeat(" ", bubbleW-visible)
70		}
71		bg := sgrBGColor(th.UserBubbleBG)
72		bar := bg + th.FG256(th.Accent, "▌ ")
73		body := bg + strings.ReplaceAll(content, reset, reset+bg) + reset
74		return bar + body
75	}
76	out := make([]string, 0, len(lines)+2)
77	out = append(out, row(""))
78	for _, line := range lines {
79		out = append(out, row(line))
80	}
81	out = append(out, row(""))
82	return out
83}
84
85func CursorColor256(index int) string {
86	r, g, b := xterm256RGB(index)
87	return "\x1b]12;rgb:" + hexByte(r) + "/" + hexByte(g) + "/" + hexByte(b) + "\x07"
88}
89
90func ResetCursorColor() string { return "\x1b]112\x07" }
91
92func CursorShapeBlock() string { return "\x1b[1 q" }
93
94func ResetCursorShape() string { return "\x1b[0 q" }
95
96func xterm256RGB(index int) (int, int, int) {
97	if index < 0 {
98		index = 0
99	}
100	if index > 255 {
101		index = 255
102	}
103	ansi := [16][3]int{
104		{0, 0, 0}, {128, 0, 0}, {0, 128, 0}, {128, 128, 0},
105		{0, 0, 128}, {128, 0, 128}, {0, 128, 128}, {192, 192, 192},
106		{128, 128, 128}, {255, 0, 0}, {0, 255, 0}, {255, 255, 0},
107		{0, 0, 255}, {255, 0, 255}, {0, 255, 255}, {255, 255, 255},
108	}
109	if index < 16 {
110		c := ansi[index]
111		return c[0], c[1], c[2]
112	}
113	if index < 232 {
114		idx := index - 16
115		levels := [6]int{0, 95, 135, 175, 215, 255}
116		return levels[idx/36], levels[(idx/6)%6], levels[idx%6]
117	}
118	gray := 8 + (index-232)*10
119	return gray, gray, gray
120}
121
122func hexByte(v int) string {
123	const digits = "0123456789abcdef"
124	if v < 0 {
125		v = 0
126	}
127	if v > 255 {
128		v = 255
129	}
130	return string([]byte{digits[v>>4], digits[v&0xf]})
131}

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