1 //===---------------------AnsiTerminal.h ------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_UTILITY_ANSITERMINAL_H
10 #define LLDB_UTILITY_ANSITERMINAL_H
11 
12 #define ANSI_FG_COLOR_BLACK 30
13 #define ANSI_FG_COLOR_RED 31
14 #define ANSI_FG_COLOR_GREEN 32
15 #define ANSI_FG_COLOR_YELLOW 33
16 #define ANSI_FG_COLOR_BLUE 34
17 #define ANSI_FG_COLOR_PURPLE 35
18 #define ANSI_FG_COLOR_CYAN 36
19 #define ANSI_FG_COLOR_WHITE 37
20 
21 #define ANSI_FG_COLOR_BRIGHT_BLACK 90
22 #define ANSI_FG_COLOR_BRIGHT_RED 91
23 #define ANSI_FG_COLOR_BRIGHT_GREEN 92
24 #define ANSI_FG_COLOR_BRIGHT_YELLOW 93
25 #define ANSI_FG_COLOR_BRIGHT_BLUE 94
26 #define ANSI_FG_COLOR_BRIGHT_PURPLE 95
27 #define ANSI_FG_COLOR_BRIGHT_CYAN 96
28 #define ANSI_FG_COLOR_BRIGHT_WHITE 97
29 
30 #define ANSI_BG_COLOR_BLACK 40
31 #define ANSI_BG_COLOR_RED 41
32 #define ANSI_BG_COLOR_GREEN 42
33 #define ANSI_BG_COLOR_YELLOW 43
34 #define ANSI_BG_COLOR_BLUE 44
35 #define ANSI_BG_COLOR_PURPLE 45
36 #define ANSI_BG_COLOR_CYAN 46
37 #define ANSI_BG_COLOR_WHITE 47
38 
39 #define ANSI_BG_COLOR_BRIGHT_BLACK 100
40 #define ANSI_BG_COLOR_BRIGHT_RED 101
41 #define ANSI_BG_COLOR_BRIGHT_GREEN 102
42 #define ANSI_BG_COLOR_BRIGHT_YELLOW 103
43 #define ANSI_BG_COLOR_BRIGHT_BLUE 104
44 #define ANSI_BG_COLOR_BRIGHT_PURPLE 105
45 #define ANSI_BG_COLOR_BRIGHT_CYAN 106
46 #define ANSI_BG_COLOR_BRIGHT_WHITE 107
47 
48 #define ANSI_SPECIAL_FRAMED 51
49 #define ANSI_SPECIAL_ENCIRCLED 52
50 
51 #define ANSI_CTRL_NORMAL 0
52 #define ANSI_CTRL_BOLD 1
53 #define ANSI_CTRL_FAINT 2
54 #define ANSI_CTRL_ITALIC 3
55 #define ANSI_CTRL_UNDERLINE 4
56 #define ANSI_CTRL_SLOW_BLINK 5
57 #define ANSI_CTRL_FAST_BLINK 6
58 #define ANSI_CTRL_IMAGE_NEGATIVE 7
59 #define ANSI_CTRL_CONCEAL 8
60 #define ANSI_CTRL_CROSSED_OUT 9
61 
62 #define ANSI_ESC_START "\033["
63 #define ANSI_ESC_END "m"
64 
65 #define ANSI_STR(s) #s
66 #define ANSI_DEF_STR(s) ANSI_STR(s)
67 
68 #define ANSI_ESCAPE1(s) ANSI_ESC_START ANSI_DEF_STR(s) ANSI_ESC_END
69 
70 #define ANSI_1_CTRL(ctrl1) "\033["##ctrl1 ANSI_ESC_END
71 #define ANSI_2_CTRL(ctrl1, ctrl2) "\033["##ctrl1 ";"##ctrl2 ANSI_ESC_END
72 
73 #include "llvm/ADT/ArrayRef.h"
74 #include "llvm/ADT/STLExtras.h"
75 #include "llvm/ADT/StringRef.h"
76 
77 #include <string>
78 
79 namespace lldb_private {
80 
81 namespace ansi {
82 
83 inline std::string FormatAnsiTerminalCodes(llvm::StringRef format,
84                                            bool do_color = true) {
85   // Convert "${ansi.XXX}" tokens to ansi values or clear them if do_color is
86   // false.
87   // clang-format off
88   static const struct {
89     const char *name;
90     const char *value;
91   } g_color_tokens[] = {
92 #define _TO_STR2(_val) #_val
93 #define _TO_STR(_val) _TO_STR2(_val)
94       {"fg.black}",         ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END},
95       {"fg.red}",           ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END},
96       {"fg.green}",         ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END},
97       {"fg.yellow}",        ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END},
98       {"fg.blue}",          ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END},
99       {"fg.purple}",        ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END},
100       {"fg.cyan}",          ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END},
101       {"fg.white}",         ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END},
102       {"fg.bright.black}",  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_BLACK) ANSI_ESC_END},
103       {"fg.bright.red}",    ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_RED) ANSI_ESC_END},
104       {"fg.bright.green}",  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_GREEN) ANSI_ESC_END},
105       {"fg.bright.yellow}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_YELLOW) ANSI_ESC_END},
106       {"fg.bright.blue}",   ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_BLUE) ANSI_ESC_END},
107       {"fg.bright.purple}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_PURPLE) ANSI_ESC_END},
108       {"fg.bright.cyan}",   ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_CYAN) ANSI_ESC_END},
109       {"fg.bright.white}",  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BRIGHT_WHITE) ANSI_ESC_END},
110       {"bg.black}",         ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END},
111       {"bg.red}",           ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END},
112       {"bg.green}",         ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END},
113       {"bg.yellow}",        ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END},
114       {"bg.blue}",          ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END},
115       {"bg.purple}",        ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END},
116       {"bg.cyan}",          ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END},
117       {"bg.white}",         ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END},
118       {"bg.bright.black}",  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_BLACK) ANSI_ESC_END},
119       {"bg.bright.red}",    ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_RED) ANSI_ESC_END},
120       {"bg.bright.green}",  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_GREEN) ANSI_ESC_END},
121       {"bg.bright.yellow}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_YELLOW) ANSI_ESC_END},
122       {"bg.bright.blue}",   ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_BLUE) ANSI_ESC_END},
123       {"bg.bright.purple}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_PURPLE) ANSI_ESC_END},
124       {"bg.bright.cyan}",   ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_CYAN) ANSI_ESC_END},
125       {"bg.bright.white}",  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BRIGHT_WHITE) ANSI_ESC_END},
126       {"normal}",           ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END},
127       {"bold}",             ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END},
128       {"faint}",            ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END},
129       {"italic}",           ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END},
130       {"underline}",        ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END},
131       {"slow-blink}",       ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END},
132       {"fast-blink}",       ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END},
133       {"negative}",         ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END},
134       {"conceal}",          ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END},
135       {"crossed-out}",      ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END},
136 #undef _TO_STR
137 #undef _TO_STR2
138   };
139   // clang-format on
140   auto codes = llvm::ArrayRef(g_color_tokens);
141 
142   static const char tok_hdr[] = "${ansi.";
143 
144   std::string fmt;
145   while (!format.empty()) {
146     llvm::StringRef left, right;
147     std::tie(left, right) = format.split(tok_hdr);
148 
149     fmt += left;
150 
151     if (left == format && right.empty()) {
152       // The header was not found.  Just exit.
153       break;
154     }
155 
156     bool found_code = false;
157     for (const auto &code : codes) {
158       if (!right.consume_front(code.name))
159         continue;
160 
161       if (do_color)
162         fmt.append(code.value);
163       found_code = true;
164       break;
165     }
166     format = right;
167     // If we haven't found a valid replacement value, we just copy the string
168     // to the result without any modifications.
169     if (!found_code)
170       fmt.append(tok_hdr);
171   }
172   return fmt;
173 }
174 }
175 } // namespace lldb_private
176 
177 #endif
178