main ab6686c

color_profile.go RawHistoryFolder

1package ansi
2
3// ColorProfile describes the color sequences an output target can represent.
4// The zero value preserves the renderer's historical truecolor behavior.
5type ColorProfile uint8
6
7const (
8	// ColorProfileTrueColor emits direct RGB colors and preserves indexed colors.
9	ColorProfileTrueColor ColorProfile = iota
10	// ColorProfileANSI256 maps RGB colors to the fixed xterm 256-color palette.
11	ColorProfileANSI256
12	// ColorProfileANSI16 emits basic and bright 16-color SGR sequences.
13	ColorProfileANSI16
14	// ColorProfileMonochrome omits explicit colors while preserving attributes.
15	ColorProfileMonochrome
16)
17
18var ansi16Palette = [...]RGB{
19	{R: 0x00, G: 0x00, B: 0x00},
20	{R: 0x80, G: 0x00, B: 0x00},
21	{R: 0x00, G: 0x80, B: 0x00},
22	{R: 0x80, G: 0x80, B: 0x00},
23	{R: 0x00, G: 0x00, B: 0x80},
24	{R: 0x80, G: 0x00, B: 0x80},
25	{R: 0x00, G: 0x80, B: 0x80},
26	{R: 0xc0, G: 0xc0, B: 0xc0},
27	{R: 0x80, G: 0x80, B: 0x80},
28	{R: 0xff, G: 0x00, B: 0x00},
29	{R: 0x00, G: 0xff, B: 0x00},
30	{R: 0xff, G: 0xff, B: 0x00},
31	{R: 0x00, G: 0x00, B: 0xff},
32	{R: 0xff, G: 0x00, B: 0xff},
33	{R: 0x00, G: 0xff, B: 0xff},
34	{R: 0xff, G: 0xff, B: 0xff},
35}
36
37var ansi256CubeLevels = [...]uint8{0, 95, 135, 175, 215, 255}
38
39func rgbToANSI16(rgb RGB) int {
40	best, bestDistance := 0, colorDistance(rgb, ansi16Palette[0])
41	for index := 1; index < len(ansi16Palette); index++ {
42		if distance := colorDistance(rgb, ansi16Palette[index]); distance < bestDistance {
43			best, bestDistance = index, distance
44		}
45	}
46	return best
47}
48
49func rgbToANSI256(rgb RGB) int {
50	ri, r := nearestCubeLevel(rgb.R)
51	gi, g := nearestCubeLevel(rgb.G)
52	bi, b := nearestCubeLevel(rgb.B)
53	cubeIndex := 16 + 36*ri + 6*gi + bi
54	cubeDistance := colorDistance(rgb, RGB{R: r, G: g, B: b})
55
56	grayIndex, grayDistance := 232, colorDistance(rgb, RGB{R: 8, G: 8, B: 8})
57	for offset := 1; offset < 24; offset++ {
58		level := uint8(8 + 10*offset)
59		if distance := colorDistance(rgb, RGB{R: level, G: level, B: level}); distance < grayDistance {
60			grayIndex, grayDistance = 232+offset, distance
61		}
62	}
63	if grayDistance < cubeDistance {
64		return grayIndex
65	}
66	return cubeIndex
67}
68
69func nearestCubeLevel(value uint8) (int, uint8) {
70	best, bestDistance := 0, absInt(int(value)-int(ansi256CubeLevels[0]))
71	for index := 1; index < len(ansi256CubeLevels); index++ {
72		if distance := absInt(int(value) - int(ansi256CubeLevels[index])); distance < bestDistance {
73			best, bestDistance = index, distance
74		}
75	}
76	return best, ansi256CubeLevels[best]
77}
78
79func ansi256ToRGB(index int) (RGB, bool) {
80	if index < 0 || index > 255 {
81		return RGB{}, false
82	}
83	if index < len(ansi16Palette) {
84		return ansi16Palette[index], true
85	}
86	if index < 232 {
87		index -= 16
88		return RGB{
89			R: ansi256CubeLevels[index/36],
90			G: ansi256CubeLevels[(index/6)%6],
91			B: ansi256CubeLevels[index%6],
92		}, true
93	}
94	level := uint8(8 + (index-232)*10)
95	return RGB{R: level, G: level, B: level}, true
96}
97
98func colorDistance(a, b RGB) int {
99	dr := int(a.R) - int(b.R)
100	dg := int(a.G) - int(b.G)
101	db := int(a.B) - int(b.B)
102	return dr*dr + dg*dg + db*db
103}
104
105func absInt(value int) int {
106	if value < 0 {
107		return -value
108	}
109	return value
110}

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