llvm.org GIT mirror llvm / e8ebb0f
Add support for outputting ANSI colors to raw_fd_ostream. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@72854 91177308-0d34-0410-b5e6-96231b3b80d8 Torok Edwin 10 years ago
5 changed file(s) with 216 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
4444 bool Unbuffered;
4545
4646 public:
47 // color order matches ANSI escape sequence, don't change
48 enum Colors {
49 BLACK=0,
50 RED,
51 GREEN,
52 YELLOW,
53 BLUE,
54 MAGENTA,
55 CYAN,
56 WHITE,
57 SAVEDCOLOR
58 };
59
4760 explicit raw_ostream(bool unbuffered=false) : Unbuffered(unbuffered) {
4861 // Start out ready to flush.
4962 OutBufStart = OutBufEnd = OutBufCur = 0;
166179 // Formatted output, see the format() function in Support/Format.h.
167180 raw_ostream &operator<<(const format_object_base &Fmt);
168181
182 /// Changes the foreground color of text that will be output from this point
183 /// forward.
184 /// @param colors ANSI color to use, the special SAVEDCOLOR can be used to
185 /// change only the bold attribute, and keep colors untouched
186 /// @param bold bold/brighter text, default false
187 /// @param bg if true change the background, default: change foreground
188 /// @returns itself so it can be used within << invocations
189 virtual raw_ostream &changeColor(enum Colors colors, bool bold=false,
190 bool bg=false) { return *this; }
191
192 /// Resets the colors to terminal defaults. Call this when you are done
193 /// outputting colored text, or before program exit.
194 virtual raw_ostream &resetColor() { return *this; }
195
169196 //===--------------------------------------------------------------------===//
170197 // Subclass Interface
171198 //===--------------------------------------------------------------------===//
242269 /// seek - Flushes the stream and repositions the underlying file descriptor
243270 /// positition to the offset specified from the beginning of the file.
244271 uint64_t seek(uint64_t off);
272
273 virtual raw_ostream &changeColor(enum Colors colors, bool bold=false,
274 bool bg=false);
275 virtual raw_ostream &resetColor();
245276 };
246277
247278 /// raw_stdout_ostream - This is a stream that always prints to stdout.
106106 /// console, or if the number of columns cannot be determined,
107107 /// this routine returns zero.
108108 static unsigned StandardErrColumns();
109
110 /// This function determines whether the terminal connected to standard
111 /// output supports colors. If standard output is not connected to a
112 /// terminal, this function returns false.
113 static bool StandardOutHasColors();
114
115 /// This function determines whether the terminal connected to standard
116 /// error supports colors. If standard error is not connected to a
117 /// terminal, this function returns false.
118 static bool StandardErrHasColors();
119
120 /// Whether changing colors requires the output to be flushed.
121 /// This is needed on systems that don't support escape sequences for
122 /// changing colors.
123 static bool ColorNeedsFlush();
124
125 /// This function returns the colorcode escape sequences, and sets Len to
126 /// the length of the escape sequence.
127 /// If ColorNeedsFlush() is true then this function will change the colors
128 /// and return an empty escape sequence. In that case it is the
129 /// responsibility of the client to flush the output stream prior to
130 /// calling this function.
131 static const char *OutputColor(char c, bool bold, bool bg);
132
133 /// Same as OutputColor, but only enables the bold attribute.
134 static const char *OutputBold(bool bg);
135
136 /// Resets the terminals colors, or returns an escape sequence to do so.
137 static const char *ResetColor();
109138 /// @}
110139 };
111140 }
1313 #include "llvm/Support/raw_ostream.h"
1414 #include "llvm/Support/Format.h"
1515 #include "llvm/System/Program.h"
16 #include "llvm/System/Process.h"
1617 #include "llvm/ADT/SmallVector.h"
1718 #include "llvm/Config/config.h"
1819 #include "llvm/Support/Compiler.h"
300301 return pos;
301302 }
302303
304 raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
305 bool bg) {
306 if (sys::Process::ColorNeedsFlush())
307 flush();
308 const char *colorcode =
309 (colors == SAVEDCOLOR) ? sys::Process::OutputBold(bg)
310 : sys::Process::OutputColor(colors, bold, bg);
311 if (colorcode) {
312 unsigned len = strlen(colorcode);
313 write(colorcode, len);
314 // don't account colors towards output characters
315 pos -= len;
316 }
317 return *this;
318 }
319
320 raw_ostream &raw_fd_ostream::resetColor() {
321 if (sys::Process::ColorNeedsFlush())
322 flush();
323 const char *colorcode = sys::Process::ResetColor();
324 if (colorcode) {
325 unsigned len = strlen(colorcode);
326 write(colorcode, len);
327 // don't account colors towards output characters
328 pos -= len;
329 }
330 return *this;
331 }
332
303333 //===----------------------------------------------------------------------===//
304334 // raw_stdout/err_ostream
305335 //===----------------------------------------------------------------------===//
234234
235235 return getColumns(2);
236236 }
237
238 static bool terminalHasColors() {
239 if (const char *term = std::getenv("TERM")) {
240 // Most modern terminals support ANSI escape sequences for colors.
241 // We could check terminfo, or have a list of known terms that support
242 // colors, but that would be overkill.
243 // The user can always ask for no colors by setting TERM to dumb, or
244 // using a commandline flag.
245 return strcmp(term, "dumb") != 0;
246 }
247 return false;
248 }
249
250 bool Process::StandardOutHasColors() {
251 if (!StandardOutIsDisplayed())
252 return false;
253 return terminalHasColors();
254 }
255
256 bool Process::StandardErrHasColors() {
257 if (!StandardErrIsDisplayed())
258 return false;
259 return terminalHasColors();
260 }
261
262 bool Process::ColorNeedsFlush() {
263 // No, we use ANSI escape sequences.
264 return false;
265 }
266
267 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
268
269 #define ALLCOLORS(FGBG,BOLD) {\
270 COLOR(FGBG, "0", BOLD),\
271 COLOR(FGBG, "1", BOLD),\
272 COLOR(FGBG, "2", BOLD),\
273 COLOR(FGBG, "3", BOLD),\
274 COLOR(FGBG, "4", BOLD),\
275 COLOR(FGBG, "5", BOLD),\
276 COLOR(FGBG, "6", BOLD),\
277 COLOR(FGBG, "7", BOLD)\
278 }
279
280 static const char* colorcodes[2][2][8] = {
281 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
282 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
283 };
284
285 const char *Process::OutputColor(char code, bool bold, bool bg) {
286 return colorcodes[bg?1:0][bold?1:0][code&7];
287 }
288
289 const char *Process::OutputBold(bool bg) {
290 return "\033[1m";
291 }
292
293 const char *Process::ResetColor() {
294 return "\033[0m";
295 }
146146 return Columns;
147147 }
148148
149 }
149 // it always has colors
150 bool Process::StandardErrHasColors() {
151 return StandardErrIsDisplayed();
152 }
153
154 bool Process::StandardOutHasColors() {
155 return StandardOutIsDisplayed();
156 }
157 namespace {
158 class DefaultColors
159 {
160 private:
161 WORD defaultColor;
162 public:
163 DefaultColors()
164 :defaultColor(GetCurrentColor()) {}
165 static unsigned GetCurrentColor() {
166 CONSOLE_SCREEN_BUFFER_INFO csbi;
167 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
168 return csbi.wAttributes;
169 return 0;
170 }
171 WORD operator()() const { return defaultColor; }
172 };
173
174 DefaultColors defaultColors;
175 }
176
177 bool Process::ColorNeedsFlush() {
178 return true;
179 }
180
181 const char *Process::OutputBold(bool bg) {
182 WORD colors = DefaultColors::GetCurrentColor();
183 if (bg)
184 colors |= BACKGROUND_INTENSITY;
185 else
186 colors |= FOREGROUND_INTENSITY;
187 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
188 return 0;
189 }
190
191 const char *Process::OutputColor(char code, bool bold, bool bg) {
192 WORD colors;
193 if (bg) {
194 colors = ((code&1) ? BACKGROUND_RED : 0) |
195 ((code&2) ? BACKGROUND_GREEN : 0 ) |
196 ((code&4) ? BACKGROUND_BLUE : 0);
197 if (bold)
198 colors |= BACKGROUND_INTENSITY;
199 } else {
200 colors = ((code&1) ? FOREGROUND_RED : 0) |
201 ((code&2) ? FOREGROUND_GREEN : 0 ) |
202 ((code&4) ? FOREGROUND_BLUE : 0);
203 if (bold)
204 colors |= FOREGROUND_INTENSITY;
205 }
206 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
207 return 0;
208 }
209
210 const char *Process::ResetColor() {
211 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
212 return 0;
213 }
214
215 }