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