mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-25 00:24:26 +00:00
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
This commit is contained in:
@ -45,6 +45,19 @@ private:
|
|||||||
bool Unbuffered;
|
bool Unbuffered;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// color order matches ANSI escape sequence, don't change
|
||||||
|
enum Colors {
|
||||||
|
BLACK=0,
|
||||||
|
RED,
|
||||||
|
GREEN,
|
||||||
|
YELLOW,
|
||||||
|
BLUE,
|
||||||
|
MAGENTA,
|
||||||
|
CYAN,
|
||||||
|
WHITE,
|
||||||
|
SAVEDCOLOR
|
||||||
|
};
|
||||||
|
|
||||||
explicit raw_ostream(bool unbuffered=false) : Unbuffered(unbuffered) {
|
explicit raw_ostream(bool unbuffered=false) : Unbuffered(unbuffered) {
|
||||||
// Start out ready to flush.
|
// Start out ready to flush.
|
||||||
OutBufStart = OutBufEnd = OutBufCur = 0;
|
OutBufStart = OutBufEnd = OutBufCur = 0;
|
||||||
@ -167,6 +180,20 @@ public:
|
|||||||
// Formatted output, see the format() function in Support/Format.h.
|
// Formatted output, see the format() function in Support/Format.h.
|
||||||
raw_ostream &operator<<(const format_object_base &Fmt);
|
raw_ostream &operator<<(const format_object_base &Fmt);
|
||||||
|
|
||||||
|
/// Changes the foreground color of text that will be output from this point
|
||||||
|
/// forward.
|
||||||
|
/// @param colors ANSI color to use, the special SAVEDCOLOR can be used to
|
||||||
|
/// change only the bold attribute, and keep colors untouched
|
||||||
|
/// @param bold bold/brighter text, default false
|
||||||
|
/// @param bg if true change the background, default: change foreground
|
||||||
|
/// @returns itself so it can be used within << invocations
|
||||||
|
virtual raw_ostream &changeColor(enum Colors colors, bool bold=false,
|
||||||
|
bool bg=false) { return *this; }
|
||||||
|
|
||||||
|
/// Resets the colors to terminal defaults. Call this when you are done
|
||||||
|
/// outputting colored text, or before program exit.
|
||||||
|
virtual raw_ostream &resetColor() { return *this; }
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Subclass Interface
|
// Subclass Interface
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
@ -243,6 +270,10 @@ public:
|
|||||||
/// seek - Flushes the stream and repositions the underlying file descriptor
|
/// seek - Flushes the stream and repositions the underlying file descriptor
|
||||||
/// positition to the offset specified from the beginning of the file.
|
/// positition to the offset specified from the beginning of the file.
|
||||||
uint64_t seek(uint64_t off);
|
uint64_t seek(uint64_t off);
|
||||||
|
|
||||||
|
virtual raw_ostream &changeColor(enum Colors colors, bool bold=false,
|
||||||
|
bool bg=false);
|
||||||
|
virtual raw_ostream &resetColor();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// raw_stdout_ostream - This is a stream that always prints to stdout.
|
/// raw_stdout_ostream - This is a stream that always prints to stdout.
|
||||||
|
@ -107,6 +107,35 @@ namespace sys {
|
|||||||
/// console, or if the number of columns cannot be determined,
|
/// console, or if the number of columns cannot be determined,
|
||||||
/// this routine returns zero.
|
/// this routine returns zero.
|
||||||
static unsigned StandardErrColumns();
|
static unsigned StandardErrColumns();
|
||||||
|
|
||||||
|
/// This function determines whether the terminal connected to standard
|
||||||
|
/// output supports colors. If standard output is not connected to a
|
||||||
|
/// terminal, this function returns false.
|
||||||
|
static bool StandardOutHasColors();
|
||||||
|
|
||||||
|
/// This function determines whether the terminal connected to standard
|
||||||
|
/// error supports colors. If standard error is not connected to a
|
||||||
|
/// terminal, this function returns false.
|
||||||
|
static bool StandardErrHasColors();
|
||||||
|
|
||||||
|
/// Whether changing colors requires the output to be flushed.
|
||||||
|
/// This is needed on systems that don't support escape sequences for
|
||||||
|
/// changing colors.
|
||||||
|
static bool ColorNeedsFlush();
|
||||||
|
|
||||||
|
/// This function returns the colorcode escape sequences, and sets Len to
|
||||||
|
/// the length of the escape sequence.
|
||||||
|
/// If ColorNeedsFlush() is true then this function will change the colors
|
||||||
|
/// and return an empty escape sequence. In that case it is the
|
||||||
|
/// responsibility of the client to flush the output stream prior to
|
||||||
|
/// calling this function.
|
||||||
|
static const char *OutputColor(char c, bool bold, bool bg);
|
||||||
|
|
||||||
|
/// Same as OutputColor, but only enables the bold attribute.
|
||||||
|
static const char *OutputBold(bool bg);
|
||||||
|
|
||||||
|
/// Resets the terminals colors, or returns an escape sequence to do so.
|
||||||
|
static const char *ResetColor();
|
||||||
/// @}
|
/// @}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Support/Format.h"
|
#include "llvm/Support/Format.h"
|
||||||
#include "llvm/System/Program.h"
|
#include "llvm/System/Program.h"
|
||||||
|
#include "llvm/System/Process.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/Config/config.h"
|
#include "llvm/Config/config.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
@ -301,6 +302,35 @@ uint64_t raw_fd_ostream::seek(uint64_t off) {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
|
||||||
|
bool bg) {
|
||||||
|
if (sys::Process::ColorNeedsFlush())
|
||||||
|
flush();
|
||||||
|
const char *colorcode =
|
||||||
|
(colors == SAVEDCOLOR) ? sys::Process::OutputBold(bg)
|
||||||
|
: sys::Process::OutputColor(colors, bold, bg);
|
||||||
|
if (colorcode) {
|
||||||
|
unsigned len = strlen(colorcode);
|
||||||
|
write(colorcode, len);
|
||||||
|
// don't account colors towards output characters
|
||||||
|
pos -= len;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ostream &raw_fd_ostream::resetColor() {
|
||||||
|
if (sys::Process::ColorNeedsFlush())
|
||||||
|
flush();
|
||||||
|
const char *colorcode = sys::Process::ResetColor();
|
||||||
|
if (colorcode) {
|
||||||
|
unsigned len = strlen(colorcode);
|
||||||
|
write(colorcode, len);
|
||||||
|
// don't account colors towards output characters
|
||||||
|
pos -= len;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// raw_stdout/err_ostream
|
// raw_stdout/err_ostream
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -235,3 +235,62 @@ unsigned Process::StandardErrColumns() {
|
|||||||
|
|
||||||
return getColumns(2);
|
return getColumns(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool terminalHasColors() {
|
||||||
|
if (const char *term = std::getenv("TERM")) {
|
||||||
|
// Most modern terminals support ANSI escape sequences for colors.
|
||||||
|
// We could check terminfo, or have a list of known terms that support
|
||||||
|
// colors, but that would be overkill.
|
||||||
|
// The user can always ask for no colors by setting TERM to dumb, or
|
||||||
|
// using a commandline flag.
|
||||||
|
return strcmp(term, "dumb") != 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::StandardOutHasColors() {
|
||||||
|
if (!StandardOutIsDisplayed())
|
||||||
|
return false;
|
||||||
|
return terminalHasColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::StandardErrHasColors() {
|
||||||
|
if (!StandardErrIsDisplayed())
|
||||||
|
return false;
|
||||||
|
return terminalHasColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::ColorNeedsFlush() {
|
||||||
|
// No, we use ANSI escape sequences.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
|
||||||
|
|
||||||
|
#define ALLCOLORS(FGBG,BOLD) {\
|
||||||
|
COLOR(FGBG, "0", BOLD),\
|
||||||
|
COLOR(FGBG, "1", BOLD),\
|
||||||
|
COLOR(FGBG, "2", BOLD),\
|
||||||
|
COLOR(FGBG, "3", BOLD),\
|
||||||
|
COLOR(FGBG, "4", BOLD),\
|
||||||
|
COLOR(FGBG, "5", BOLD),\
|
||||||
|
COLOR(FGBG, "6", BOLD),\
|
||||||
|
COLOR(FGBG, "7", BOLD)\
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* colorcodes[2][2][8] = {
|
||||||
|
{ ALLCOLORS("3",""), ALLCOLORS("3","1;") },
|
||||||
|
{ ALLCOLORS("4",""), ALLCOLORS("4","1;") }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *Process::OutputColor(char code, bool bold, bool bg) {
|
||||||
|
return colorcodes[bg?1:0][bold?1:0][code&7];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Process::OutputBold(bool bg) {
|
||||||
|
return "\033[1m";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Process::ResetColor() {
|
||||||
|
return "\033[0m";
|
||||||
|
}
|
||||||
|
@ -147,4 +147,70 @@ unsigned Process::StandardErrColumns() {
|
|||||||
return Columns;
|
return Columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// it always has colors
|
||||||
|
bool Process::StandardErrHasColors() {
|
||||||
|
return StandardErrIsDisplayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::StandardOutHasColors() {
|
||||||
|
return StandardOutIsDisplayed();
|
||||||
|
}
|
||||||
|
namespace {
|
||||||
|
class DefaultColors
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
WORD defaultColor;
|
||||||
|
public:
|
||||||
|
DefaultColors()
|
||||||
|
:defaultColor(GetCurrentColor()) {}
|
||||||
|
static unsigned GetCurrentColor() {
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
|
||||||
|
return csbi.wAttributes;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
WORD operator()() const { return defaultColor; }
|
||||||
|
};
|
||||||
|
|
||||||
|
DefaultColors defaultColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::ColorNeedsFlush() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Process::OutputBold(bool bg) {
|
||||||
|
WORD colors = DefaultColors::GetCurrentColor();
|
||||||
|
if (bg)
|
||||||
|
colors |= BACKGROUND_INTENSITY;
|
||||||
|
else
|
||||||
|
colors |= FOREGROUND_INTENSITY;
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Process::OutputColor(char code, bool bold, bool bg) {
|
||||||
|
WORD colors;
|
||||||
|
if (bg) {
|
||||||
|
colors = ((code&1) ? BACKGROUND_RED : 0) |
|
||||||
|
((code&2) ? BACKGROUND_GREEN : 0 ) |
|
||||||
|
((code&4) ? BACKGROUND_BLUE : 0);
|
||||||
|
if (bold)
|
||||||
|
colors |= BACKGROUND_INTENSITY;
|
||||||
|
} else {
|
||||||
|
colors = ((code&1) ? FOREGROUND_RED : 0) |
|
||||||
|
((code&2) ? FOREGROUND_GREEN : 0 ) |
|
||||||
|
((code&4) ? FOREGROUND_BLUE : 0);
|
||||||
|
if (bold)
|
||||||
|
colors |= FOREGROUND_INTENSITY;
|
||||||
|
}
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Process::ResetColor() {
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user