1package tui
2
3import (
4 "regexp"
5 "strings"
6 "testing"
7)
8
9func TestStripANSIBackgroundsKeepsExtendedColors(t *testing.T) {
10 cases := []struct{ name, in, want string }{
11 {"256 foreground in background range", "\x1b[38;5;45mstring\x1b[0m", "\x1b[38;5;45mstring\x1b[0m"},
12 {"256 foreground index 48", "\x1b[38;5;48mx\x1b[0m", "\x1b[38;5;48mx\x1b[0m"},
13 {"256 foreground index 49", "\x1b[38;5;49mx\x1b[0m", "\x1b[38;5;49mx\x1b[0m"},
14 {"256 foreground bright range", "\x1b[38;5;101mcomment\x1b[0m", "\x1b[38;5;101mcomment\x1b[0m"},
15 {"256 foreground index 107", "\x1b[38;5;107mx\x1b[0m", "\x1b[38;5;107mx\x1b[0m"},
16 {"bold plus foreground", "\x1b[1;38;5;45mstring\x1b[0m", "\x1b[1;38;5;45mstring\x1b[0m"},
17 {"truecolor foreground", "\x1b[38;2;40;101;49mstring\x1b[0m", "\x1b[38;2;40;101;49mstring\x1b[0m"},
18 {"plain text", "hello", "hello"},
19 {"reset", "\x1b[0m", "\x1b[0m"},
20 {"256 background dropped", "\x1b[48;5;45mbg\x1b[0m", "bg\x1b[0m"},
21 {"separate background dropped", "\x1b[38;5;45m\x1b[48;5;0mtext", "\x1b[38;5;45mtext"},
22 {"combined background dropped", "\x1b[38;5;45;48;5;0mtext", "\x1b[38;5;45mtext"},
23 {"truecolor background dropped", "\x1b[48;2;9;0;21mbg\x1b[0m", "bg\x1b[0m"},
24 {"default background dropped", "\x1b[49mbg", "bg"},
25 {"ANSI background dropped", "\x1b[41mbg", "bg"},
26 {"bright background dropped", "\x1b[101mbg", "bg"},
27 {"bare foreground introducer dropped", "\x1b[38mtext", "text"},
28 {"truncated indexed foreground", "\x1b[38;5mstring", "string"},
29 {"truncated indexed background", "\x1b[48;5mstring", "string"},
30 {"truncated truecolor foreground", "\x1b[38;2;1;2mtext", "text"},
31 {"truncated truecolor background", "\x1b[48;2;1;2mtext", "text"},
32 // An unsupported extended selector is not consumed as a color unit;
33 // unrelated standalone attributes keep their ordinary SGR semantics.
34 {"unknown selector preserves reverse", "\x1b[38;7mtext", "\x1b[7mtext"},
35 }
36 for _, tc := range cases {
37 t.Run(tc.name, func(t *testing.T) {
38 if got := stripANSIBackgrounds(tc.in); got != tc.want {
39 t.Fatalf("got %q, want %q", got, tc.want)
40 }
41 })
42 }
43}
44
45// Chroma maps this custom type color to xterm index 45, which the old
46// background filter removed from the foreground unit.
47func TestHighlightCodeExtendedColorIsWellFormed(t *testing.T) {
48 th := Dark
49 th.Syntax = SyntaxTheme{KeywordType: "#00e5ff", NameBuiltin: "#00e5ff"}
50 joined := strings.Join(th.HighlightCode("func splitFrontmatter(raw string) (string, string) {\n", "go"), "\n")
51 if strings.Contains(joined, "\x1b[38;5m") || strings.Contains(joined, "\x1b[48;5m") {
52 t.Fatalf("highlighting emitted a malformed extended color: %q", joined)
53 }
54 idx := strings.Index(joined, "string")
55 if idx < 0 {
56 t.Fatalf("type keyword missing: %q", joined)
57 }
58 prefix := joined[:idx]
59 escape := strings.LastIndex(prefix, "\x1b[")
60 if escape < 0 || !regexp.MustCompile(`^\x1b\[(?:[0-9]+;)*38;5;[0-9]+m$`).MatchString(prefix[escape:]) {
61 t.Fatalf("type keyword lost its foreground color: %q", joined)
62 }
63}