dte test coverage


Directory: ./
File: src/terminal/style.c
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 86 86 100.0%
Functions: 8 8 100.0%
Branches: 58 62 93.5%

Line Branch Exec Source
1 #include <string.h>
2 #include "style.h"
3 #include "color.h"
4 #include "util/array.h"
5 #include "util/ascii.h"
6 #include "util/debug.h"
7 #include "util/numtostr.h"
8 #include "util/str-util.h"
9 #include "util/strtonum.h"
10 #include "util/xmalloc.h"
11
12 static const char attr_names[][16] = {
13 "keep",
14 "underline",
15 "reverse",
16 "blink",
17 "dim",
18 "bold",
19 "invisible",
20 "italic",
21 "strikethrough"
22 };
23
24 static const char color_names[][16] = {
25 "keep",
26 "default",
27 "black",
28 "red",
29 "green",
30 "yellow",
31 "blue",
32 "magenta",
33 "cyan",
34 "gray",
35 "darkgray",
36 "lightred",
37 "lightgreen",
38 "lightyellow",
39 "lightblue",
40 "lightmagenta",
41 "lightcyan",
42 "white"
43 };
44
45 18 UNITTEST {
46 18 CHECK_STRING_ARRAY(attr_names);
47 18 CHECK_STRING_ARRAY(color_names);
48 18 }
49
50 292 static unsigned int lookup_attr(const char *s)
51 {
52
2/2
✓ Branch 0 taken 1531 times.
✓ Branch 1 taken 23 times.
1554 for (size_t i = 0; i < ARRAYLEN(attr_names); i++) {
53
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 1262 times.
1531 if (streq(s, attr_names[i])) {
54 269 return 1U << i;
55 }
56 }
57
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
23 if (streq(s, "lowintensity")) {
58 1 return ATTR_DIM;
59 }
60 return 0;
61 }
62
63 800 static int32_t lookup_color(const char *name)
64 {
65 800 return STR_TO_ENUM_WITH_OFFSET(name, color_names, COLOR_INVALID, -2);
66 }
67
68 852 static int32_t parse_color(const char *str)
69 {
70 852 size_t len = strlen(str);
71
2/2
✓ Branch 0 taken 850 times.
✓ Branch 1 taken 2 times.
852 if (unlikely(len == 0)) {
72 return COLOR_INVALID;
73 }
74
75 // Parse #rgb or #rrggbb
76
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 838 times.
850 if (str[0] == '#') {
77 12 return parse_rgb(str + 1, len - 1);
78 }
79
80 // Parse r/g/b
81
4/4
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 741 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 87 times.
838 if (len == 5 && str[1] == '/') {
82 10 const unsigned char *u_str = str;
83 10 uint8_t r = u_str[0] - '0';
84 10 uint8_t g = u_str[2] - '0';
85 10 uint8_t b = u_str[4] - '0';
86
5/6
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
10 if (unlikely(r > 5 || g > 5 || b > 5 || str[3] != '/')) {
87 return COLOR_INVALID;
88 }
89 // Convert to color index 16..231 (xterm 6x6x6 color cube)
90 6 return 16 + (r * 36) + (g * 6) + b;
91 }
92
93 // Parse -2 .. 255
94
6/6
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 736 times.
✓ Branch 2 taken 89 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 64 times.
828 if (len <= 3 && (str[0] == '-' || ascii_isdigit(str[0]))) {
95 28 int x;
96
5/6
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 1 times.
28 if (unlikely(!str_to_int(str, &x) || x < -2 || x > 255)) {
97 return COLOR_INVALID;
98 }
99 26 return x;
100 }
101
102 800 return lookup_color(str);
103 }
104
105 // Note: this function returns the number of valid strings parsed, or -1 if
106 // more than 2 valid colors were encountered. Thus, success is indicated by
107 // a return value equal to `nstrs`.
108 599 ssize_t parse_term_style(TermStyle *style, char **strs, size_t nstrs)
109 {
110 599 int32_t colors[2] = {COLOR_DEFAULT, COLOR_DEFAULT};
111 599 unsigned int attrs = 0;
112 599 size_t i = 0;
113
114
2/2
✓ Branch 0 taken 852 times.
✓ Branch 1 taken 575 times.
1427 for (size_t nr_colors = 0; i < nstrs; i++) {
115 852 const char *str = strs[i];
116 852 int32_t c = parse_color(str);
117
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 560 times.
852 if (c == COLOR_INVALID) {
118 292 unsigned int attr = lookup_attr(str);
119
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 22 times.
292 if (likely(attr)) {
120 270 attrs |= attr;
121 270 continue;
122 }
123 // Invalid color or attribute
124 22 return i;
125 }
126
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 531 times.
560 if (nr_colors == ARRAYLEN(colors)) {
127
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 2 times.
29 if (likely(c == COLOR_KEEP)) {
128 // "keep" is also a valid attribute
129 27 attrs |= ATTR_KEEP;
130 27 continue;
131 }
132 // Too many colors
133 return -1;
134 }
135 531 colors[nr_colors++] = c;
136 }
137
138 575 *style = (TermStyle) {
139 575 .fg = colors[0],
140 575 .bg = colors[1],
141 .attr = attrs
142 };
143 575 return i;
144 }
145
146 1 void collect_colors_and_attributes(PointerArray *a, const char *prefix)
147 {
148
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
18 for (size_t i = 1; i < ARRAYLEN(color_names); i++) {
149
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (str_has_prefix(color_names[i], prefix)) {
150 17 ptr_array_append(a, xstrdup(color_names[i]));
151 }
152 }
153
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (size_t i = 0; i < ARRAYLEN(attr_names); i++) {
154
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (str_has_prefix(attr_names[i], prefix)) {
155 9 ptr_array_append(a, xstrdup(attr_names[i]));
156 }
157 }
158 1 }
159
160 113 size_t color_to_str(char buf[COLOR_STR_BUFSIZE], int32_t color)
161 {
162 113 BUG_ON(!color_is_valid(color));
163
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 19 times.
113 if (color < 16) {
164 94 static_assert(sizeof(color_names[0]) <= COLOR_STR_BUFSIZE);
165 94 memcpy(buf, color_names[color + 2], sizeof(color_names[0]));
166 94 return strlen(buf);
167 }
168
169
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 10 times.
19 if (color < 256) {
170 9 return buf_u8_to_str((uint8_t)color, buf);
171 }
172
173 10 size_t i = 0;
174 10 buf[i++] = '#';
175 10 i += hex_encode_byte(buf + i, color_r(color));
176 10 i += hex_encode_byte(buf + i, color_g(color));
177 10 i += hex_encode_byte(buf + i, color_b(color));
178 10 BUG_ON(i != 7);
179 return i;
180 }
181
182 71 const char *term_style_to_string(char buf[TERM_STYLE_BUFSIZE], const TermStyle *style)
183 {
184 71 size_t pos = color_to_str(buf, style->fg);
185
186
4/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 50 times.
71 if (style->bg != COLOR_DEFAULT || (style->attr & ATTR_KEEP) != 0) {
187 21 buf[pos++] = ' ';
188 21 pos += color_to_str(buf + pos, style->bg);
189 }
190
191
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 71 times.
710 for (size_t i = 0; i < ARRAYLEN(attr_names); i++) {
192
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 597 times.
639 if (style->attr & (1U << i)) {
193 42 BUG_ON(pos + 2 + sizeof(attr_names[0]) >= TERM_STYLE_BUFSIZE);
194 42 buf[pos++] = ' ';
195 42 memcpy(buf + pos, attr_names[i], sizeof(attr_names[0]));
196 42 pos += strlen(buf + pos);
197 }
198 }
199
200 71 buf[pos] = '\0';
201 71 return buf;
202 }
203