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