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 
17 using namespace llvm;
18 
19 cl::OptionCategory &llvm::getColorCategory() {
20   static cl::OptionCategory ColorCategory("Color Options");
21   return ColorCategory;
22 }
23 namespace {
24 struct 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
33 static ManagedStatic<cl::opt<cl::boolOrDefault>, CreateUseColor> UseColor;
34 void llvm::initWithColorOptions() { *UseColor; }
35 
36 static bool DefaultAutoDetectFunction(const raw_ostream &OS) {
37   return *UseColor == cl::BOU_UNSET ? OS.has_colors()
38                                     : *UseColor == cl::BOU_TRUE;
39 }
40 
41 WithColor::AutoDetectFunctionType WithColor::AutoDetectFunction =
42     DefaultAutoDetectFunction;
43 
44 WithColor::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 
83 raw_ostream &WithColor::error() { return error(errs()); }
84 
85 raw_ostream &WithColor::warning() { return warning(errs()); }
86 
87 raw_ostream &WithColor::note() { return note(errs()); }
88 
89 raw_ostream &WithColor::remark() { return remark(errs()); }
90 
91 raw_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 
101 raw_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 
111 raw_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 
121 raw_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 
131 bool 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 
143 WithColor &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 
150 WithColor &WithColor::resetColor() {
151   if (colorsEnabled())
152     OS.resetColor();
153   return *this;
154 }
155 
156 WithColor::~WithColor() { resetColor(); }
157 
158 void WithColor::defaultErrorHandler(Error Err) {
159   handleAllErrors(std::move(Err), [](ErrorInfoBase &Info) {
160     WithColor::error() << Info.message() << '\n';
161   });
162 }
163 
164 void WithColor::defaultWarningHandler(Error Warning) {
165   handleAllErrors(std::move(Warning), [](ErrorInfoBase &Info) {
166     WithColor::warning() << Info.message() << '\n';
167   });
168 }
169 
170 WithColor::AutoDetectFunctionType WithColor::defaultAutoDetectFunction() {
171   return DefaultAutoDetectFunction;
172 }
173 
174 void WithColor::setAutoDetectFunction(
175     AutoDetectFunctionType NewAutoDetectFunction) {
176   AutoDetectFunction = NewAutoDetectFunction;
177 }
178