From d87404b23b56c51726decd57a79596fe3c35f68e Mon Sep 17 00:00:00 2001 From: Nicolas Lesser Date: Sun, 9 Dec 2018 17:03:43 +0100 Subject: [PATCH] Add support for builtin terminal colors. --- include/fmt/color.h | 71 +++++++++++++++++++++++++++++++++++++--- test/format-impl-test.cc | 10 ++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/include/fmt/color.h b/include/fmt/color.h index 20399210..ea327a3d 100644 --- a/include/fmt/color.h +++ b/include/fmt/color.h @@ -191,6 +191,25 @@ enum class color : uint32_t { yellow_green = 0x9ACD32 // rgb(154,205,50) }; // enum class color +enum class terminal_color : uint8_t { + black = 30, + red, + green, + yellow, + blue, + magenta, + cyan, + white, + bright_black = 90, + bright_red, + bright_green, + bright_yellow, + bright_blue, + bright_magenta, + bright_cyan, + bright_white +}; // enum class terminal_color + enum class emphasis : uint8_t { bold = 1, italic = 1 << 1, @@ -198,18 +217,23 @@ enum class emphasis : uint8_t { strikethrough = 1 << 3 }; // enum class emphasis -// rgb is a struct for red, green and blue colors. +// rgb is a struct for red, green and blue colors plus an extra byte to store +// a terminal color. // We use rgb as name because some editors will show it as color direct in the // editor. struct rgb { - FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR_DECL rgb() : t(0), r(0), g(0), b(0) {} FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_) - : r(r_), g(g_), b(b_) {} + : t(0), r(r_), g(g_), b(b_) {} FMT_CONSTEXPR_DECL rgb(uint32_t hex) - : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {} + : t((hex >> 24) & 0xFF), r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), + b((hex)&0xFF) {} FMT_CONSTEXPR_DECL rgb(color hex) - : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), + : t(0), r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), b(uint32_t(hex) & 0xFF) {} + FMT_CONSTEXPR_DECL rgb(terminal_color hex) FMT_NOEXCEPT + : t(uint8_t(hex)), r(0), g(0), b(0) {} + uint8_t t; // terminal color uint8_t r; uint8_t g; uint8_t b; @@ -315,7 +339,11 @@ private: } friend FMT_CONSTEXPR_DECL text_style fg(rgb foreground) FMT_NOEXCEPT; + friend FMT_CONSTEXPR_DECL text_style fg(terminal_color foreground) + FMT_NOEXCEPT; friend FMT_CONSTEXPR_DECL text_style bg(rgb background) FMT_NOEXCEPT; + friend FMT_CONSTEXPR_DECL text_style bg(terminal_color background) + FMT_NOEXCEPT; rgb foreground_color; rgb background_color; @@ -328,10 +356,18 @@ FMT_CONSTEXPR text_style fg(rgb foreground) FMT_NOEXCEPT { return text_style(/*is_foreground=*/true, foreground); } +FMT_CONSTEXPR_DECL text_style fg(terminal_color foreground) FMT_NOEXCEPT { + return text_style(/*is_foreground=*/true, foreground); +} + FMT_CONSTEXPR text_style bg(rgb background) FMT_NOEXCEPT { return text_style(/*is_foreground=*/false, background); } +FMT_CONSTEXPR_DECL text_style bg(terminal_color background) FMT_NOEXCEPT { + return text_style(/*is_foreground=*/false, background); +} + FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { return text_style(lhs) | rhs; } @@ -341,6 +377,31 @@ namespace internal { template struct ansi_color_escape { FMT_CONSTEXPR ansi_color_escape(rgb color, const char * esc) FMT_NOEXCEPT { + // If we have a terminal color, we need to output another escape code + // sequence. + if (color.t) { + bool is_background = esc == internal::data::BACKGROUND_COLOR; + // Background ASCII codes are the same as the foreground ones but with + // 10 more. + if (is_background) + color.t += 10; + + std::size_t index = 0; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + + if (color.t >= 100) { + buffer[index++] = static_cast('1'); + color.t %= 100; + } + buffer[index++] = static_cast('0' + color.t / 10); + buffer[index++] = static_cast('0' + color.t % 10); + + buffer[index++] = static_cast('m'); + buffer[index++] = static_cast('\0'); + return; + } + for (int i = 0; i < 7; i++) { buffer[i] = static_cast(esc[i]); } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index c40fe3b5..af53242f 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -228,4 +228,14 @@ TEST(ColorsTest, Colors) { stdout, fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"), "\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m"); + EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"), + "\x1b[31mtred\x1b[0m"); + EXPECT_WRITE(stdout, fmt::print(bg(fmt::terminal_color::cyan), "tcyan"), + "\x1b[46mtcyan\x1b[0m"); + EXPECT_WRITE(stdout, + fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"), + "\x1b[92mtbgreen\x1b[0m"); + EXPECT_WRITE(stdout, + fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"), + "\x1b[105mtbmagenta\x1b[0m"); }