feat(colors): adds 256 and 16M colors mode support in fmt

This commit is contained in:
Johann Dreo 2023-01-23 12:08:09 +01:00
commit 7955ec197f
6 changed files with 795 additions and 75 deletions

170
README.md
View file

@ -217,9 +217,9 @@ Output style
Output lines can be colored differently depending on the log level.
```cpp
// Print error messages in bold red:
log.style(clutchlog::level::error, // First, the log level.
clutchlog::fmt::fg::red, // Then the styles, in any order...
clutchlog::fmt::typo::bold);
log.style(level::error, // First, the log level.
fmt::fg::red, // Then the styles, in any order...
fmt::typo::bold);
```
Or, if you want to declare some semantics beforehand:
@ -227,40 +227,32 @@ Or, if you want to declare some semantics beforehand:
// Print warning messages in bold magenta:
using fmt = clutchlog::fmt;
fmt warn(fmt::fg::magenta, fmt::typo::bold);
log.style(clutchlog::level::warning, warn);
log.style(level::warning, warn);
```
Note: this inserts a style marker at the very beginning of the line.
If you add other styles later on the line, they will take precedence.
Using the `clutchlog::fmt` class, you can style:
Colors can be specified in several different ways.
The ANSI color mode will be automatically detected,
depending on the types of arguments passed to styling functions:
- named tags from `clutchlog::fmt::fg` or `clutchlog::fmt::bg` will encode a 16-colors mode,
- integers will encode a 256-colors mode,
- numeric triplets or web hex strings will encode a 16 million ("true") colors mode,
- `clutchlog::fg::none` and `clutchlog::bg::none` can be passed in all modes.
- the foreground color, passing a `clutchlog::fmt::fg`,
- the background color, passing a `clutchlog::fmt::bg`,
- some typographic style, passing a `clutchlog::fmt::typo`.
Any of the three arguments may be passed, in any order,
if an argument is omitted, it defaults to no color/style.
Available colors are:
- black,
- red,
- green,
- yellow,
- blue,
- magenta,
- cyan,
- white,
- none.
Available typographies:
- reset (remove any style),
- bold,
- underline,
- inverse,
- none.
For example, all the following lines encode
a bright red foreground for the critical level:
```cpp
log.style(level:critical,
fmt::fg::red); // 16-colors mode.
log.style(level:critical,
255); // 256-colors mode.
log.style(level:critical,
255,0,0); // 16M-colors mode.
log.style(level:critical,
"#ff0000"); // 16M-colors mode again.
```
You may use styling within the format message template itself, to add even more colors:
```cpp
@ -279,13 +271,97 @@ You may want to set their style to `none` if you want to stay in control of inse
The horizontal filling line (the `{hfill}` tag) can be configured separately with `clutchlog::hfill_style`,
for example:
```cpp
log.hfill_style(clutchlog::fmt::fg::black);
log.hfill_style(fmt::fg::black);
```
Note: this will actually reset any styling after the hfill,
disabling any style you would have set for the whole message using `clutchlog::format`
for the remaining of the message.
### Typographic Style
Available typographies:
- reset (remove any style),
- bold,
- underline,
- inverse,
- none.
Typographic styles are always passed with the named tag
(see `clutchlog::fmt::typo`), whatever the color mode.
### Colors
#### 16-colors mode
Using the `clutchlog::fmt` class, you can style:
- the foreground color, passing a `clutchlog::fmt::fg`,
- the background color, passing a `clutchlog::fmt::bg`.
In 16-colors mode, any of the arguments may be passed, in any order,
if an argument is omitted, it defaults to no color/style.
Available colors are:
- black,
- red,
- green,
- yellow,
- blue,
- magenta,
- cyan,
- white,
- bright_black,
- bright_red,
- bright_green,
- bright_yellow,
- bright_blue,
- bright_magenta,
- bright_cyan,
- bright_white,
- none.
Note: some terminals allow the user to configure the actual encoding of
those colors. You may thus notice some difference with the expected rendering
of the same colors encoded in the other modes. Use the other color modes if you
want to fully control the actual color rendering.
#### 256-colors mode
For 256-colors mode, colors are expected to be passed as integers in [-1,255]
or the `fg::none` and `bg::none` tags.
In 256-colors mode, if you want to only encode the background color,
you cannot just omit the foreground color,
you have to bass a `fg::none` tag as first argument.
```cpp
log.style(level::info, fg::none, 52); // No color over dark red.
log.style(level::info, fg::none, 52, typo::bold); // No color over bold dark red.
```
#### 16 million colors mode (RGB)
For 16M-colors mode, colors can be encoded as:
- three integer arguments,
- a "web color" hexadecimal triplet string, starting with a leading number sign (e.g. "#0055ff").
- the `fg::none` and `bg::none` tags.
In 16M-colors mode, if you want to only encode the background color,
you cannot just omit the foreground color,
you have to pass a `fg::none` tag as first argument.
```cpp
log.style(level::info, fg::none, 100,0,0); // No color over dark red.
log.style(level::info, fg::none, 100,0,0, typo::bold); // No color over bold dark red.
```
Advanced Usage
==============
@ -491,6 +567,36 @@ And here are all the functions you may call to log something:
ASSERT(x>0);
```
Here what you would do to setup clutchlog with the default configuration
using 16M-colors mode:
```cpp
auto& log = clutchlog::logger();
log.out(std::clog);
// Location filtering.
log.depth(std::numeric_limits<size_t>::max());
log.threshold("Error");
log.file(".*");
log.func(".*");
log.line(".*");
// Colors of the 3 firsts levels.
log.style(clutchlog::level::critical, clutchlog::fmt(
"#ff0000",
clutchlog::fmt::typo::underline);
log.style(clutchlog::level::error, clutchlog::fmt(
"#ff0000",
clutchlog::fmt::typo::bold);
log.style(clutchlog::level::warning, clutchlog::fmt(
"#ff00ff",
clutchlog::fmt::typo::bold);
// Assuming you are on a POSIX system.
log.format("[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\n");
log.depth_mark(">");
log.strip_calls(5);
log.hfill_char('.');
log.hfill_max(300);
log.hfill_style(clutchlog::fmt::fg::none);
```
Limitations
===========

View file

@ -308,11 +308,84 @@ class clutchlog
* @{ */
/** Color and style formatter for ANSI terminal escape sequences.
*
* The formatter supports typographic "styles" and colors.
* Typographic styles are available as named tag in `fmt::typo`.
*
* The formatter supports the three ANSI modes, which are automatically selected depending the argument types:
* - 16 colors (using named tags),
* - 256 colors (using integers),
* - 16 millions ("true") colors (using RGB integer triplets or web hex strings).
*
* For 16-colors mode, colors are named tag in:
* - `fmt::fg` for foreground colors.
* - `fmt::bg` for background colors.
*
* @note The order in which you pass foreground, background and style does not matter in 16-colors mode.
*
* The following colors are available for both foregrounds (see `fmt::fg`) and backgrounds (see `fmt::bg`):
* - none,
* - black,
* - red,
* - green,
* - yellow,
* - blue,
* - magenta,
* - cyan,
* - white,
* - bright_black (i.e. grey),
* - bright_red,
* - bright_green,
* - bright_yellow,
* - bright_blue,
* - bright_magenta,
* - bright_cyan,
* - bright_white.
*
* @note Some terminal are configured to display colored text set in bold
* using the bright color counterpart.
*
* For 256-colors mode, colors are expected to be passed as integers in [-1,255]
* or the `fg::none` and `bg::none` tags.
*
* @note In 256-colors mode, if you want to only encode the background color,
* you cannot just omit the foreground color,
* you have to bass a `fg::none` tag as first argument.
*
* For 16M-colors mode, colors can be encoded as:
* - three integer arguments,
* - a "web color" hexadecimal triplet string, starting with a leading number sign (e.g. "#0055ff").
* - the `fg::none` and `bg::none` tags.
*
* @note In 16M-colors mode, if you want to only encode the background color,
* you cannot just omit the foreground color,
* you have to bass a `fg::none` tag as first argument.
*
* @note All styles may not be supported by a given terminal/operating system.
*/
class fmt {
public:
//! ANSI code configuring the available number of colors.
enum class ansi {
//! 16 colors mode.
colors_16 = -1, // Not supposed to be casted.
//! 256 colors mode.
colors_256 = 5, // Casted as short in color::operator<<.
//! 16 millions ("true") colors mode.
colors_16M = 2 // Casted as short in color::operator<<
} /** Current ANSI color mode. */ mode;
//! Typographic style codes.
enum class typo {
reset = 0,
bold = 1,
underline = 4,
inverse = 7,
none = -1
} /** Typographic style. */ style;
/** @addtogroup colors16 Colors management in 16 colors mode (4-bits ANSI).
* @{ */
//! Foreground color codes.
enum class fg {
black = 30,
@ -323,8 +396,16 @@ class clutchlog
magenta = 35,
cyan = 36,
white = 37,
none
} /** Foreground color */ fore;
bright_black = 90,
bright_red = 91,
bright_green = 92,
bright_yellow = 93,
bright_blue = 94,
bright_magenta = 95,
bright_cyan = 96,
bright_white = 97,
none = -1
} /** Foreground color. */ fore;
//! Background color codes.
enum class bg {
@ -336,48 +417,351 @@ class clutchlog
magenta = 45,
cyan = 46,
white = 47,
none
} /** Background color */ back;
bright_black = 100,
bright_red = 101,
bright_green = 102,
bright_yellow = 103,
bright_blue = 104,
bright_magenta = 105,
bright_cyan = 106,
bright_white = 107,
none = -1
} /** Background color. */ back;
//! Typographic style codes.
enum class typo {
reset = 0,
bold = 1,
underline = 4,
inverse = 7,
none
} /** Typographic style*/ style;
protected:
//! Output stream operator for a 3-tuple of 16-colors mode tags.
friend std::ostream& operator<<(std::ostream& os, const std::tuple<fg,bg,typo>& fbs)
{
auto [f,b,s] = fbs;
std::vector<short> codes; codes.reserve(3);
if(f != fg::none) { codes.push_back(static_cast<short>(f));}
if(b != bg::none) { codes.push_back(static_cast<short>(b));}
if(s != typo::none) { codes.push_back(static_cast<short>(s));}
if(codes.size() == 0) {
return os;
//! Empty constructor, only useful for a no-op formatter.
fmt() : fore(fg::none), back(bg::none), style(typo::none) {}
} else {
os << "\033[";
os << codes[0];
for(size_t i=1; i < codes.size(); ++i) {
os << ";" << codes[i];
}
os << "m";
}
return os;
}
/** @name All combination of constructors with different parameters orders.
//! Output stream operator for a typo tag alone, in 16-colors mode.
friend std::ostream& operator<<(std::ostream& os, const typo& s)
{
if(s != typo::none) {
os << "\033[" << static_cast<short>(s) << "m";
}
return os;
}
/** @} colors16 */
protected:
/** @addtogroup colors256_16M Internal colors management in 256 and 16M colors modes.
* @{ */
fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) {}
fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) {}
/** Interface class for colors representation. */
struct color {
ansi mode; // Not const to allow for the implicit copy assignemnt operator.
//! Codes for representing foreground or background.
enum class ground { // idem.
fore = 38,
back = 48
} /** Type of color (foreground or background). */ type;
/** Constructor.
*
* @param a ANSI mode (i.e. number of colors).
* @param g Color type (i.e. foreground or background).
*/
color(ansi a, ground g) : mode(a), type(g) {}
//! Should return true if the underying representation encodes an existing color.
virtual bool is_set() const = 0;
//! Should print the underlying representation on the given stream.
virtual std::ostream& print_on( std::ostream& os) const = 0;
//! Print the actually encoded escaped color sequence on the given stream.
friend std::ostream& operator<<(std::ostream& os, const color& c)
{
if(c.is_set()) {
os << "\033[" << static_cast<short>(c.type) << ";" << static_cast<short>(c.mode) << ";";
c.print_on(os);
os << "m";
}
return os;
}
};
// There is no color_16 because it would be the same as color_256, only with different indices,
// hence making it more complicated for the user to select the right constructor.
// Here, we just use enum for 16 colors, and indices for 256 colors.
//! Abstract base class for 256 colors objects (8-bits ANSI).
struct color_256 : public color {
/** The encoded color index in 4-bits ANSI.
*
* "No color" is encoded as -1. */
short index;
/** Constructor
*
* @param t Foreground or background tag. */
color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
/** Constructor
*
* @param t Foreground or background tag.
* @param i Color index (within [-1,255], -1 being "no color").
*/
color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {assert(-1 <= i and i <= 255);}
//! Returns true if the underying representation encodes an existing color.
bool is_set() const {return index > -1;}
//! Print the color index on the given stream.
std::ostream& print_on( std::ostream& os) const
{
os << index;
return os;
}
};
//! Foreground in 256-colors mode.
struct fg_256 : public color_256 {
//! Empty constructor: no color.
fg_256() : color_256(ground::fore) {}
/** Constructor.
*
* @param f Foreground color index (within [-1,255], -1 being "no color"). */
fg_256(const short f) : color_256(ground::fore, f) {}
/** Conversion constructor from 16-colors mode.
*
* @warning Only encodes "no color", whatever is passed. */
fg_256(const fg&) : color_256(ground::fore, -1) {}
} /** Current foreground in 256-colors mode. */ fore_256;
//! Background in 256-colors mode.
struct bg_256 : public color_256 {
//! Empty constructor: no color.
bg_256() : color_256(ground::back) {}
/** Constructor.
*
* @param b Background color index (within [-1,255], -1 being "no color"). */
bg_256(const short b) : color_256(ground::back, b) {}
/** Conversion constructor from 16-colors mode.
*
* @warning Only encodes "no color", whatever is passed. */
bg_256(const bg&) : color_256(ground::back, -1) {}
} /** Current background in 256-colors mode. */ back_256;
//! Abstract base class for 16M colors objects (24-bits ANSI).
struct color_16M : public color {
/** The encoded RGB indices.
*
* "No color" is encoded as -1. */
short red, green, blue;
/** Constructor.
*
* @param t Foreground or background tag. */
color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
/** Numeric triplet constructor.
*
* @param t Foreground or background tag.
* @param r Red color component.
* @param g Green color component.
* @param b Blue color component.
*/
color_16M(ground t, short r, short g, short b)
: color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
/** Hex triplet string constructor.
*
* @note If the given string is ill-formed, it will silently encode a "no color".
*
* @param t Foreground or background tag.
* @param srgb A "web color" hexadecimal triplet of two characters, starting with a leading number sign (e.g. "#0055ff").
*/
color_16M(ground t, const std::string& srgb) : color(ansi::colors_16M, t)
{
assert(srgb.size() == 7);
if(srgb.size() != 7) {
red = -1;
green = -1;
blue = -1;
} else {
char i = 0;
if(srgb.at(0) == '#') {
i = 1;
}
std::istringstream(srgb.substr(0+i,2)) >> std::hex >> red;
std::istringstream(srgb.substr(2+i,2)) >> std::hex >> green;
std::istringstream(srgb.substr(4+i,2)) >> std::hex >> blue;
}
assert(-1 <= red and red <= 255);
assert(-1 <= green and green <= 255);
assert(-1 <= blue and blue <= 255);
}
//! Returns true if the underying representation encodes an existing color.
bool is_set() const {return red > -1 and green > -1 and blue > -1;}
//! Print the color RGB triplet on the given stream.
std::ostream& print_on( std::ostream& os) const
{
os << red << ";" << green << ";" << blue;
return os;
}
};
//! Foreground in 256-colors mode.
struct fg_16M : public color_16M {
//! Empty constructor: no color.
fg_16M() : color_16M(ground::fore) {}
/** Numeric triplet constructor.
*
* Parameters are expected to be in [0,255].
*
* @param r Red color component.
* @param g Green color component.
* @param b Blue color component.
*/
fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
/** Hex triplet string constructor.
*
* @note If the given string is ill-formed, it will silently encode a "no color".
*
* @param srgb A "web color" hexadecimal triplet of two characters, starting with a leading number sign (e.g. "#0055ff").
*/
fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
/** Conversion constructor from 16-colors mode.
*
* @warning Only encodes "no color", whatever is passed. */
fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
} /** Current foreground in 16M-colors mode. */ fore_16M;
//! background in 256-colors mode.
struct bg_16M : public color_16M {
//! Empty constructor: no color.
bg_16M() : color_16M(ground::back) {}
/** Numeric triplet constructor.
*
* Parameters are expected to be in [0,255].
*
* @param r Red color component.
* @param g Green color component.
* @param b Blue color component.
*/
bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
/** Hex triplet string constructor.
*
* @note If the given string is ill-formed, it will silently encode a "no color".
*
* @param srgb A "web color" hexadecimal triplet of two characters, starting with a leading number sign (e.g. "#0055ff").
*/
bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
/** Conversion constructor from 16-colors mode.
*
* @warning Only encodes "no color", whatever is passed. */
bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
} /** Current background in 16M-colors mode. */ back_16M;
/** @} colors256_16M */
public:
//! Empty constructor, only useful for a no-op formatter.
fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
/** @name All combination of 16-colors mode constructors with different parameters orders.
* @{ */
fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
/** @} */
/** @name All combination of 256-colors mode constructors with different parameters orders.
* @{ */
fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
/** @} */
/** @name All combination of 16M-colors mode constructors with different parameters orders.
* @{ */
fmt(const short fr, const short fg, const short fb,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
fmt(fg,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
fmt(const short fr, const short fg, const short fb,
bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const short fr, const short fg, const short fb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const std::string& f, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
fmt(fg, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
fmt(const std::string& f, bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
fmt(const std::string& f, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
/** @} */
protected:
//! Print the currently encoded format escape code on the given output stream.
std::ostream& print_on( std::ostream& os) const
{
std::vector<int> codes; codes.reserve(3);
if(this->fore != fg::none) { codes.push_back(static_cast<int>(this->fore ));}
if(this->back != bg::none) { codes.push_back(static_cast<int>(this->back ));}
if(this->style != typo::none) { codes.push_back(static_cast<int>(this->style));}
if(codes.size() == 0) {return os;}
if(mode == ansi::colors_16) {
// Print all in a single escape.
os << std::make_tuple(fore,back,style);
os << "\033[";
assert(codes.size() > 0);
os << codes[0];
for(size_t i=1; i < codes.size(); ++i) {
os << ";" << codes[i];
} else {
// 256 or 16M: always print separated escapes for foreground/background.
if(mode == ansi::colors_256) {
os << fore_256;
os << back_256;
} else if(mode == ansi::colors_16M) {
os << fore_16M;
os << back_16M;
}
// In any case, print the style separately.
os << style;
}
os << "m";
return os;
}
@ -999,21 +1383,99 @@ class clutchlog
enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
class fmt {
public:
enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore;
enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back;
enum class typo { reset, bold, underline, inverse, none } style;
fmt() : fore(fg::none), back(bg::none), style(typo::none) {}
fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) {}
fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) {}
enum class ansi { colors_16, colors_256, colors_16M} mode;
enum class typo { reset, bold, underline, inverse, none} style;
enum class fg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none} fore;
enum class bg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none } back;
protected:
std::ostream& print_on(std::ostream&) const {}
friend std::ostream& operator<<(std::ostream&, const std::tuple<fg,bg,typo>&) {}
friend std::ostream& operator<<(std::ostream&, const typo&) {}
protected:
struct color {
ansi mode;
enum class ground { fore, back } type;
color(ansi a, ground g) : mode(a), type(g) {}
virtual bool is_set() const = 0;
virtual std::ostream& print_on( std::ostream&) const = 0;
friend std::ostream& operator<<(std::ostream&, const color&) {}
};
struct color_256 : public color {
short index;
color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {}
bool is_set() const {}
std::ostream& print_on( std::ostream&) const {}
};
struct fg_256 : public color_256 {
fg_256() : color_256(ground::fore) {}
fg_256(const short f) : color_256(ground::fore, f) {}
fg_256(const fg&) : color_256(ground::fore, -1) {}
} fore_256;
struct bg_256 : public color_256 {
bg_256() : color_256(ground::back) {}
bg_256(const short b) : color_256(ground::back, b) {}
bg_256(const bg&) : color_256(ground::back, -1) {}
} back_256;
struct color_16M : public color {
short red, green, blue;
color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
color_16M(ground t, short r, short g, short b) : color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
color_16M(ground t, const std::string&) : color(ansi::colors_16M, t) {}
bool is_set() const {return red > -1 and green > -1 and blue > -1;}
std::ostream& print_on( std::ostream&) const {}
};
struct fg_16M : public color_16M {
fg_16M() : color_16M(ground::fore) {}
fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
} fore_16M;
struct bg_16M : public color_16M {
bg_16M() : color_16M(ground::back) {}
bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
} back_16M;
public:
fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
fmt(const short fr, const short fg, const short fb,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
fmt(fg,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
fmt(const short fr, const short fg, const short fb,
bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const short fr, const short fg, const short fb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const std::string& f, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
fmt(fg, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
fmt(const std::string& f, bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
fmt(const std::string& f, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
protected:
std::ostream& print_on( std::ostream&) const {}
public:
friend std::ostream& operator<<(std::ostream&, const fmt&) {}
std::string operator()(const std::string&) const {}
std::string operator()( const std::string&) const {}
std::string str() const {}
};
public:
clutchlog(clutchlog const&) = delete;

47
tests/t-color16M.cpp Normal file
View file

@ -0,0 +1,47 @@
#include <iostream>
#include <limits>
#include "../clutchlog/clutchlog.h"
int main(/*const int argc, char* argv[]*/)
{
using typo = clutchlog::fmt::typo;
// using fg = clutchlog::fmt::fg;
// using bg = clutchlog::fmt::bg;
clutchlog::fmt none;
clutchlog::fmt end(typo::reset);
clutchlog::fmt note(typo::bold);
clutchlog::fmt info(120,255,120); // greenish
clutchlog::fmt warning("#ff0055", typo::bold); // magentaish
clutchlog::fmt error(255,100,150, typo::bold); // redish magenta
clutchlog::fmt critical("#ffff00", "#ff0000"); // Yellow over red.
auto& log = clutchlog::logger();
log.threshold(clutchlog::level::info);
// Change a style.
log.style(clutchlog::level::critical, error);
CLUTCHLOG(critical,"Styles demo");
CLUTCHLOG(info,"Either using functions...");
std::cout << none("No style: ") << std::endl;
std::cout << note("NOTE: bold") << std::endl;
std::cout << info("INFO: green") << std::endl;
CLUTCHLOG(info,"... or tags.");
std::cout << warning << "WARNING" << end << ": bold magenta" << std::endl;
std::cout << error << "ERROR" << end << ": bold red" << std::endl;
std::cout << critical << "CRITICAL" << end << ": underlined black over red background" << std::endl;
std::ostringstream format;
clutchlog::fmt discreet("#888888", typo::inverse);
format << "{level}: "
<< discreet("{file}") << ":"
<< clutchlog::fmt(/*front RGB*/200,150,0, /*back RGB*/0,0,0) << "{line}" // gold yellow over black
<< clutchlog::fmt(typo::reset) << " {msg} ! " << std::endl;
log.format(format.str());
CLUTCHLOG(critical,"After having inserted styles within a new format template");
}

46
tests/t-color256.cpp Normal file
View file

@ -0,0 +1,46 @@
#include <iostream>
#include <limits>
#include "../clutchlog/clutchlog.h"
int main(/*const int argc, char* argv[]*/)
{
using typo = clutchlog::fmt::typo;
// using fg = clutchlog::fmt::fg;
// using bg = clutchlog::fmt::bg;
clutchlog::fmt none;
clutchlog::fmt end(typo::reset);
clutchlog::fmt note(typo::bold);
clutchlog::fmt info(106); // greenish
clutchlog::fmt warning(171, typo::bold); // magentaish
clutchlog::fmt error(198, typo::bold); // redish magenta
clutchlog::fmt critical(226, 196, typo::underline); // Yellow over red.
auto& log = clutchlog::logger();
log.threshold(clutchlog::level::info);
// Change a style.
log.style(clutchlog::level::critical, error);
CLUTCHLOG(critical,"Styles demo");
CLUTCHLOG(info,"Either using functions...");
std::cout << none("No style: ") << std::endl;
std::cout << note("NOTE: bold") << std::endl;
std::cout << info("INFO: green") << std::endl;
CLUTCHLOG(info,"... or tags.");
std::cout << warning << "WARNING" << end << ": bold magenta" << std::endl;
std::cout << error << "ERROR" << end << ": bold red" << std::endl;
std::cout << critical << "CRITICAL" << end << ": underlined black over red background" << std::endl;
std::ostringstream format;
clutchlog::fmt discreet(254);
format << "{level}: "
<< discreet("{file}:")
<< clutchlog::fmt(220, typo::inverse) << "{line}" // gold yellow
<< clutchlog::fmt(typo::reset) << " {msg} ! " << std::endl;
log.format(format.str());
CLUTCHLOG(critical,"After having inserted styles within a new format template");
}

View file

@ -0,0 +1,45 @@
#include <iostream>
#include <limits>
#include "../clutchlog/clutchlog.h"
int main(/*const int argc, char* argv[]*/)
{
using fmt = clutchlog::fmt;
using fg = clutchlog::fmt::fg;
using bg = clutchlog::fmt::bg;
using typo = clutchlog::fmt::typo;
fmt none;
fmt c16_full(fg::red , bg::black , typo::bold);
fmt c16_nofg(bg::black , typo::bold);
fmt c16_nobg(fg::red , typo::bold);
fmt c16_fg (fg::red );
fmt c16_bg (bg::red );
fmt c16_typo(typo::bold);
fmt c16_bft (bg::black , fg::red , typo::bold);
fmt c16_bgfg(bg::black , fg::red );
fmt c16_tbf (typo::bold, bg::black , fg::red );
fmt c16_tfb (typo::bold, fg::red , bg::black );
fmt c16_tf (typo::bold, fg::red );
fmt c16_tb (typo::bold, bg::black );
fmt c256_fbt(196 , 236 , typo::bold);
fmt c256_ft (196 , typo::bold);
fmt c256_fb (196 , 236 );
fmt c256_nbt(fg::none, 236 , typo::bold);
fmt c256_fnt(196 , bg::none , typo::bold);
fmt c256_nb (fg::none, 236 );
fmt c256_fn (196 , bg::none );
fmt c16M_fbt(255,10,10 , 10,10,20 , typo::bold);
fmt c16M_ft (255,10,10 , typo::bold);
fmt c16M_fb (255,10,10 , 10,10,20 );
fmt c16M_nbt(fg::none , 10,10,20 , typo::bold);
fmt c16M_fnt(255,10,10 , bg::none , typo::bold);
fmt c16M_nb (fg::none , 10,10,20 );
fmt c16M_fn (255,10,10 , bg::none );
}

14
tests/t-one-line-if.cpp Normal file
View file

@ -0,0 +1,14 @@
#include "../clutchlog/clutchlog.h"
int main()
{
if(true)
CLUTCHLOG(error, "WHAT?");
else
CLUTCHLOG(info, "OH!");
if(false)
CLUTCHLOG(info, "AH!");
else
CLUTCHLOG(error, "NO!");
}