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