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