1//===- WithColor.cpp ------------------------------------------------------===//
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#include "llvm/Support/WithColor.h"
10
11#include "DebugOptions.h"
12
13#include "llvm/Support/CommandLine.h"
14#include "llvm/Support/Error.h"
15#include "llvm/Support/ManagedStatic.h"
16
17using namespace llvm;
18
19cl::OptionCategory &llvm::getColorCategory() {
20  static cl::OptionCategory ColorCategory("Color Options");
21  return ColorCategory;
22}
23namespace {
24struct CreateUseColor {
25  static void *call() {
26    return new cl::opt<cl::boolOrDefault>(
27        "color", cl::cat(getColorCategory()),
28        cl::desc("Use colors in output (default=autodetect)"),
29        cl::init(cl::BOU_UNSET));
30  }
31};
32} // namespace
33static ManagedStatic<cl::opt<cl::boolOrDefault>, CreateUseColor> UseColor;
34void llvm::initWithColorOptions() { *UseColor; }
35
36static bool DefaultAutoDetectFunction(const raw_ostream &OS) {
37  return *UseColor == cl::BOU_UNSET ? OS.has_colors()
38                                    : *UseColor == cl::BOU_TRUE;
39}
40
41WithColor::AutoDetectFunctionType WithColor::AutoDetectFunction =
42    DefaultAutoDetectFunction;
43
44WithColor::WithColor(raw_ostream &OS, HighlightColor Color, ColorMode Mode)
45    : OS(OS), Mode(Mode) {
46  // Detect color from terminal type unless the user passed the --color option.
47  if (colorsEnabled()) {
48    switch (Color) {
49    case HighlightColor::Address:
50      OS.changeColor(raw_ostream::YELLOW);
51      break;
52    case HighlightColor::String:
53      OS.changeColor(raw_ostream::GREEN);
54      break;
55    case HighlightColor::Tag:
56      OS.changeColor(raw_ostream::BLUE);
57      break;
58    case HighlightColor::Attribute:
59      OS.changeColor(raw_ostream::CYAN);
60      break;
61    case HighlightColor::Enumerator:
62      OS.changeColor(raw_ostream::MAGENTA);
63      break;
64    case HighlightColor::Macro:
65      OS.changeColor(raw_ostream::RED);
66      break;
67    case HighlightColor::Error:
68      OS.changeColor(raw_ostream::RED, true);
69      break;
70    case HighlightColor::Warning:
71      OS.changeColor(raw_ostream::MAGENTA, true);
72      break;
73    case HighlightColor::Note:
74      OS.changeColor(raw_ostream::BLACK, true);
75      break;
76    case HighlightColor::Remark:
77      OS.changeColor(raw_ostream::BLUE, true);
78      break;
79    }
80  }
81}
82
83raw_ostream &WithColor::error() { return error(errs()); }
84
85raw_ostream &WithColor::warning() { return warning(errs()); }
86
87raw_ostream &WithColor::note() { return note(errs()); }
88
89raw_ostream &WithColor::remark() { return remark(errs()); }
90
91raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix,
92                              bool DisableColors) {
93  if (!Prefix.empty())
94    OS << Prefix << ": ";
95  return WithColor(OS, HighlightColor::Error,
96                   DisableColors ? ColorMode::Disable : ColorMode::Auto)
97             .get()
98         << "error: ";
99}
100
101raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix,
102                                bool DisableColors) {
103  if (!Prefix.empty())
104    OS << Prefix << ": ";
105  return WithColor(OS, HighlightColor::Warning,
106                   DisableColors ? ColorMode::Disable : ColorMode::Auto)
107             .get()
108         << "warning: ";
109}
110
111raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix,
112                             bool DisableColors) {
113  if (!Prefix.empty())
114    OS << Prefix << ": ";
115  return WithColor(OS, HighlightColor::Note,
116                   DisableColors ? ColorMode::Disable : ColorMode::Auto)
117             .get()
118         << "note: ";
119}
120
121raw_ostream &WithColor::remark(raw_ostream &OS, StringRef Prefix,
122                               bool DisableColors) {
123  if (!Prefix.empty())
124    OS << Prefix << ": ";
125  return WithColor(OS, HighlightColor::Remark,
126                   DisableColors ? ColorMode::Disable : ColorMode::Auto)
127             .get()
128         << "remark: ";
129}
130
131bool WithColor::colorsEnabled() {
132  switch (Mode) {
133  case ColorMode::Enable:
134    return true;
135  case ColorMode::Disable:
136    return false;
137  case ColorMode::Auto:
138    return AutoDetectFunction(OS);
139  }
140  llvm_unreachable("All cases handled above.");
141}
142
143WithColor &WithColor::changeColor(raw_ostream::Colors Color, bool Bold,
144                                  bool BG) {
145  if (colorsEnabled())
146    OS.changeColor(Color, Bold, BG);
147  return *this;
148}
149
150WithColor &WithColor::resetColor() {
151  if (colorsEnabled())
152    OS.resetColor();
153  return *this;
154}
155
156WithColor::~WithColor() { resetColor(); }
157
158void WithColor::defaultErrorHandler(Error Err) {
159  handleAllErrors(std::move(Err), [](ErrorInfoBase &Info) {
160    WithColor::error() << Info.message() << '\n';
161  });
162}
163
164void WithColor::defaultWarningHandler(Error Warning) {
165  handleAllErrors(std::move(Warning), [](ErrorInfoBase &Info) {
166    WithColor::warning() << Info.message() << '\n';
167  });
168}
169
170WithColor::AutoDetectFunctionType WithColor::defaultAutoDetectFunction() {
171  return DefaultAutoDetectFunction;
172}
173
174void WithColor::setAutoDetectFunction(
175    AutoDetectFunctionType NewAutoDetectFunction) {
176  AutoDetectFunction = NewAutoDetectFunction;
177}
178