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