diff --git a/include/spdlog/pattern_formatter-inl.h b/include/spdlog/pattern_formatter-inl.h index 796eda99..1d5c5252 100644 --- a/include/spdlog/pattern_formatter-inl.h +++ b/include/spdlog/pattern_formatter-inl.h @@ -726,6 +726,38 @@ private: std::string str_; }; +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) +// mark the color range. expect it to be in the form of "%^colored text%$" +class color_start_formatter final : public flag_formatter +{ +public: + explicit color_start_formatter(padding_info padinfo, styling_info style_info) + : flag_formatter(padinfo, style_info) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + styleinfo_.is_start = true; + styleinfo_.position = dest.size(); + msg.styling_ranges.push_back(styleinfo_); + } +}; + +class color_stop_formatter final : public flag_formatter +{ +public: + explicit color_stop_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + styleinfo_.is_start = false; + styleinfo_.position = dest.size(); + msg.styling_ranges.push_back(styleinfo_); + } +}; +#else // mark the color range. expect it to be in the form of "%^colored text%$" class color_start_formatter final : public flag_formatter { @@ -749,9 +781,10 @@ public: void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { - msg.color_range_end = dest.size(); + msg.color_range_stop = dest.size(); } }; +#endif // print source location template @@ -989,12 +1022,25 @@ public: } dest.push_back('['); +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + // wrap the level name with color + styleinfo_.is_start = true; + styleinfo_.position = dest.size(); + msg.styling_ranges.push_back(styleinfo_); + + fmt_helper::append_string_view(level::to_string_view(msg.level), dest); + + styleinfo_.is_start = false; + styleinfo_.position = dest.size(); + msg.styling_ranges.push_back(styleinfo_); +#else // wrap the level name with color msg.color_range_start = dest.size(); // fmt_helper::append_string_view(level::to_c_str(msg.level), dest); fmt_helper::append_string_view(level::to_string_view(msg.level), dest); msg.color_range_end = dest.size(); +#endif dest.push_back(']'); dest.push_back(' '); @@ -1103,7 +1149,11 @@ SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) } template +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) +SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding, details::styling_info styling) +#else SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) +#endif { // process custom flags auto it = custom_handlers_.find(flag); @@ -1262,7 +1312,11 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i break; case ('^'): // color range start +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + formatters_.push_back(details::make_unique(padding, styling)); +#else formatters_.push_back(details::make_unique(padding)); +#endif break; case ('$'): // color range end @@ -1388,6 +1442,99 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri return details::padding_info{std::min(width, max_width), side, truncate}; } +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) +// Extract given style spec (e.g. %{style}^X, %{style;style}^X, ...) +// Advance the given it pass the end of the style spec found (if any) +// Return style. +SPDLOG_INLINE details::styling_info pattern_formatter::handle_stylespec_(std::string::const_iterator &it, std::string::const_iterator end) +{ + using details::styling_info; + + if (it == end || *it != '{' ) + { // there is no style spec, shortcuit + return styling_info{}; + } + it++; // consume '{' + + std::string input = static_cast(&(*it)); + size_t end_of_spec = input.find('}'); + + if (end_of_spec == std::string::npos) + { // the style spec closing delimtier is not present + return styling_info{}; + } + std::string full_spec_(input, 0, end_of_spec); + + // need to advance the iterator the number of characters in the spec + // plus the closing delimiter '}' + size_t consumed_characters = full_spec_.length() + 1; + it += consumed_characters; + + // the style spec can be delimited by semi-colons to declare + // mutliple types of styling (i.e. {fg_green;bold}) + size_t insert_position = 0; + details::styles_array styles{}; + + if (full_spec_.find(';') != std::string::npos) + { // spec contains multiple styles + for (auto it_s = full_spec_.begin(); it_s != full_spec_.end(); ++it_s) + { + std::string t_spec_ = static_cast(&(*it_s)); + size_t delimiter = t_spec_.find(';'); + + if (delimiter == std::string::npos) + { // this is the last style in the spec + for (int i = 0; i < SPDLOG_ANSI_STLYE_COUNT; i++) + { + if (t_spec_.compare(details::style_type_table[i]) == 0) + { // verify this style spec is valid + try + { + styles[insert_position] = details::style_type(i); + insert_position++; + } + catch (...) // user added more styles than are defined + {} + break; + } + } + break; + } + + std::string s_spec_(t_spec_, 0, delimiter); + for (int i = 0; i < SPDLOG_ANSI_STLYE_COUNT; i++) + { + if (s_spec_.compare(details::style_type_table[i]) == 0) + { // verify this style spec is valid + try + { + styles[insert_position] = details::style_type(i); + insert_position++; + } + catch (...) // user added more styles than are defined + {} + break; + } + } + // advance the iterator, the for loop will consume the semi-colon + size_t consumed_style = s_spec_.length(); + it_s += consumed_style; + } + } + else + { // style spec contains single style + for (int i = 0; i < SPDLOG_ANSI_STLYE_COUNT; i++) + { // verify this style spec is valid + if (full_spec_.compare(details::style_type_table[i]) == 0) + { + styles[insert_position] = details::style_type(i); + break; + } + } + } + return styling_info{styles}; +} +#endif SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) { auto end = pattern.end(); @@ -1404,6 +1551,21 @@ SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &patter auto padding = handle_padspec_(++it, end); +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + auto styles = handle_stylespec_(it, end); + + if (it != end) + { + if (padding.enabled()) + { + handle_flag_(*it, padding, styles); + } + else + { + handle_flag_(*it, padding, styles); + } + } +#else if (it != end) { if (padding.enabled()) @@ -1415,6 +1577,7 @@ SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &patter handle_flag_(*it, padding); } } +#endif else { break; diff --git a/include/spdlog/pattern_formatter.h b/include/spdlog/pattern_formatter.h index 4c87b21e..02199560 100644 --- a/include/spdlog/pattern_formatter.h +++ b/include/spdlog/pattern_formatter.h @@ -47,6 +47,37 @@ struct padding_info bool enabled_ = false; }; +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + +class SPDLOG_API flag_formatter +{ +public: + explicit flag_formatter(padding_info padinfo) + : padinfo_(padinfo) + {} + explicit flag_formatter(padding_info padinfo, styling_info style_info) + : padinfo_(padinfo) + , styleinfo_(style_info) + {} + flag_formatter() = default; + virtual ~flag_formatter() = default; + virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0; + +protected: + padding_info padinfo_; + styling_info styleinfo_; +}; + +static const details::style_strings style_type_table +{ + "null_style", + "reset", "bold", "dark", "underline", "blink", "reverse", + "fg_black", "fg_red", "fg_green", "fg_yellow", "fg_blue", "fg_magenta", "fg_cyan", "fg_white", "fg_default", + "bg_black", "bg_red", "bg_green", "bg_yellow", "bg_blue", "bg_magenta", "bg_cyan", "bg_white", "bg_default" +}; + +#else + class SPDLOG_API flag_formatter { public: @@ -61,6 +92,8 @@ protected: padding_info padinfo_; }; +#endif + } // namespace details class SPDLOG_API custom_flag_formatter : public details::flag_formatter @@ -112,13 +145,19 @@ private: std::tm get_time_(const details::log_msg &msg); template - void handle_flag_(char flag, details::padding_info padding); + void handle_flag_(char flag, details::padding_info padding, details::styling_info styling); // Extract given pad spec (e.g. %8X) // Advance the given it pass the end of the padding spec found (if any) // Return padding. static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); +#if !defined(_WIN32) && defined(SPDLOG_EXTENDED_STLYING) + // Extract given style spec (e.g. %{style}^X, %{style;style}^X, etc...) + // Advance the given it pass the end of the style spec found (if any) + // Return style. + static details::styling_info handle_stylespec_(std::string::const_iterator &it, std::string::const_iterator end); +#endif void compile_pattern_(const std::string &pattern); }; } // namespace spdlog