patterncppMinor
Colorful output on terminal
Viewed 0 times
terminaloutputcolorful
Problem
I went from manually outputting escape codes in each string to creating a utility struct/class full of static functions and variables that needed to be initialized in source files (static private members are required to) which was a bit ugly for me. Then I was searching for something different and while playing with enums, I found it interesting for my scenario. And then I carefully used namespaces to construct my sort-of function only header and here it is. Also, I'm not supporting pre-C++11 version of compilers.
My aims were – not to use classes since they became ugly with lots of static members and creating an object and using it for colouring doesn't looks so good (however I might try that in future), and to make it fast and also modern C++ish. Along the way, some neat tricks with C++ namespaces made it possible to sort of hide (well at least to code completions) my non-interface elements and give a nice shape to the code.
*I also want to reduce some not so necessary headers (e.g. `
#ifndef RANG_H
#define RANG_H
#include
#include
#include
extern "C" {
#include
}
namespace rang {
enum class style : unsigned char {
Reset = 0,
bold = 1,
dim = 2,
italic = 3,
underline = 4,
blink = 5,
reversed = 6,
conceal = 7,
crossed = 8
};
enum class fg : unsigned char {
def = 39,
black = 30,
red = 31,
green = 32,
yellow = 33,
blue = 34,
magenta = 35,
cyan = 36,
gray = 37
};
enum class bg : unsigned char {
def = 49,
black = 40,
red = 41,
green = 42,
yellow = 43,
blue = 44,
magenta = 45,
cyan = 46,
gray = 47
};
}
namespace {
bool isAllowed = false;
bool isTerminal()
{
return isatty(STDOUT_FILENO);
}
bool supportsColor()
My aims were – not to use classes since they became ugly with lots of static members and creating an object and using it for colouring doesn't looks so good (however I might try that in future), and to make it fast and also modern C++ish. Along the way, some neat tricks with C++ namespaces made it possible to sort of hide (well at least to code completions) my non-interface elements and give a nice shape to the code.
*I also want to reduce some not so necessary headers (e.g. `
) if possible.
``#ifndef RANG_H
#define RANG_H
#include
#include
#include
extern "C" {
#include
}
namespace rang {
enum class style : unsigned char {
Reset = 0,
bold = 1,
dim = 2,
italic = 3,
underline = 4,
blink = 5,
reversed = 6,
conceal = 7,
crossed = 8
};
enum class fg : unsigned char {
def = 39,
black = 30,
red = 31,
green = 32,
yellow = 33,
blue = 34,
magenta = 35,
cyan = 36,
gray = 37
};
enum class bg : unsigned char {
def = 49,
black = 40,
red = 41,
green = 42,
yellow = 43,
blue = 44,
magenta = 45,
cyan = 46,
gray = 47
};
}
namespace {
bool isAllowed = false;
bool isTerminal()
{
return isatty(STDOUT_FILENO);
}
bool supportsColor()
Solution
I have a few comments.
-
You use
-
The repetition of having three implementations of
This seems much cleaner and more readable, at least to me.
-
You use
isatty to check whether standard output is connected to a terminal, regardless of what stream you're writing to. This means the rest of the functions only work correctly if you pass std::cout as the stream to which they're going to write. Otherwise, you may allow formatting when writing to something that's not a TTY, and you may prohibit formatting when writing to something that is a TTY.-
The repetition of having three implementations of
operator
-
Maybe it's just me, but every time I see code like:
isAllowed = isTerminal() && supportsColor() ? true : false;
... I grit my teeth. The result from isTeriminal() && supportsColor() is already a perfectly good bool`--you can use it directly:isAllowed = isTerminal() && supportsColor();This seems much cleaner and more readable, at least to me.
Code Snippets
isAllowed = isTerminal() && supportsColor() ? true : false;isAllowed = isTerminal() && supportsColor();Context
StackExchange Code Review Q#120777, answer score: 5
Revisions (0)
No revisions yet.