diff --git a/include/spdlog/sinks/ansicolor_sink-inl.h b/include/spdlog/sinks/ansicolor_sink-inl.h index de253461..1e8ca090 100644 --- a/include/spdlog/sinks/ansicolor_sink-inl.h +++ b/include/spdlog/sinks/ansicolor_sink-inl.h @@ -21,6 +21,15 @@ SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, co { set_color_mode(mode); +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + colors_.at(level::trace) = details::styles_array{details::style_type::fg_white}; + colors_.at(level::debug) = details::styles_array{details::style_type::fg_cyan}; + colors_.at(level::info) = details::styles_array{details::style_type::fg_green}; + colors_.at(level::warn) = details::styles_array{details::style_type::bold,details::style_type::fg_yellow}; + colors_.at(level::err) = details::styles_array{details::style_type::bold,details::style_type::fg_red}; + colors_.at(level::critical) = details::styles_array{details::style_type::bold,details::style_type::bg_red}; + colors_.at(level::off) = details::styles_array{details::style_type::reset}; +#else colors_.at(level::trace) = to_string_(white); colors_.at(level::debug) = to_string_(cyan); colors_.at(level::info) = to_string_(green); @@ -28,14 +37,24 @@ SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, co colors_.at(level::err) = to_string_(red_bold); colors_.at(level::critical) = to_string_(bold_on_red); colors_.at(level::off) = to_string_(reset); +#endif } +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) +template +SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, details::styles_array color) +{ + std::lock_guard lock(mutex_); + colors_.at(static_cast(color_level)) = color; +} +#else 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); } +#endif template SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg) @@ -46,8 +65,86 @@ SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg msg.color_range_start = 0; msg.color_range_end = 0; +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + msg.styling_ranges.clear(); +#endif + memory_buf_t formatted; formatter_->format(msg, formatted); + +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + if (should_do_colors_ && msg.styling_ranges.size() > 0) + { + string_view_t reset = details::styling_table[(int)details::style_type::reset]; + + size_t open_styles_count = 0; + size_t before_style_range = 0; + + for(auto info = msg.styling_ranges.begin(); info != msg.styling_ranges.end(); info++) + { + if (info->is_start) + { + // this stlying formatter is the first occurrance past the previous closing formatter + // all of the preceding characters if any are outside color the range + if (msg.color_range_end <= info->position && open_styles_count == 0) + { + msg.color_range_start = info->position; + // before style range + print_range_(formatted, before_style_range, msg.color_range_start); + } + open_styles_count++; + + // each styling formatter can contain multiple styles in its style spec + // loop through each style and print the style code + auto styles = info->styles; + + // it is possible to not provide a style spec with the formatter, in that + // case the first style spec will be null_style therefore default to the + // generic log level style + if (styles[0] == details::style_type::null_style) + { + styles = colors_.at(msg.level); + } + + try + { + for(int i = 0; styles[i] != details::style_type::null_style ; i++) + { + // in style range + print_ccode_(details::styling_table.at((int)styles[i])); + } + } + catch (const std::out_of_range &ex) + { // full style spec output looks either amazing or trash + } + } + else { + // this closing styling formatter is the first occurrance past the previous + // n opening styling formatters, because a reset ends all preceding styling + // this position is the true closing formatter in the event more closing + // formatters are declared + if (open_styles_count > 0) + { + msg.color_range_end = info->position; + // style range has fully been defined + print_range_(formatted, msg.color_range_start, msg.color_range_end); + print_ccode_(reset); + // get new location outside style ranges + before_style_range = msg.color_range_end; + // reset open styles count + open_styles_count = 0; + } + } + } + // after all style ranges + print_range_(formatted, msg.color_range_end, formatted.size()); + + // printing a reset code at the very end of the log clears all dangling + // open formatters and will not be visible on the output line in the + // event there are no dangling formatters + print_ccode_(reset); + } +#else if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { // before color range @@ -56,9 +153,10 @@ SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg print_ccode_(colors_.at(static_cast(msg.level))); print_range_(formatted, msg.color_range_start, msg.color_range_end); print_ccode_(reset); - // after all color ranges + // after color range print_range_(formatted, msg.color_range_end, formatted.size()); } +#endif else // no color { print_range_(formatted, 0, formatted.size()); diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index 39d966bc..ba760db5 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -35,7 +35,12 @@ public: ansicolor_sink &operator=(const ansicolor_sink &other) = delete; ansicolor_sink &operator=(ansicolor_sink &&other) = delete; +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + void set_color(level::level_enum color_level, details::styles_array color); +#else void set_color(level::level_enum color_level, string_view_t color); +#endif + void set_color_mode(color_mode mode); bool should_color(); @@ -84,7 +89,13 @@ private: mutex_t &mutex_; bool should_do_colors_; std::unique_ptr formatter_; + +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + std::array colors_; +#else std::array colors_; +#endif + void print_ccode_(const string_view_t &color_code); void print_range_(const memory_buf_t &formatted, size_t start, size_t end); static std::string to_string_(const string_view_t &sv); @@ -111,6 +122,46 @@ using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; using ansicolor_stderr_sink_st = ansicolor_stderr_sink; } // namespace sinks + +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) +namespace details { + static details::style_codes styling_table + { + "", // null_style + + // font style + "\033[0m", // reset + "\033[1m", // bold + "\033[2m", // dark + "\033[4m", // underline + "\033[5m", // blink + "\033[7m", // reverse + + // font foreground colors + "\033[30m", // fg_black + "\033[31m", // fg_red + "\033[32m", // fg_green + "\033[33m", // fg_yellow + "\033[34m", // fg_blue + "\033[35m", // fg_magenta + "\033[36m", // fg_cyan + "\033[37m", // fg_white + "\033[39m", // fg_default + + // font background colors + "\033[40m", // bg_black + "\033[41m", // bg_red + "\033[42m", // bg_green + "\033[43m", // bg_yellow + "\033[44m", // bg_blue + "\033[45m", // bg_magenta + "\033[46m", // bg_cyan + "\033[47m", // bg_white + "\033[49m", // bg_default + }; +} // namespace details +#endif + } // namespace spdlog #ifdef SPDLOG_HEADER_ONLY