hppa: Fix LO_SUM DLTIND14R address support in PRINT_OPERAND_ADDRESS
[official-gcc.git] / gcc / text-art / ruler.cc
blobf80d9bb8758cb31e4ffccb01bd92366331648ce5
1 /* Classes for printing labelled rulers.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
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 "selftest.h"
28 #include "text-art/selftests.h"
29 #include "text-art/ruler.h"
30 #include "text-art/theme.h"
32 using namespace text_art;
34 void
35 x_ruler::add_label (const canvas::range_t &r,
36 styled_string text,
37 style::id_t style_id,
38 label_kind kind)
40 m_labels.push_back (label (r, std::move (text), style_id, kind));
41 m_has_layout = false;
44 int
45 x_ruler::get_canvas_y (int rel_y) const
47 gcc_assert (rel_y >= 0);
48 gcc_assert (rel_y < m_size.h);
49 switch (m_label_dir)
51 default:
52 gcc_unreachable ();
53 case label_dir::ABOVE:
54 return m_size.h - (rel_y + 1);
55 case label_dir::BELOW:
56 return rel_y;
60 void
61 x_ruler::paint_to_canvas (canvas &canvas,
62 canvas::coord_t offset,
63 const theme &theme)
65 ensure_layout ();
67 if (0)
68 canvas.fill (canvas::rect_t (offset, m_size),
69 canvas::cell_t ('*'));
71 for (size_t idx = 0; idx < m_labels.size (); idx++)
73 const label &iter_label = m_labels[idx];
75 /* Paint the ruler itself. */
76 const int ruler_rel_y = get_canvas_y (0);
77 for (int rel_x = iter_label.m_range.start;
78 rel_x < iter_label.m_range.next;
79 rel_x++)
81 enum theme::cell_kind kind = theme::cell_kind::X_RULER_MIDDLE;
83 if (rel_x == iter_label.m_range.start)
85 kind = theme::cell_kind::X_RULER_LEFT_EDGE;
86 if (idx > 0)
88 const label &prev_label = m_labels[idx - 1];
89 if (prev_label.m_range.get_max () == iter_label.m_range.start)
90 kind = theme::cell_kind::X_RULER_INTERNAL_EDGE;
93 else if (rel_x == iter_label.m_range.get_max ())
94 kind = theme::cell_kind::X_RULER_RIGHT_EDGE;
95 else if (rel_x == iter_label.m_connector_x)
97 switch (m_label_dir)
99 default:
100 gcc_unreachable ();
101 case label_dir::ABOVE:
102 kind = theme::cell_kind::X_RULER_CONNECTOR_TO_LABEL_ABOVE;
103 break;
104 case label_dir::BELOW:
105 kind = theme::cell_kind::X_RULER_CONNECTOR_TO_LABEL_BELOW;
106 break;
109 canvas.paint (canvas::coord_t (rel_x, ruler_rel_y) + offset,
110 theme.get_cell (kind, iter_label.m_style_id));
113 /* Paint the connector to the text. */
114 for (int connector_rel_y = 1;
115 connector_rel_y < iter_label.m_text_rect.get_min_y ();
116 connector_rel_y++)
118 canvas.paint
119 ((canvas::coord_t (iter_label.m_connector_x,
120 get_canvas_y (connector_rel_y))
121 + offset),
122 theme.get_cell (theme::cell_kind::X_RULER_VERTICAL_CONNECTOR,
123 iter_label.m_style_id));
126 /* Paint the text. */
127 switch (iter_label.m_kind)
129 default:
130 gcc_unreachable ();
131 case x_ruler::label_kind::TEXT:
132 canvas.paint_text
133 ((canvas::coord_t (iter_label.m_text_rect.get_min_x (),
134 get_canvas_y (iter_label.m_text_rect.get_min_y ()))
135 + offset),
136 iter_label.m_text);
137 break;
139 case x_ruler::label_kind::TEXT_WITH_BORDER:
141 const canvas::range_t rel_x_range
142 (iter_label.m_text_rect.get_x_range ());
144 enum theme::cell_kind inner_left_kind;
145 enum theme::cell_kind inner_connector_kind;
146 enum theme::cell_kind inner_right_kind;
147 enum theme::cell_kind outer_left_kind;
148 enum theme::cell_kind outer_right_kind;
150 switch (m_label_dir)
152 default:
153 gcc_unreachable ();
154 case label_dir::ABOVE:
155 outer_left_kind = theme::cell_kind::TEXT_BORDER_TOP_LEFT;
156 outer_right_kind = theme::cell_kind::TEXT_BORDER_TOP_RIGHT;
157 inner_left_kind = theme::cell_kind::TEXT_BORDER_BOTTOM_LEFT;
158 inner_connector_kind = theme::cell_kind::X_RULER_CONNECTOR_TO_LABEL_BELOW;
159 inner_right_kind = theme::cell_kind::TEXT_BORDER_BOTTOM_RIGHT;
160 break;
161 case label_dir::BELOW:
162 inner_left_kind = theme::cell_kind::TEXT_BORDER_TOP_LEFT;
163 inner_connector_kind = theme::cell_kind::X_RULER_CONNECTOR_TO_LABEL_ABOVE;
164 inner_right_kind = theme::cell_kind::TEXT_BORDER_TOP_RIGHT;
165 outer_left_kind = theme::cell_kind::TEXT_BORDER_BOTTOM_LEFT;
166 outer_right_kind = theme::cell_kind::TEXT_BORDER_BOTTOM_RIGHT;
167 break;
169 /* Inner border. */
171 const int rel_canvas_y
172 = get_canvas_y (iter_label.m_text_rect.get_min_y ());
173 /* Left corner. */
174 canvas.paint ((canvas::coord_t (rel_x_range.get_min (),
175 rel_canvas_y)
176 + offset),
177 theme.get_cell (inner_left_kind,
178 iter_label.m_style_id));
179 /* Edge. */
180 const canvas::cell_t edge_border_cell
181 = theme.get_cell (theme::cell_kind::TEXT_BORDER_HORIZONTAL,
182 iter_label.m_style_id);
183 const canvas::cell_t connector_border_cell
184 = theme.get_cell (inner_connector_kind,
185 iter_label.m_style_id);
186 for (int rel_x = rel_x_range.get_min () + 1;
187 rel_x < rel_x_range.get_max ();
188 rel_x++)
189 if (rel_x == iter_label.m_connector_x)
190 canvas.paint ((canvas::coord_t (rel_x, rel_canvas_y)
191 + offset),
192 connector_border_cell);
193 else
194 canvas.paint ((canvas::coord_t (rel_x, rel_canvas_y)
195 + offset),
196 edge_border_cell);
198 /* Right corner. */
199 canvas.paint ((canvas::coord_t (rel_x_range.get_max (),
200 rel_canvas_y)
201 + offset),
202 theme.get_cell (inner_right_kind,
203 iter_label.m_style_id));
207 const int rel_canvas_y
208 = get_canvas_y (iter_label.m_text_rect.get_min_y () + 1);
209 const canvas::cell_t border_cell
210 = theme.get_cell (theme::cell_kind::TEXT_BORDER_VERTICAL,
211 iter_label.m_style_id);
213 /* Left border. */
214 canvas.paint ((canvas::coord_t (rel_x_range.get_min (),
215 rel_canvas_y)
216 + offset),
217 border_cell);
218 /* Text. */
219 canvas.paint_text ((canvas::coord_t (rel_x_range.get_min () + 1,
220 rel_canvas_y)
221 + offset),
222 iter_label.m_text);
223 /* Right border. */
224 canvas.paint ((canvas::coord_t (rel_x_range.get_max (),
225 rel_canvas_y)
226 + offset),
227 border_cell);
230 /* Outer border. */
232 const int rel_canvas_y
233 = get_canvas_y (iter_label.m_text_rect.get_max_y ());
234 /* Left corner. */
235 canvas.paint ((canvas::coord_t (rel_x_range.get_min (),
236 rel_canvas_y)
237 + offset),
238 theme.get_cell (outer_left_kind,
239 iter_label.m_style_id));
240 /* Edge. */
241 const canvas::cell_t border_cell
242 = theme.get_cell (theme::cell_kind::TEXT_BORDER_HORIZONTAL,
243 iter_label.m_style_id);
244 for (int rel_x = rel_x_range.get_min () + 1;
245 rel_x < rel_x_range.get_max ();
246 rel_x++)
247 canvas.paint ((canvas::coord_t (rel_x, rel_canvas_y)
248 + offset),
249 border_cell);
251 /* Right corner. */
252 canvas.paint ((canvas::coord_t (rel_x_range.get_max (),
253 rel_canvas_y)
254 + offset),
255 theme.get_cell (outer_right_kind,
256 iter_label.m_style_id));
259 break;
264 DEBUG_FUNCTION void
265 x_ruler::debug (const style_manager &sm)
267 canvas c (get_size (), sm);
268 paint_to_canvas (c, canvas::coord_t (0, 0), unicode_theme ());
269 c.debug (true);
272 x_ruler::label::label (const canvas::range_t &range,
273 styled_string text,
274 style::id_t style_id,
275 label_kind kind)
276 : m_range (range),
277 m_text (std::move (text)),
278 m_style_id (style_id),
279 m_kind (kind),
280 m_text_rect (canvas::coord_t (0, 0),
281 canvas::size_t (m_text.calc_canvas_width (), 1)),
282 m_connector_x ((m_range.get_min () + m_range.get_max ()) / 2)
284 if (kind == label_kind::TEXT_WITH_BORDER)
286 m_text_rect.m_size.w += 2;
287 m_text_rect.m_size.h += 2;
291 bool
292 x_ruler::label::operator< (const label &other) const
294 int cmp = m_range.start - other.m_range.start;
295 if (cmp)
296 return cmp < 0;
297 return m_range.next < other.m_range.next;
300 void
301 x_ruler::ensure_layout ()
303 if (m_has_layout)
304 return;
305 update_layout ();
306 m_has_layout = true;
309 void
310 x_ruler::update_layout ()
312 if (m_labels.empty ())
313 return;
315 std::sort (m_labels.begin (), m_labels.end ());
317 /* Place labels. */
318 int ruler_width = m_labels.back ().m_range.get_next ();
319 int width_with_labels = ruler_width;
321 /* Get x coordinates of text parts of each label
322 (m_text_rect.m_top_left.x for each label). */
323 for (size_t idx = 0; idx < m_labels.size (); idx++)
325 label &iter_label = m_labels[idx];
326 /* Attempt to center the text label. */
327 int min_x;
328 if (idx > 0)
330 /* ...but don't overlap with the connector to the left. */
331 int left_neighbor_connector_x = m_labels[idx - 1].m_connector_x;
332 min_x = left_neighbor_connector_x + 1;
334 else
336 /* ...or go beyond the leftmost column. */
337 min_x = 0;
339 int connector_x = iter_label.m_connector_x;
340 int centered_x
341 = connector_x - ((int)iter_label.m_text_rect.get_width () / 2);
342 int text_x = std::max (min_x, centered_x);
343 iter_label.m_text_rect.m_top_left.x = text_x;
346 /* Now walk backwards trying to place them vertically,
347 setting m_text_rect.m_top_left.y for each label,
348 consolidating the rows where possible.
349 The y cooordinates are stored with respect to label_dir::BELOW. */
350 int label_y = 2;
351 for (int idx = m_labels.size () - 1; idx >= 0; idx--)
353 label &iter_label = m_labels[idx];
354 /* Does it fit on the same row as the text label to the right? */
355 size_t text_len = iter_label.m_text_rect.get_width ();
356 /* Get the x-coord of immediately beyond iter_label's text. */
357 int next_x = iter_label.m_text_rect.get_min_x () + text_len;
358 if (idx < (int)m_labels.size () - 1)
360 if (next_x >= m_labels[idx + 1].m_text_rect.get_min_x ())
362 /* If not, start a new row. */
363 label_y += m_labels[idx + 1].m_text_rect.get_height ();
366 iter_label.m_text_rect.m_top_left.y = label_y;
367 width_with_labels = std::max (width_with_labels, next_x);
370 m_size = canvas::size_t (width_with_labels,
371 label_y + m_labels[0].m_text_rect.get_height ());
374 #if CHECKING_P
376 namespace selftest {
378 static void
379 assert_x_ruler_streq (const location &loc,
380 x_ruler &ruler,
381 const theme &theme,
382 const style_manager &sm,
383 bool styled,
384 const char *expected_str)
386 canvas c (ruler.get_size (), sm);
387 ruler.paint_to_canvas (c, canvas::coord_t (0, 0), theme);
388 if (0)
389 c.debug (styled);
390 assert_canvas_streq (loc, c, styled, expected_str);
393 #define ASSERT_X_RULER_STREQ(RULER, THEME, SM, STYLED, EXPECTED_STR) \
394 SELFTEST_BEGIN_STMT \
395 assert_x_ruler_streq ((SELFTEST_LOCATION), \
396 (RULER), \
397 (THEME), \
398 (SM), \
399 (STYLED), \
400 (EXPECTED_STR)); \
401 SELFTEST_END_STMT
403 static void
404 test_single ()
406 style_manager sm;
407 x_ruler r (x_ruler::label_dir::BELOW);
408 r.add_label (canvas::range_t (0, 11), styled_string (sm, "foo"),
409 style::id_plain, x_ruler::label_kind::TEXT);
410 ASSERT_X_RULER_STREQ
411 (r, ascii_theme (), sm, true,
412 ("|~~~~+~~~~|\n"
413 " |\n"
414 " foo\n"));
415 ASSERT_X_RULER_STREQ
416 (r, unicode_theme (), sm, true,
417 ("├────┬────┤\n"
418 " │\n"
419 " foo\n"));
422 static void
423 test_single_above ()
425 style_manager sm;
426 x_ruler r (x_ruler::label_dir::ABOVE);
427 r.add_label (canvas::range_t (0, 11), styled_string (sm, "hello world"),
428 style::id_plain);
429 ASSERT_X_RULER_STREQ
430 (r, ascii_theme (), sm, true,
431 ("hello world\n"
432 " |\n"
433 "|~~~~+~~~~|\n"));
434 ASSERT_X_RULER_STREQ
435 (r, unicode_theme (), sm, true,
436 ("hello world\n"
437 " │\n"
438 "├────┴────┤\n"));
441 static void
442 test_multiple_contiguous ()
444 style_manager sm;
445 x_ruler r (x_ruler::label_dir::BELOW);
446 r.add_label (canvas::range_t (0, 11), styled_string (sm, "foo"),
447 style::id_plain);
448 r.add_label (canvas::range_t (10, 16), styled_string (sm, "bar"),
449 style::id_plain);
450 ASSERT_X_RULER_STREQ
451 (r, ascii_theme (), sm, true,
452 ("|~~~~+~~~~|~+~~|\n"
453 " | |\n"
454 " foo bar\n"));
455 ASSERT_X_RULER_STREQ
456 (r, unicode_theme (), sm, true,
457 ("├────┬────┼─┬──┤\n"
458 " │ │\n"
459 " foo bar\n"));
462 static void
463 test_multiple_contiguous_above ()
465 style_manager sm;
466 x_ruler r (x_ruler::label_dir::ABOVE);
467 r.add_label (canvas::range_t (0, 11), styled_string (sm, "foo"),
468 style::id_plain);
469 r.add_label (canvas::range_t (10, 16), styled_string (sm, "bar"),
470 style::id_plain);
471 ASSERT_X_RULER_STREQ
472 (r, ascii_theme (), sm, true,
473 (" foo bar\n"
474 " | |\n"
475 "|~~~~+~~~~|~+~~|\n"));
476 ASSERT_X_RULER_STREQ
477 (r, unicode_theme (), sm, true,
478 (" foo bar\n"
479 " │ │\n"
480 "├────┴────┼─┴──┤\n"));
483 static void
484 test_multiple_contiguous_abutting_labels ()
486 style_manager sm;
487 x_ruler r (x_ruler::label_dir::BELOW);
488 r.add_label (canvas::range_t (0, 11), styled_string (sm, "12345678"),
489 style::id_plain);
490 r.add_label (canvas::range_t (10, 16), styled_string (sm, "1234678"),
491 style::id_plain);
492 ASSERT_X_RULER_STREQ
493 (r, unicode_theme (), sm, true,
494 ("├────┬────┼─┬──┤\n"
495 " │ │\n"
496 " │ 1234678\n"
497 " 12345678\n"));
500 static void
501 test_multiple_contiguous_overlapping_labels ()
503 style_manager sm;
504 x_ruler r (x_ruler::label_dir::BELOW);
505 r.add_label (canvas::range_t (0, 11), styled_string (sm, "123456789"),
506 style::id_plain);
507 r.add_label (canvas::range_t (10, 16), styled_string (sm, "12346789"),
508 style::id_plain);
509 ASSERT_X_RULER_STREQ
510 (r, unicode_theme (), sm, true,
511 ("├────┬────┼─┬──┤\n"
512 " │ │\n"
513 " │ 12346789\n"
514 " 123456789\n"));
516 static void
517 test_abutting_left_border ()
519 style_manager sm;
520 x_ruler r (x_ruler::label_dir::BELOW);
521 r.add_label (canvas::range_t (0, 6),
522 styled_string (sm, "this is a long label"),
523 style::id_plain);
524 ASSERT_X_RULER_STREQ
525 (r, unicode_theme (), sm, true,
526 ("├─┬──┤\n"
527 " │\n"
528 "this is a long label\n"));
531 static void
532 test_too_long_to_consolidate_vertically ()
534 style_manager sm;
535 x_ruler r (x_ruler::label_dir::BELOW);
536 r.add_label (canvas::range_t (0, 11),
537 styled_string (sm, "long string A"),
538 style::id_plain);
539 r.add_label (canvas::range_t (10, 16),
540 styled_string (sm, "long string B"),
541 style::id_plain);
542 ASSERT_X_RULER_STREQ
543 (r, unicode_theme (), sm, true,
544 ("├────┬────┼─┬──┤\n"
545 " │ │\n"
546 " │long string B\n"
547 "long string A\n"));
550 static void
551 test_abutting_neighbor ()
553 style_manager sm;
554 x_ruler r (x_ruler::label_dir::BELOW);
555 r.add_label (canvas::range_t (0, 11),
556 styled_string (sm, "very long string A"),
557 style::id_plain);
558 r.add_label (canvas::range_t (10, 16),
559 styled_string (sm, "very long string B"),
560 style::id_plain);
561 ASSERT_X_RULER_STREQ
562 (r, unicode_theme (), sm, true,
563 ("├────┬────┼─┬──┤\n"
564 " │ │\n"
565 " │very long string B\n"
566 "very long string A\n"));
569 static void
570 test_gaps ()
572 style_manager sm;
573 x_ruler r (x_ruler::label_dir::BELOW);
574 r.add_label (canvas::range_t (0, 5),
575 styled_string (sm, "foo"),
576 style::id_plain);
577 r.add_label (canvas::range_t (10, 15),
578 styled_string (sm, "bar"),
579 style::id_plain);
580 ASSERT_X_RULER_STREQ
581 (r, ascii_theme (), sm, true,
582 ("|~+~| |~+~|\n"
583 " | |\n"
584 " foo bar\n"));
587 static void
588 test_styled ()
590 style_manager sm;
591 style s1, s2;
592 s1.m_bold = true;
593 s1.m_fg_color = style::named_color::YELLOW;
594 s2.m_bold = true;
595 s2.m_fg_color = style::named_color::BLUE;
596 style::id_t sid1 = sm.get_or_create_id (s1);
597 style::id_t sid2 = sm.get_or_create_id (s2);
599 x_ruler r (x_ruler::label_dir::BELOW);
600 r.add_label (canvas::range_t (0, 5), styled_string (sm, "foo"), sid1);
601 r.add_label (canvas::range_t (10, 15), styled_string (sm, "bar"), sid2);
602 ASSERT_X_RULER_STREQ
603 (r, ascii_theme (), sm, true,
604 ("\e[00;01;33m\e[K|~+~|\e[00m\e[K \e[00;01;34m\e[K|~+~|\e[00m\e[K\n"
605 " \e[00;01;33m\e[K|\e[00m\e[K \e[00;01;34m\e[K|\e[00m\e[K\n"
606 " foo bar\n"));
609 static void
610 test_borders ()
612 style_manager sm;
614 x_ruler r (x_ruler::label_dir::BELOW);
615 r.add_label (canvas::range_t (0, 5),
616 styled_string (sm, "label 1"),
617 style::id_plain,
618 x_ruler::label_kind::TEXT_WITH_BORDER);
619 r.add_label (canvas::range_t (10, 15),
620 styled_string (sm, "label 2"),
621 style::id_plain);
622 r.add_label (canvas::range_t (20, 25),
623 styled_string (sm, "label 3"),
624 style::id_plain,
625 x_ruler::label_kind::TEXT_WITH_BORDER);
626 ASSERT_X_RULER_STREQ
627 (r, ascii_theme (), sm, true,
628 "|~+~| |~+~| |~+~|\n"
629 " | | |\n"
630 " | label 2 +---+---+\n"
631 "+-+-----+ |label 3|\n"
632 "|label 1| +-------+\n"
633 "+-------+\n");
634 ASSERT_X_RULER_STREQ
635 (r, unicode_theme (), sm, true,
636 "├─┬─┤ ├─┬─┤ ├─┬─┤\n"
637 " │ │ │\n"
638 " │ label 2 ╭───┴───╮\n"
639 "╭─┴─────╮ │label 3│\n"
640 "│label 1│ ╰───────╯\n"
641 "╰───────╯\n");
644 x_ruler r (x_ruler::label_dir::ABOVE);
645 r.add_label (canvas::range_t (0, 5),
646 styled_string (sm, "label 1"),
647 style::id_plain,
648 x_ruler::label_kind::TEXT_WITH_BORDER);
649 r.add_label (canvas::range_t (10, 15),
650 styled_string (sm, "label 2"),
651 style::id_plain);
652 r.add_label (canvas::range_t (20, 25),
653 styled_string (sm, "label 3"),
654 style::id_plain,
655 x_ruler::label_kind::TEXT_WITH_BORDER);
656 ASSERT_X_RULER_STREQ
657 (r, ascii_theme (), sm, true,
658 "+-------+\n"
659 "|label 1| +-------+\n"
660 "+-+-----+ |label 3|\n"
661 " | label 2 +---+---+\n"
662 " | | |\n"
663 "|~+~| |~+~| |~+~|\n");
664 ASSERT_X_RULER_STREQ
665 (r, unicode_theme (), sm, true,
666 "╭───────╮\n"
667 "│label 1│ ╭───────╮\n"
668 "╰─┬─────╯ │label 3│\n"
669 " │ label 2 ╰───┬───╯\n"
670 " │ │ │\n"
671 "├─┴─┤ ├─┴─┤ ├─┴─┤\n");
675 static void
676 test_emoji ()
678 style_manager sm;
680 styled_string s;
681 s.append (styled_string (0x26A0, /* U+26A0 WARNING SIGN. */
682 true));
683 s.append (styled_string (sm, " "));
684 s.append (styled_string (sm, "this is a warning"));
686 x_ruler r (x_ruler::label_dir::BELOW);
687 r.add_label (canvas::range_t (0, 5),
688 std::move (s),
689 style::id_plain,
690 x_ruler::label_kind::TEXT_WITH_BORDER);
692 ASSERT_X_RULER_STREQ
693 (r, ascii_theme (), sm, true,
694 "|~+~|\n"
695 " |\n"
696 "+-+------------------+\n"
697 "|⚠️ this is a warning|\n"
698 "+--------------------+\n");
701 /* Run all selftests in this file. */
703 void
704 text_art_ruler_cc_tests ()
706 test_single ();
707 test_single_above ();
708 test_multiple_contiguous ();
709 test_multiple_contiguous_above ();
710 test_multiple_contiguous_abutting_labels ();
711 test_multiple_contiguous_overlapping_labels ();
712 test_abutting_left_border ();
713 test_too_long_to_consolidate_vertically ();
714 test_abutting_neighbor ();
715 test_gaps ();
716 test_styled ();
717 test_borders ();
718 test_emoji ();
721 } // namespace selftest
724 #endif /* #if CHECKING_P */