summaryrefslogtreecommitdiff
path: root/internal/render/color.go
blob: cf2af89d9d3e1f960c4329add57478819e405c5b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package render

import "strings"

// Colour uses ANSI slots 0-15 only -- codes 30-37 and 90-97, plus the
// attributes 1 (bold), 2 (dim) and 4 (underline). Never 256-colour indices:
// this runs on terminals whose palette remaps the low slots (the phone's is
// entirely green), where a hardcoded 38;5;196 would be the one off-palette
// thing on screen.
const (
	Reset     = "0"
	Bold      = "1"
	Dim       = "2"
	Underline = "4"

	Blue        = "34"
	Cyan        = "36"
	Green       = "32"
	Yellow      = "33"
	Red         = "31"
	BrightBlue  = "94"
	BrightRed   = "91"
	BrightWhite = "97"
)

// Styler returns a function that wraps text in an ANSI code, or returns it
// unchanged when colour is off.
func Styler(colour bool) func(code, text string) string {
	if !colour {
		return func(_, text string) string { return text }
	}
	return func(code, text string) string {
		if code == "" {
			return text
		}
		return "\033[" + code + "m" + text + "\033[0m"
	}
}

// Cell is one character of chart output with the style it should carry.
type Cell struct {
	Style string
	Text  string
}

// Paint joins cells, emitting one escape sequence per run of identical style
// rather than one per character. A per-character version makes the chart around
// ten times larger for output that looks exactly the same.
func Paint(cells []Cell, c func(string, string) string) string {
	var b strings.Builder
	for i := 0; i < len(cells); {
		j := i
		var run strings.Builder
		for j < len(cells) && cells[j].Style == cells[i].Style {
			run.WriteString(cells[j].Text)
			j++
		}
		b.WriteString(c(cells[i].Style, run.String()))
		i = j
	}
	return b.String()
}