From 73c53d7833cd66d5f2994f2cc215df6411e0a55a Mon Sep 17 00:00:00 2001 From: Daniela Engert Date: Mon, 17 Sep 2018 18:21:24 +0200 Subject: [PATCH] Parameterize 'printf(rgb color, ...)' and 'vprint_rgb(rgb color, ...)' on the type of the format string. Signed-off-by: Daniela Engert --- include/fmt/color.h | 139 ++++++++++++++++++++++++++------------- include/fmt/format-inl.h | 2 + include/fmt/format.h | 2 + 3 files changed, 99 insertions(+), 44 deletions(-) diff --git a/include/fmt/color.h b/include/fmt/color.h index 4973976a..a1ee3b03 100644 --- a/include/fmt/color.h +++ b/include/fmt/color.h @@ -209,8 +209,85 @@ struct rgb { uint8_t b; }; -void vprint_rgb(rgb fd, string_view format, format_args args); -void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args); +namespace internal { + +template +struct ansi_color_escape { + FMT_CONSTEXPR ansi_color_escape(rgb color, const char * esc) FMT_NOEXCEPT { + for (int i = 0; i < 7; i++) { + buffer[i] = static_cast(esc[i]); + } + to_esc(color.r, buffer + 7, ';'); + to_esc(color.g, buffer + 11, ';'); + to_esc(color.b, buffer + 15, 'm'); + buffer[19] = static_cast(0); + } + FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; } + +private: + Char buffer[7 + 3 * 4 + 1]; + + static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out, char delimiter) FMT_NOEXCEPT { + out[0] = static_cast('0' + c / 100); + out[1] = static_cast('0' + c / 10 % 10); + out[2] = static_cast('0' + c % 10); + out[3] = static_cast(delimiter); + } +}; + +template +FMT_CONSTEXPR ansi_color_escape +make_foreground_color(rgb color) FMT_NOEXCEPT { + return ansi_color_escape(color, internal::data::FOREGROUND_COLOR); +} + +template +FMT_CONSTEXPR ansi_color_escape +make_background_color(rgb color) FMT_NOEXCEPT { + return ansi_color_escape(color, internal::data::BACKGROUND_COLOR); +} + +template +inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT { + std::fputs(chars, stream); +} + +template <> +inline void fputs(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT { + std::fputws(chars, stream); +} + +template +inline void reset_color(FILE *stream) FMT_NOEXCEPT { + fputs(internal::data::RESET_COLOR, stream); +} + +template <> +inline void reset_color(FILE *stream) FMT_NOEXCEPT { + fputs(internal::data::WRESET_COLOR, stream); +} +} // namespace internal + +template < + typename String, + typename Char = typename internal::format_string_traits::char_type> +void vprint_rgb(rgb fd, const String &format, + basic_format_args::type> args) { + internal::fputs(internal::make_foreground_color(fd), stdout); + vprint(format, args); + internal::reset_color(stdout); +} + +template < + typename String, + typename Char = typename internal::format_string_traits::char_type> +void vprint_rgb(rgb fd, rgb bg, const String &format, + basic_format_args::type> args) { + internal::fputs(internal::make_foreground_color(fd), stdout); + internal::fputs(internal::make_background_color(bg), stdout); + vprint(format, args); + internal::reset_color(stdout); +} /** Formats a string and prints it to stdout using ANSI escape sequences to @@ -218,9 +295,14 @@ void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args); Example: fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23); */ -template -inline void print(rgb fd, string_view format_str, const Args & ... args) { - vprint_rgb(fd, format_str, make_format_args(args...)); +template +typename std::enable_if::value>::type +print(rgb fd, const String &format_str, const Args & ... args) { + internal::check_format_string(format_str); + typedef typename internal::format_string_traits::char_type char_t; + typedef typename buffer_context::type context_t; + format_arg_store as{args...}; + vprint_rgb(fd, format_str, basic_format_args(as)); } /** @@ -230,45 +312,14 @@ inline void print(rgb fd, string_view format_str, const Args & ... args) { fmt::print(fmt::color::red, fmt::color::black, "Elapsed time: {0:.2f} seconds", 1.23); */ -template -inline void print(rgb fd, rgb bg, string_view format_str, - const Args & ... args) { - vprint_rgb(fd, bg, format_str, make_format_args(args...)); -} -namespace internal { -FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) { - out[offset + 0] = static_cast('0' + c / 100); - out[offset + 1] = static_cast('0' + c / 10 % 10); - out[offset + 2] = static_cast('0' + c % 10); -} -} // namespace internal - -inline void vprint_rgb(rgb fd, string_view format, format_args args) { - char escape_fd[] = "\x1b[38;2;000;000;000m"; - internal::to_esc(fd.r, escape_fd, 7); - internal::to_esc(fd.g, escape_fd, 11); - internal::to_esc(fd.b, escape_fd, 15); - - std::fputs(escape_fd, stdout); - vprint(format, args); - std::fputs(internal::data::RESET_COLOR, stdout); -} - -inline void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) { - char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color - char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color - internal::to_esc(fd.r, escape_fd, 7); - internal::to_esc(fd.g, escape_fd, 11); - internal::to_esc(fd.b, escape_fd, 15); - - internal::to_esc(bg.r, escape_bg, 7); - internal::to_esc(bg.g, escape_bg, 11); - internal::to_esc(bg.b, escape_bg, 15); - - std::fputs(escape_fd, stdout); - std::fputs(escape_bg, stdout); - vprint(format, args); - std::fputs(internal::data::RESET_COLOR, stdout); +template +typename std::enable_if::value>::type +print(rgb fd, rgb bg, const String &format_str, const Args & ... args) { + internal::check_format_string(format_str); + typedef typename internal::format_string_traits::char_type char_t; + typedef typename buffer_context::type context_t; + format_arg_store as{args...}; + vprint_rgb(fd, bg, format_str, basic_format_args(as)); } #endif diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 56c4d581..24403cec 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -337,6 +337,8 @@ const int16_t basic_data::POW10_EXPONENTS[] = { 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; +template const char basic_data::FOREGROUND_COLOR[] = "\x1b[38;2;"; +template const char basic_data::BACKGROUND_COLOR[] = "\x1b[48;2;"; template const char basic_data::RESET_COLOR[] = "\x1b[0m"; template const wchar_t basic_data::WRESET_COLOR[] = L"\x1b[0m"; diff --git a/include/fmt/format.h b/include/fmt/format.h index a98f4568..3d75065f 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -888,6 +888,8 @@ struct FMT_API basic_data { static const uint64_t POW10_SIGNIFICANDS[]; static const int16_t POW10_EXPONENTS[]; static const char DIGITS[]; + static const char FOREGROUND_COLOR[]; + static const char BACKGROUND_COLOR[]; static const char RESET_COLOR[]; static const wchar_t WRESET_COLOR[]; };