From 1d7886a27a6f1971e7e6fe84eb9e867bb9322161 Mon Sep 17 00:00:00 2001 From: Patrick Rotsaert Date: Sun, 16 Jun 2024 18:33:17 +0200 Subject: [PATCH] #1838 Factor out ANSI coloring. Purpose to make the ANSI coloring code reusable in new sink types. --- include/spdlog/details/ansicolors-inl.h | 57 ++++++++++++++++++ include/spdlog/details/ansicolors.h | 72 +++++++++++++++++++++++ include/spdlog/sinks/ansicolor_sink-inl.h | 37 +++--------- include/spdlog/sinks/ansicolor_sink.h | 60 +++++++++---------- src/spdlog.cpp | 1 + 5 files changed, 169 insertions(+), 58 deletions(-) create mode 100644 include/spdlog/details/ansicolors-inl.h create mode 100644 include/spdlog/details/ansicolors.h diff --git a/include/spdlog/details/ansicolors-inl.h b/include/spdlog/details/ansicolors-inl.h new file mode 100644 index 00000000..a583463b --- /dev/null +++ b/include/spdlog/details/ansicolors-inl.h @@ -0,0 +1,57 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +namespace spdlog { +namespace details { + +SPDLOG_INLINE ansicolors::ansicolors() { + colors_.at(level::trace) = to_string_(white); + colors_.at(level::debug) = to_string_(cyan); + colors_.at(level::info) = to_string_(green); + colors_.at(level::warn) = to_string_(yellow_bold); + colors_.at(level::err) = to_string_(red_bold); + colors_.at(level::critical) = to_string_(bold_on_red); + colors_.at(level::off) = to_string_(reset); +} + +SPDLOG_INLINE void ansicolors::set_color(level::level_enum color_level, string_view_t color) { + colors_.at(static_cast(color_level)) = to_string_(color); +} + +SPDLOG_INLINE std::vector ansicolors::ranges( + const details::log_msg &msg, const memory_buf_t &formatted_msg) const { + std::vector result{}; + if (msg.color_range_end > msg.color_range_start) { + // before color range + if (msg.color_range_start > 0) { + result.push_back(string_view_t{formatted_msg.data(), msg.color_range_start}); + } + // in color range + result.push_back(string_view_t{colors_.at(static_cast(msg.level))}); + result.push_back(string_view_t{formatted_msg.data() + msg.color_range_start, + msg.color_range_end - msg.color_range_start}); + result.push_back(reset); + // after color range + if (msg.color_range_end < formatted_msg.size()) { + result.push_back(string_view_t{formatted_msg.data() + msg.color_range_end, + formatted_msg.size() - msg.color_range_end}); + } + } else // no color + { + result.push_back(string_view_t{formatted_msg.data(), formatted_msg.size()}); + } + return result; +} + +SPDLOG_INLINE std::string ansicolors::to_string_(const string_view_t &sv) { + return std::string(sv.data(), sv.size()); +} + +} // namespace details +} // namespace spdlog diff --git a/include/spdlog/details/ansicolors.h b/include/spdlog/details/ansicolors.h new file mode 100644 index 00000000..27c9441e --- /dev/null +++ b/include/spdlog/details/ansicolors.h @@ -0,0 +1,72 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include + +#include + +#include +#include + +namespace spdlog { +namespace details { + +class SPDLOG_API ansicolors { +public: + explicit ansicolors(); + ansicolors(const ansicolors&) = delete; + ansicolors& operator=(const ansicolors&) = delete; + + void set_color(level::level_enum color_level, string_view_t color); + + std::vector ranges(const details::log_msg& msg, + const memory_buf_t& formatted_msg) const; + + // Formatting codes + static constexpr const char* reset = "\033[m"; + static constexpr const char* bold = "\033[1m"; + static constexpr const char* dark = "\033[2m"; + static constexpr const char* underline = "\033[4m"; + static constexpr const char* blink = "\033[5m"; + static constexpr const char* reverse = "\033[7m"; + static constexpr const char* concealed = "\033[8m"; + static constexpr const char* clear_line = "\033[K"; + + // Foreground colors + static constexpr const char* black = "\033[30m"; + static constexpr const char* red = "\033[31m"; + static constexpr const char* green = "\033[32m"; + static constexpr const char* yellow = "\033[33m"; + static constexpr const char* blue = "\033[34m"; + static constexpr const char* magenta = "\033[35m"; + static constexpr const char* cyan = "\033[36m"; + static constexpr const char* white = "\033[37m"; + + /// Background colors + static constexpr const char* on_black = "\033[40m"; + static constexpr const char* on_red = "\033[41m"; + static constexpr const char* on_green = "\033[42m"; + static constexpr const char* on_yellow = "\033[43m"; + static constexpr const char* on_blue = "\033[44m"; + static constexpr const char* on_magenta = "\033[45m"; + static constexpr const char* on_cyan = "\033[46m"; + static constexpr const char* on_white = "\033[47m"; + + /// Bold colors + static constexpr const char* yellow_bold = "\033[33m\033[1m"; + static constexpr const char* red_bold = "\033[31m\033[1m"; + static constexpr const char* bold_on_red = "\033[1m\033[41m"; + +private: + std::array colors_; + static std::string to_string_(const string_view_t& sv); +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "ansicolors-inl.h" +#endif diff --git a/include/spdlog/sinks/ansicolor_sink-inl.h b/include/spdlog/sinks/ansicolor_sink-inl.h index 2194f67b..bafdaf66 100644 --- a/include/spdlog/sinks/ansicolor_sink-inl.h +++ b/include/spdlog/sinks/ansicolor_sink-inl.h @@ -17,24 +17,15 @@ template SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, color_mode mode) : target_file_(target_file), mutex_(ConsoleMutex::mutex()), - formatter_(details::make_unique()) - -{ + formatter_(details::make_unique()) { set_color_mode(mode); - colors_.at(level::trace) = to_string_(white); - colors_.at(level::debug) = to_string_(cyan); - colors_.at(level::info) = to_string_(green); - colors_.at(level::warn) = to_string_(yellow_bold); - colors_.at(level::err) = to_string_(red_bold); - colors_.at(level::critical) = to_string_(bold_on_red); - colors_.at(level::off) = to_string_(reset); } template SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, string_view_t color) { std::lock_guard lock(mutex_); - colors_.at(static_cast(color_level)) = to_string_(color); + colors_.set_color(color_level, color); } template @@ -46,15 +37,10 @@ SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg msg.color_range_end = 0; memory_buf_t formatted; formatter_->format(msg, formatted); - if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { - // before color range - print_range_(formatted, 0, msg.color_range_start); - // in color range - print_ccode_(colors_.at(static_cast(msg.level))); - print_range_(formatted, msg.color_range_start, msg.color_range_end); - print_ccode_(reset); - // after color range - print_range_(formatted, msg.color_range_end, formatted.size()); + if (should_do_colors_) { + for (const auto &range : colors_.ranges(msg, formatted)) { + print_view_(range); + } } else // no color { print_range_(formatted, 0, formatted.size()); @@ -71,7 +57,7 @@ SPDLOG_INLINE void ansicolor_sink::flush() { template SPDLOG_INLINE void ansicolor_sink::set_pattern(const std::string &pattern) { std::lock_guard lock(mutex_); - formatter_ = std::unique_ptr(new pattern_formatter(pattern)); + formatter_ = details::make_unique(pattern); } template @@ -105,8 +91,8 @@ SPDLOG_INLINE void ansicolor_sink::set_color_mode(color_mode mode) } template -SPDLOG_INLINE void ansicolor_sink::print_ccode_(const string_view_t &color_code) { - fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); +SPDLOG_INLINE void ansicolor_sink::print_view_(const string_view_t &sv) { + fwrite(sv.data(), sizeof(char), sv.size(), target_file_); } template @@ -116,11 +102,6 @@ SPDLOG_INLINE void ansicolor_sink::print_range_(const memory_buf_t fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); } -template -SPDLOG_INLINE std::string ansicolor_sink::to_string_(const string_view_t &sv) { - return std::string(sv.data(), sv.size()); -} - // ansicolor_stdout_sink template SPDLOG_INLINE ansicolor_stdout_sink::ansicolor_stdout_sink(color_mode mode) diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index ff53730c..1b62e4bc 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -44,49 +45,48 @@ public: void set_formatter(std::unique_ptr sink_formatter) override; // Formatting codes - const string_view_t reset = "\033[m"; - const string_view_t bold = "\033[1m"; - const string_view_t dark = "\033[2m"; - const string_view_t underline = "\033[4m"; - const string_view_t blink = "\033[5m"; - const string_view_t reverse = "\033[7m"; - const string_view_t concealed = "\033[8m"; - const string_view_t clear_line = "\033[K"; + const string_view_t reset = details::ansicolors::reset; + const string_view_t bold = details::ansicolors::bold; + const string_view_t dark = details::ansicolors::dark; + const string_view_t underline = details::ansicolors::underline; + const string_view_t blink = details::ansicolors::blink; + const string_view_t reverse = details::ansicolors::reverse; + const string_view_t concealed = details::ansicolors::concealed; + const string_view_t clear_line = details::ansicolors::clear_line; // Foreground colors - const string_view_t black = "\033[30m"; - const string_view_t red = "\033[31m"; - const string_view_t green = "\033[32m"; - const string_view_t yellow = "\033[33m"; - const string_view_t blue = "\033[34m"; - const string_view_t magenta = "\033[35m"; - const string_view_t cyan = "\033[36m"; - const string_view_t white = "\033[37m"; + const string_view_t black = details::ansicolors::black; + const string_view_t red = details::ansicolors::red; + const string_view_t green = details::ansicolors::green; + const string_view_t yellow = details::ansicolors::yellow; + const string_view_t blue = details::ansicolors::blue; + const string_view_t magenta = details::ansicolors::magenta; + const string_view_t cyan = details::ansicolors::cyan; + const string_view_t white = details::ansicolors::white; /// Background colors - const string_view_t on_black = "\033[40m"; - const string_view_t on_red = "\033[41m"; - const string_view_t on_green = "\033[42m"; - const string_view_t on_yellow = "\033[43m"; - const string_view_t on_blue = "\033[44m"; - const string_view_t on_magenta = "\033[45m"; - const string_view_t on_cyan = "\033[46m"; - const string_view_t on_white = "\033[47m"; + const string_view_t on_black = details::ansicolors::on_black; + const string_view_t on_red = details::ansicolors::on_red; + const string_view_t on_green = details::ansicolors::on_green; + const string_view_t on_yellow = details::ansicolors::on_yellow; + const string_view_t on_blue = details::ansicolors::on_blue; + const string_view_t on_magenta = details::ansicolors::on_magenta; + const string_view_t on_cyan = details::ansicolors::on_cyan; + const string_view_t on_white = details::ansicolors::on_white; /// Bold colors - const string_view_t yellow_bold = "\033[33m\033[1m"; - const string_view_t red_bold = "\033[31m\033[1m"; - const string_view_t bold_on_red = "\033[1m\033[41m"; + const string_view_t yellow_bold = details::ansicolors::yellow_bold; + const string_view_t red_bold = details::ansicolors::red_bold; + const string_view_t bold_on_red = details::ansicolors::bold_on_red; private: FILE *target_file_; mutex_t &mutex_; + details::ansicolors colors_; bool should_do_colors_; std::unique_ptr formatter_; - std::array colors_; - void print_ccode_(const string_view_t &color_code); + void print_view_(const string_view_t &sv); void print_range_(const memory_buf_t &formatted, size_t start, size_t end); - static std::string to_string_(const string_view_t &sv); }; template diff --git a/src/spdlog.cpp b/src/spdlog.cpp index 27cc592b..6baa2d0d 100644 --- a/src/spdlog.cpp +++ b/src/spdlog.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include