Branch data Line data Source code
1 : : /* Classes for styling text cells (color, URLs).
2 : : Copyright (C) 2023-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #define INCLUDE_ALGORITHM
23 : : #define INCLUDE_VECTOR
24 : : #include "system.h"
25 : : #include "coretypes.h"
26 : : #include "pretty-print.h"
27 : : #include "intl.h"
28 : : #include "selftest.h"
29 : : #include "text-art/selftests.h"
30 : : #include "text-art/types.h"
31 : : #include "color-macros.h"
32 : : #include "diagnostic-color.h"
33 : :
34 : : using namespace text_art;
35 : :
36 : : /* class text_art::style. */
37 : :
38 : : style &
39 : 24 : style::set_style_url (const char *url)
40 : : {
41 : 24 : m_url.clear ();
42 : 672 : while (*url)
43 : 648 : m_url.push_back (*(url++));
44 : 24 : return *this;
45 : : }
46 : :
47 : : /* class text_art::style::color. */
48 : :
49 : : bool
50 : 10222 : style::color::operator== (const style::color &other) const
51 : : {
52 : 10222 : if (m_kind != other.m_kind)
53 : : return false;
54 : 9254 : switch (m_kind)
55 : : {
56 : 0 : default:
57 : 0 : gcc_unreachable ();
58 : 7904 : case kind::NAMED:
59 : 7904 : return (u.m_named.m_name == other.u.m_named.m_name
60 : 7904 : && u.m_named.m_bright == other.u.m_named.m_bright);
61 : 8 : case kind::BITS_8:
62 : 8 : return u.m_8bit == other.u.m_8bit;
63 : 1342 : case kind::BITS_24:
64 : 1342 : return (u.m_24bit.r == other.u.m_24bit.r
65 : 686 : && u.m_24bit.g == other.u.m_24bit.g
66 : 2028 : && u.m_24bit.b == other.u.m_24bit.b);
67 : : }
68 : : }
69 : :
70 : : static void
71 : 516 : ensure_separator (pretty_printer *pp, bool &need_separator)
72 : : {
73 : 0 : if (need_separator)
74 : 112 : pp_string (pp, COLOR_SEPARATOR);
75 : 516 : need_separator = true;
76 : 0 : }
77 : :
78 : : void
79 : 1056 : style::color::print_sgr (pretty_printer *pp,
80 : : bool fg,
81 : : bool &need_separator) const
82 : : {
83 : 1056 : switch (m_kind)
84 : : {
85 : 0 : default:
86 : 0 : gcc_unreachable ();
87 : 808 : case kind::NAMED:
88 : 808 : {
89 : 808 : static const char * const fg_normal[] = {"", // reset, for DEFAULT
90 : : COLOR_FG_BLACK,
91 : : COLOR_FG_RED,
92 : : COLOR_FG_GREEN,
93 : : COLOR_FG_YELLOW,
94 : : COLOR_FG_BLUE,
95 : : COLOR_FG_MAGENTA,
96 : : COLOR_FG_CYAN,
97 : : COLOR_FG_WHITE};
98 : 808 : static const char * const fg_bright[] = {"", // reset, for DEFAULT
99 : : COLOR_FG_BRIGHT_BLACK,
100 : : COLOR_FG_BRIGHT_RED,
101 : : COLOR_FG_BRIGHT_GREEN,
102 : : COLOR_FG_BRIGHT_YELLOW,
103 : : COLOR_FG_BRIGHT_BLUE,
104 : : COLOR_FG_BRIGHT_MAGENTA,
105 : : COLOR_FG_BRIGHT_CYAN,
106 : : COLOR_FG_BRIGHT_WHITE};
107 : 808 : static const char * const bg_normal[] = {"", // reset, for DEFAULT
108 : : COLOR_BG_BLACK,
109 : : COLOR_BG_RED,
110 : : COLOR_BG_GREEN,
111 : : COLOR_BG_YELLOW,
112 : : COLOR_BG_BLUE,
113 : : COLOR_BG_MAGENTA,
114 : : COLOR_BG_CYAN,
115 : : COLOR_BG_WHITE};
116 : 808 : static const char * const bg_bright[] = {"", // reset, for DEFAULT
117 : : COLOR_BG_BRIGHT_BLACK,
118 : : COLOR_BG_BRIGHT_RED,
119 : : COLOR_BG_BRIGHT_GREEN,
120 : : COLOR_BG_BRIGHT_YELLOW,
121 : : COLOR_BG_BRIGHT_BLUE,
122 : : COLOR_BG_BRIGHT_MAGENTA,
123 : : COLOR_BG_BRIGHT_CYAN,
124 : : COLOR_BG_BRIGHT_WHITE};
125 : 808 : STATIC_ASSERT (ARRAY_SIZE (fg_normal) == ARRAY_SIZE (fg_bright));
126 : 808 : STATIC_ASSERT (ARRAY_SIZE (fg_normal) == ARRAY_SIZE (bg_normal));
127 : 808 : STATIC_ASSERT (ARRAY_SIZE (fg_normal) == ARRAY_SIZE (bg_bright));
128 : 808 : gcc_assert ((size_t)u.m_named.m_name < ARRAY_SIZE (fg_normal));
129 : 808 : const char *const *arr;
130 : 808 : if (fg)
131 : 436 : arr = u.m_named.m_bright ? fg_bright : fg_normal;
132 : : else
133 : 372 : arr = u.m_named.m_bright ? bg_bright : bg_normal;
134 : 808 : const char *str = arr[(size_t)u.m_named.m_name];
135 : 808 : if (strlen (str) > 0)
136 : : {
137 : 236 : ensure_separator (pp, need_separator);
138 : 236 : pp_string (pp, str);
139 : : }
140 : : }
141 : : break;
142 : 48 : case kind::BITS_8:
143 : 48 : {
144 : 48 : ensure_separator (pp, need_separator);
145 : 48 : if (fg)
146 : 24 : pp_string (pp, "38");
147 : : else
148 : 24 : pp_string (pp, "48");
149 : 48 : pp_printf (pp, ";5;%i", (int)u.m_8bit);
150 : : }
151 : 48 : break;
152 : 200 : case kind::BITS_24:
153 : 200 : {
154 : 200 : ensure_separator (pp, need_separator);
155 : 200 : if (fg)
156 : 68 : pp_string (pp, "38");
157 : : else
158 : 132 : pp_string (pp, "48");
159 : 200 : pp_printf (pp, ";2;%i;%i;%i",
160 : 200 : (int)u.m_24bit.r,
161 : 200 : (int)u.m_24bit.g,
162 : 200 : (int)u.m_24bit.b);
163 : : }
164 : 200 : break;
165 : : }
166 : 1056 : }
167 : :
168 : : /* class text_art::style. */
169 : :
170 : : /* See https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf
171 : : GRCM - GRAPHIC RENDITION COMBINATION MODE can be "REPLACING" or
172 : : "CUMULATIVE", which affects whether we need to respecify all attributes
173 : : at each SGR, or can accumulate them. Looks like we can't rely on the value
174 : : of this, so we have to emit a single SGR for all changes, with a "0" reset
175 : : at the front, forcing it to be effectively replacing. */
176 : :
177 : : void
178 : 5050 : style::print_changes (pretty_printer *pp,
179 : : const style &old_style,
180 : : const style &new_style)
181 : : {
182 : 5050 : if (pp_show_color (pp))
183 : : {
184 : 568 : bool needs_sgr = ((old_style.m_bold != new_style.m_bold)
185 : 520 : || (old_style.m_underscore != new_style.m_underscore)
186 : 512 : || (old_style.m_blink != new_style.m_blink)
187 : 504 : || (old_style.m_fg_color != new_style.m_fg_color)
188 : 832 : || (old_style.m_bg_color != new_style.m_bg_color));
189 : 528 : if (needs_sgr)
190 : : {
191 : 1056 : bool emit_reset = (old_style.m_bold
192 : 504 : || new_style.m_bold
193 : 480 : || old_style.m_underscore
194 : 476 : || new_style.m_underscore
195 : 472 : || old_style.m_blink
196 : 996 : || new_style.m_blink);
197 : 528 : bool need_separator = false;
198 : :
199 : 528 : pp_string (pp, SGR_START);
200 : 528 : if (emit_reset)
201 : : {
202 : 64 : pp_string (pp, COLOR_NONE);
203 : 64 : need_separator = true;
204 : : }
205 : 528 : if (new_style.m_bold)
206 : : {
207 : 24 : gcc_assert (emit_reset);
208 : 24 : ensure_separator (pp, need_separator);
209 : 24 : pp_string (pp, COLOR_BOLD);
210 : : }
211 : 528 : if (new_style.m_underscore)
212 : : {
213 : 4 : gcc_assert (emit_reset);
214 : 4 : ensure_separator (pp, need_separator);
215 : 4 : pp_string (pp, COLOR_UNDERSCORE);
216 : : }
217 : 528 : if (new_style.m_blink)
218 : : {
219 : 4 : gcc_assert (emit_reset);
220 : 4 : ensure_separator (pp, need_separator);
221 : 4 : pp_string (pp, COLOR_BLINK);
222 : : }
223 : 528 : new_style.m_fg_color.print_sgr (pp, true, need_separator);
224 : 528 : new_style.m_bg_color.print_sgr (pp, false, need_separator);
225 : 528 : pp_string (pp, SGR_END);
226 : : }
227 : : }
228 : :
229 : 5050 : if (old_style.m_url != new_style.m_url)
230 : : {
231 : 48 : if (!old_style.m_url.empty ())
232 : 24 : pp_end_url (pp);
233 : 48 : if (pp->supports_urls_p ()
234 : 48 : && !new_style.m_url.empty ())
235 : : {
236 : : /* Adapted from pp_begin_url, but encoding the
237 : : chars to UTF-8 on the fly, rather than converting
238 : : to a buffer. */
239 : 16 : pp_string (pp, "\33]8;;");
240 : 448 : for (auto ch : new_style.m_url)
241 : 432 : pp_unicode_character (pp, ch);
242 : 16 : switch (pp->get_url_format ())
243 : : {
244 : 0 : default:
245 : 0 : case URL_FORMAT_NONE:
246 : 0 : gcc_unreachable ();
247 : 8 : case URL_FORMAT_ST:
248 : 8 : pp_string (pp, "\33\\");
249 : 8 : break;
250 : 8 : case URL_FORMAT_BEL:
251 : 8 : pp_string (pp, "\a");
252 : 8 : break;
253 : : }
254 : : }
255 : : }
256 : 5050 : }
257 : :
258 : : /* Look up the current SGR codes for a color capability NAME
259 : : (from GCC_COLORS or the defaults), and convert them to
260 : : a text_art::style. */
261 : :
262 : : style
263 : 148 : text_art::get_style_from_color_cap_name (const char *name)
264 : : {
265 : 148 : const char *sgr_codes = colorize_start (true, name);
266 : 148 : gcc_assert (sgr_codes);
267 : :
268 : : /* Parse the sgr codes. We expect the resulting styled_string to be
269 : : empty; we're interested in the final style created during parsing. */
270 : 148 : style_manager sm;
271 : 148 : styled_string styled_str (sm, sgr_codes);
272 : 148 : return sm.get_style (sm.get_num_styles () - 1);
273 : 148 : }
274 : :
275 : : /* class text_art::style_manager. */
276 : :
277 : 9435 : style_manager::style_manager ()
278 : : {
279 : : // index 0 will be the default style
280 : 9435 : m_styles.push_back (style ());
281 : 9435 : }
282 : :
283 : : style::id_t
284 : 2188 : style_manager::get_or_create_id (const style &s)
285 : : {
286 : : // For now, linear search
287 : 2188 : std::vector<style>::iterator existing
288 : 2188 : (std::find (m_styles.begin (), m_styles.end (), s));
289 : :
290 : : /* If found, return index of slot. */
291 : 2188 : if (existing != m_styles.end ())
292 : 1381 : return std::distance (m_styles.begin (), existing);
293 : :
294 : : /* Not found. */
295 : :
296 : : /* styled_str uses 7 bits for style information, so we can only support
297 : : up to 128 different style combinations.
298 : : Gracefully fail by turning off styling when this limit is reached. */
299 : 807 : if (m_styles.size () >= 127)
300 : : return 0;
301 : :
302 : 807 : m_styles.push_back (s);
303 : 807 : return m_styles.size () - 1;
304 : : }
305 : :
306 : : void
307 : 7019 : style_manager::print_any_style_changes (pretty_printer *pp,
308 : : style::id_t old_id,
309 : : style::id_t new_id) const
310 : : {
311 : 7019 : gcc_assert (pp);
312 : 7019 : if (old_id == new_id)
313 : : return;
314 : :
315 : 4826 : const style &old_style = m_styles[old_id];
316 : 4826 : const style &new_style = m_styles[new_id];
317 : 4826 : gcc_assert (!(old_style == new_style));
318 : 4826 : style::print_changes (pp, old_style, new_style);
319 : : }
320 : :
321 : : #if CHECKING_P
322 : :
323 : : namespace selftest {
324 : :
325 : : void
326 : 224 : assert_style_change_streq (const location &loc,
327 : : const style &old_style,
328 : : const style &new_style,
329 : : const char *expected_str)
330 : : {
331 : 224 : pretty_printer pp;
332 : 224 : pp_show_color (&pp) = true;
333 : 224 : style::print_changes (&pp, old_style, new_style);
334 : 224 : ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected_str);
335 : 224 : }
336 : :
337 : : #define ASSERT_STYLE_CHANGE_STREQ(OLD_STYLE, NEW_STYLE, EXPECTED_STR) \
338 : : SELFTEST_BEGIN_STMT \
339 : : assert_style_change_streq ((SELFTEST_LOCATION), \
340 : : (OLD_STYLE), \
341 : : (NEW_STYLE), \
342 : : (EXPECTED_STR)); \
343 : : SELFTEST_END_STMT
344 : :
345 : : static void
346 : 4 : test_bold ()
347 : : {
348 : 4 : style_manager sm;
349 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
350 : :
351 : 4 : style plain;
352 : 4 : ASSERT_EQ (sm.get_or_create_id (plain), 0);
353 : 12 : ASSERT_EQ (sm.get_num_styles (), 1);
354 : :
355 : 4 : style bold;
356 : 4 : bold.m_bold = true;
357 : :
358 : 4 : ASSERT_EQ (sm.get_or_create_id (bold), 1);
359 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
360 : 4 : ASSERT_EQ (sm.get_or_create_id (bold), 1);
361 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
362 : :
363 : 4 : ASSERT_STYLE_CHANGE_STREQ (plain, bold, "\33[00;01m\33[K");
364 : 4 : ASSERT_STYLE_CHANGE_STREQ (bold, plain, "\33[00m\33[K");
365 : 4 : }
366 : :
367 : : static void
368 : 4 : test_underscore ()
369 : : {
370 : 4 : style_manager sm;
371 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
372 : :
373 : 4 : style plain;
374 : 4 : ASSERT_EQ (sm.get_or_create_id (plain), 0);
375 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
376 : :
377 : 4 : style underscore;
378 : 4 : underscore.m_underscore = true;
379 : :
380 : 4 : ASSERT_EQ (sm.get_or_create_id (underscore), 1);
381 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
382 : 4 : ASSERT_EQ (sm.get_or_create_id (underscore), 1);
383 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
384 : :
385 : 4 : ASSERT_STYLE_CHANGE_STREQ (plain, underscore, "\33[00;04m\33[K");
386 : 4 : ASSERT_STYLE_CHANGE_STREQ (underscore, plain, "\33[00m\33[K");
387 : 4 : }
388 : :
389 : : static void
390 : 4 : test_blink ()
391 : : {
392 : 4 : style_manager sm;
393 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
394 : :
395 : 4 : style plain;
396 : 4 : ASSERT_EQ (sm.get_or_create_id (plain), 0);
397 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
398 : :
399 : 4 : style blink;
400 : 4 : blink.m_blink = true;
401 : :
402 : 4 : ASSERT_EQ (sm.get_or_create_id (blink), 1);
403 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
404 : 4 : ASSERT_EQ (sm.get_or_create_id (blink), 1);
405 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
406 : :
407 : 4 : ASSERT_STYLE_CHANGE_STREQ (plain, blink, "\33[00;05m\33[K");
408 : 4 : ASSERT_STYLE_CHANGE_STREQ (blink, plain, "\33[00m\33[K");
409 : 4 : }
410 : :
411 : : #define ASSERT_NAMED_COL_STREQ(NAMED_COLOR, FG, BRIGHT, EXPECTED_STR) \
412 : : SELFTEST_BEGIN_STMT \
413 : : { \
414 : : style plain; \
415 : : style s; \
416 : : if (FG) \
417 : : s.m_fg_color = style::color ((NAMED_COLOR), (BRIGHT)); \
418 : : else \
419 : : s.m_bg_color = style::color ((NAMED_COLOR), (BRIGHT)); \
420 : : assert_style_change_streq ((SELFTEST_LOCATION), \
421 : : plain, \
422 : : s, \
423 : : (EXPECTED_STR)); \
424 : : } \
425 : : SELFTEST_END_STMT
426 : :
427 : : static void
428 : 4 : test_named_colors ()
429 : : {
430 : : /* Foreground colors. */
431 : 4 : {
432 : 4 : const bool fg = true;
433 : 4 : {
434 : 4 : const bool bright = false;
435 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::DEFAULT, fg, bright, "");
436 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLACK, fg, bright,
437 : : "[30m[K");
438 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::RED, fg, bright,
439 : : "[31m[K");
440 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::GREEN, fg, bright,
441 : : "[32m[K");
442 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::YELLOW, fg, bright,
443 : : "[33m[K");
444 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLUE, fg, bright,
445 : : "[34m[K");
446 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::MAGENTA, fg, bright,
447 : : "[35m[K");
448 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::CYAN, fg, bright,
449 : : "[36m[K");
450 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::WHITE, fg, bright,
451 : : "[37m[K");
452 : : }
453 : 4 : {
454 : 4 : const bool bright = true;
455 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::DEFAULT, fg, bright,
456 : : "[m[K");
457 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLACK, fg, bright,
458 : : "[90m[K");
459 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::RED, fg, bright,
460 : : "[91m[K");
461 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::GREEN, fg, bright,
462 : : "[92m[K");
463 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::YELLOW, fg, bright,
464 : : "[93m[K");
465 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLUE, fg, bright,
466 : : "[94m[K");
467 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::MAGENTA, fg, bright,
468 : : "[95m[K");
469 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::CYAN, fg, bright,
470 : : "[96m[K");
471 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::WHITE, fg, bright,
472 : : "[97m[K");
473 : : }
474 : : }
475 : :
476 : : /* Background colors. */
477 : 4 : {
478 : 4 : const bool fg = false;
479 : 4 : {
480 : 4 : const bool bright = false;
481 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::DEFAULT, fg, bright, "");
482 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLACK, fg, bright,
483 : : "[40m[K");
484 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::RED, fg, bright,
485 : : "[41m[K");
486 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::GREEN, fg, bright,
487 : : "[42m[K");
488 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::YELLOW, fg, bright,
489 : : "[43m[K");
490 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLUE, fg, bright,
491 : : "[44m[K");
492 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::MAGENTA, fg, bright,
493 : : "[45m[K");
494 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::CYAN, fg, bright,
495 : : "[46m[K");
496 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::WHITE, fg, bright,
497 : : "[47m[K");
498 : : }
499 : 4 : {
500 : 4 : const bool bright = true;
501 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::DEFAULT, fg, bright,
502 : : "[m[K");
503 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLACK, fg, bright,
504 : : "[100m[K");
505 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::RED, fg, bright,
506 : : "[101m[K");
507 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::GREEN, fg, bright,
508 : : "[102m[K");
509 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::YELLOW, fg, bright,
510 : : "[103m[K");
511 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::BLUE, fg, bright,
512 : : "[104m[K");
513 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::MAGENTA, fg, bright,
514 : : "[105m[K");
515 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::CYAN, fg, bright,
516 : : "[106m[K");
517 : 4 : ASSERT_NAMED_COL_STREQ (style::named_color::WHITE, fg, bright,
518 : : "[107m[K");
519 : : }
520 : : }
521 : 4 : }
522 : :
523 : : #define ASSERT_8_BIT_COL_STREQ(COL_VAL, FG, EXPECTED_STR) \
524 : : SELFTEST_BEGIN_STMT \
525 : : { \
526 : : style plain; \
527 : : style s; \
528 : : if (FG) \
529 : : s.m_fg_color = style::color (COL_VAL); \
530 : : else \
531 : : s.m_bg_color = style::color (COL_VAL); \
532 : : assert_style_change_streq ((SELFTEST_LOCATION), \
533 : : plain, \
534 : : s, \
535 : : (EXPECTED_STR)); \
536 : : } \
537 : : SELFTEST_END_STMT
538 : :
539 : : static void
540 : 4 : test_8_bit_colors ()
541 : : {
542 : : /* Foreground colors. */
543 : 4 : {
544 : 4 : const bool fg = true;
545 : : /* 0-15: standard and high-intensity standard colors. */
546 : 4 : ASSERT_8_BIT_COL_STREQ (0, fg, "[38;5;0m[K");
547 : 4 : ASSERT_8_BIT_COL_STREQ (15, fg, "[38;5;15m[K");
548 : : /* 16-231: 6x6x6 color cube. */
549 : 4 : ASSERT_8_BIT_COL_STREQ (16, fg, "[38;5;16m[K");
550 : 4 : ASSERT_8_BIT_COL_STREQ (231, fg, "[38;5;231m[K");
551 : : /* 232-255: grayscale. */
552 : 4 : ASSERT_8_BIT_COL_STREQ (232, fg, "[38;5;232m[K");
553 : 4 : ASSERT_8_BIT_COL_STREQ (255, fg, "[38;5;255m[K");
554 : : }
555 : : /* Background colors. */
556 : 4 : {
557 : 4 : const bool fg = false;
558 : : /* 0-15: standard and high-intensity standard colors. */
559 : 4 : ASSERT_8_BIT_COL_STREQ (0, fg, "[48;5;0m[K");
560 : 4 : ASSERT_8_BIT_COL_STREQ (15, fg, "[48;5;15m[K");
561 : : /* 16-231: 6x6x6 color cube. */
562 : 4 : ASSERT_8_BIT_COL_STREQ (16, fg, "[48;5;16m[K");
563 : 4 : ASSERT_8_BIT_COL_STREQ (231, fg, "[48;5;231m[K");
564 : : /* 232-255: grayscale. */
565 : 4 : ASSERT_8_BIT_COL_STREQ (232, fg, "[48;5;232m[K");
566 : 4 : ASSERT_8_BIT_COL_STREQ (255, fg, "[48;5;255m[K");
567 : : }
568 : 4 : }
569 : :
570 : : #define ASSERT_24_BIT_COL_STREQ(R, G, B, FG, EXPECTED_STR) \
571 : : SELFTEST_BEGIN_STMT \
572 : : { \
573 : : style plain; \
574 : : style s; \
575 : : if (FG) \
576 : : s.m_fg_color = style::color ((R), (G), (B)); \
577 : : else \
578 : : s.m_bg_color = style::color ((R), (G), (B)); \
579 : : assert_style_change_streq ((SELFTEST_LOCATION), \
580 : : plain, \
581 : : s, \
582 : : (EXPECTED_STR)); \
583 : : } \
584 : : SELFTEST_END_STMT
585 : :
586 : : static void
587 : 4 : test_24_bit_colors ()
588 : : {
589 : : /* Foreground colors. */
590 : 4 : {
591 : 4 : const bool fg = true;
592 : : // #F3FAF2:
593 : 4 : ASSERT_24_BIT_COL_STREQ (0xf3, 0xfa, 0xf2, fg,
594 : : "[38;2;243;250;242m[K");
595 : : }
596 : : /* Background colors. */
597 : 4 : {
598 : 4 : const bool fg = false;
599 : : // #FDF7E7
600 : 4 : ASSERT_24_BIT_COL_STREQ (0xfd, 0xf7, 0xe7, fg,
601 : : "[48;2;253;247;231m[K");
602 : : }
603 : 4 : }
604 : :
605 : : static void
606 : 4 : test_style_combinations ()
607 : : {
608 : 4 : style_manager sm;
609 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
610 : :
611 : 4 : style plain;
612 : 4 : ASSERT_EQ (sm.get_or_create_id (plain), 0);
613 : 4 : ASSERT_EQ (sm.get_num_styles (), 1);
614 : :
615 : 4 : style bold;
616 : 4 : bold.m_bold = true;
617 : :
618 : 4 : ASSERT_EQ (sm.get_or_create_id (bold), 1);
619 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
620 : 4 : ASSERT_EQ (sm.get_or_create_id (bold), 1);
621 : 4 : ASSERT_EQ (sm.get_num_styles (), 2);
622 : :
623 : 4 : style magenta_on_blue;
624 : 4 : magenta_on_blue.m_fg_color = style::named_color::MAGENTA;
625 : 4 : magenta_on_blue.m_bg_color = style::named_color::BLUE;
626 : 4 : ASSERT_EQ (sm.get_or_create_id (magenta_on_blue), 2);
627 : 4 : ASSERT_EQ (sm.get_num_styles (), 3);
628 : 4 : ASSERT_EQ (sm.get_or_create_id (magenta_on_blue), 2);
629 : 4 : ASSERT_EQ (sm.get_num_styles (), 3);
630 : 4 : }
631 : :
632 : : /* Run all selftests in this file. */
633 : :
634 : : void
635 : 4 : text_art_style_cc_tests ()
636 : : {
637 : 4 : test_bold ();
638 : 4 : test_underscore ();
639 : 4 : test_blink ();
640 : 4 : test_named_colors ();
641 : 4 : test_8_bit_colors ();
642 : 4 : test_24_bit_colors ();
643 : 4 : test_style_combinations ();
644 : 4 : }
645 : :
646 : : } // namespace selftest
647 : :
648 : :
649 : : #endif /* #if CHECKING_P */
|