diff --git a/README.md b/README.md index 2a891b2..e18f246 100644 --- a/README.md +++ b/README.md @@ -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::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 =========== diff --git a/clutchlog/clutchlog.h b/clutchlog/clutchlog.h index 954a201..e06c075 100644 --- a/clutchlog/clutchlog.h +++ b/clutchlog/clutchlog.h @@ -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& fbs) + { + auto [f,b,s] = fbs; + std::vector codes; codes.reserve(3); + if(f != fg::none) { codes.push_back(static_cast(f));} + if(b != bg::none) { codes.push_back(static_cast(b));} + if(s != typo::none) { codes.push_back(static_cast(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(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(c.type) << ";" << static_cast(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 codes; codes.reserve(3); - if(this->fore != fg::none) { codes.push_back(static_cast(this->fore ));} - if(this->back != bg::none) { codes.push_back(static_cast(this->back ));} - if(this->style != typo::none) { codes.push_back(static_cast(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&) {} + 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; diff --git a/tests/t-color16M.cpp b/tests/t-color16M.cpp new file mode 100644 index 0000000..0811456 --- /dev/null +++ b/tests/t-color16M.cpp @@ -0,0 +1,47 @@ +#include +#include + +#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"); +} + + diff --git a/tests/t-color256.cpp b/tests/t-color256.cpp new file mode 100644 index 0000000..00420f7 --- /dev/null +++ b/tests/t-color256.cpp @@ -0,0 +1,46 @@ +#include +#include + +#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"); +} + diff --git a/tests/t-fmt-constructors.cpp b/tests/t-fmt-constructors.cpp new file mode 100644 index 0000000..65da41a --- /dev/null +++ b/tests/t-fmt-constructors.cpp @@ -0,0 +1,45 @@ +#include +#include + +#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 ); +} + + + diff --git a/tests/t-one-line-if.cpp b/tests/t-one-line-if.cpp new file mode 100644 index 0000000..bcccba4 --- /dev/null +++ b/tests/t-one-line-if.cpp @@ -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!"); +}