diff --git a/source/mijin/logging/formatting.hpp b/source/mijin/logging/formatting.hpp index fe15d32..09df423 100644 --- a/source/mijin/logging/formatting.hpp +++ b/source/mijin/logging/formatting.hpp @@ -13,6 +13,7 @@ #include "../memory/memutil.hpp" #include "../memory/virtual_allocator.hpp" #include "../util/annot.hpp" +#include "../util/ansi_colors.hpp" #include "../util/concepts.hpp" #include "../util/string.hpp" @@ -31,7 +32,7 @@ public: virtual ~BaseLogFormatter() noexcept = default; - virtual void format(const LogMessage& message, string_t& outFormatted) noexcept = 0; + virtual void format(const LogMessage& message, string_t& outFormatted) = 0; }; template, @@ -44,13 +45,16 @@ public: using allocator_t = TAllocator; using base_t = BaseLogFormatter; using typename base_t::string_t; + using string_view_t = std::basic_string_view; private: string_t mFormat; string_t mFormatBuffer; public: explicit BaseSimpleLogFormatter(string_t format) MIJIN_NOEXCEPT : mFormat(std::move(format)), mFormatBuffer(mFormat.get_allocator()) {} - void format(const LogMessage& message, string_t& outFormatted) noexcept override; + void format(const LogMessage& message, string_t& outFormatted) override; +private: + void formatAnsiSequence(const LogMessage& message, string_view_t ansiName, string_t& outFormatted); }; #define FORMATTER_SET_ARGS(chr_type) chr_type, std::char_traits, TAllocator @@ -114,10 +118,8 @@ MIJIN_DEFINE_CHAR_VERSIONS_TMPL(FormattingLogSink, MIJIN_FORMATTING_SINK_COMMON_ #undef SINK_SET_ARGS template TAllocator> -void BaseSimpleLogFormatter::format(const LogMessage& message, string_t& outFormatted) noexcept +void BaseSimpleLogFormatter::format(const LogMessage& message, string_t& outFormatted) { - using string_view_t = std::basic_string_view; - mFormatBuffer.clear(); for (auto pos = mFormat.begin(); pos != mFormat.end(); ++pos) { @@ -252,6 +254,10 @@ void BaseSimpleLogFormatter::format(const LogMessage { formatInline(message.level->name); } + else if (argName == MIJIN_SMART_QUOTE(char_t, "ansi")) + { + formatAnsiSequence(message, argFormat.substr(1), outFormatted); + } else { MIJIN_ERROR("Invalid format argument name."); @@ -263,6 +269,56 @@ void BaseSimpleLogFormatter::format(const LogMessage } } } + +template TAllocator> +void BaseSimpleLogFormatter::formatAnsiSequence(const LogMessage& message, string_view_t ansiName, string_t& outFormatted) +{ + std::size_t numParts = 0; + const auto formatParts = splitFixed<4>(ansiName, ",", {}, &numParts); + + outFormatted += MIJIN_SMART_QUOTE(char_t, "\033["); + for (std::size_t partIdx = 0; partIdx < numParts; ++partIdx) + { + const string_view_t& part = formatParts[partIdx]; + if (partIdx > 0) + { + outFormatted += MIJIN_SMART_QUOTE(char_t, ','); + } + if (part == MIJIN_SMART_QUOTE(char_t, "reset")) + { + outFormatted += BaseAnsiFontEffects::RESET; + } + else if (part == MIJIN_SMART_QUOTE(char_t, "level_color")) + { + const int levelValue = message.level->value; + if (levelValue < MIJIN_LOG_LEVEL_VALUE_VERBOSE) + { + outFormatted += BaseAnsiFontEffects::FG_CYAN; + } + else if (levelValue < MIJIN_LOG_LEVEL_VALUE_INFO) + { + outFormatted += BaseAnsiFontEffects::FG_WHITE; + } + else if (levelValue < MIJIN_LOG_LEVEL_VALUE_WARNING) + { + outFormatted += BaseAnsiFontEffects::FG_BRIGHT_WHITE; + } + else if (levelValue < MIJIN_LOG_LEVEL_VALUE_ERROR) + { + outFormatted += BaseAnsiFontEffects::FG_YELLOW; + } + else + { + outFormatted += BaseAnsiFontEffects::FG_RED; + } + } + else + { + MIJIN_ERROR("Invalid format ansi font effect name."); + } + } + outFormatted += MIJIN_SMART_QUOTE(char_t, 'm'); +} } // namespace mijin #endif // !defined(MIJIN_LOGGING_FORMATTING_HPP_INCLUDED) diff --git a/source/mijin/logging/stdio_sink.hpp b/source/mijin/logging/stdio_sink.hpp index 43739e0..1a76b86 100644 --- a/source/mijin/logging/stdio_sink.hpp +++ b/source/mijin/logging/stdio_sink.hpp @@ -11,7 +11,7 @@ namespace mijin { template requires(allocator_type>) -class StdioSink : public BaseFormattingLogSink +class BaseStdioSink : public BaseFormattingLogSink { public: using base_t = BaseFormattingLogSink; @@ -20,12 +20,18 @@ public: using typename base_t::formatter_ptr_t; using typename base_t::message_t; private: - int mMinStderrLevel; + int mMinStderrLevel = MIJIN_LOG_LEVEL_VALUE_WARNING; public: - explicit StdioSink(not_null_t formatter, allocator_t allocator = {}, - int minStderrLevel = MIJIN_LOG_LEVEL_VALUE_WARNING) + explicit BaseStdioSink(not_null_t formatter, allocator_t allocator = {}) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v) - : base_t(std::move(formatter), std::move(allocator)), mMinStderrLevel(minStderrLevel) {} + : base_t(std::move(formatter), std::move(allocator)) {} + + [[nodiscard]] + int getMinStderrLevel() const MIJIN_NOEXCEPT { return mMinStderrLevel; } + + void setMinStderrLevel(int level) MIJIN_NOEXCEPT { mMinStderrLevel = level; } + + void setMinStderrLevel(const BaseLogLevel& level) MIJIN_NOEXCEPT { mMinStderrLevel = level.value; } void handleMessageFormatted(const message_t& message, const char_t* formatted) MIJIN_NOEXCEPT override { @@ -52,6 +58,12 @@ public: } } }; + +#define SINK_SET_ARGS(chr_type) chr_type, std::char_traits, TAllocator, TDeleter + +MIJIN_DEFINE_CHAR_VERSIONS_TMPL(StdioSink, MIJIN_FORMATTING_SINK_COMMON_ARGS, SINK_SET_ARGS) + +#undef SINK_SET_ARGS } // namespace mijin diff --git a/source/mijin/util/ansi_colors.hpp b/source/mijin/util/ansi_colors.hpp new file mode 100644 index 0000000..6c607dc --- /dev/null +++ b/source/mijin/util/ansi_colors.hpp @@ -0,0 +1,55 @@ + +#pragma once + +#if !defined(MIJIN_UTIL_ANSI_COLORS_HPP_INCLUDED) +#define MIJIN_UTIL_ANSI_COLORS_HPP_INCLUDED 1 + +#include "../internal/common.hpp" + +namespace mijin +{ +template +struct BaseAnsiFontEffects +{ + using char_t = TChar; + + static constexpr const char_t* RESET = MIJIN_SMART_QUOTE(char_t, "0"); + + static constexpr const char_t* FG_BLACK = MIJIN_SMART_QUOTE(char_t, "30"); + static constexpr const char_t* FG_RED = MIJIN_SMART_QUOTE(char_t, "31"); + static constexpr const char_t* FG_GREEN = MIJIN_SMART_QUOTE(char_t, "32"); + static constexpr const char_t* FG_YELLOW = MIJIN_SMART_QUOTE(char_t, "33"); + static constexpr const char_t* FG_BLUE = MIJIN_SMART_QUOTE(char_t, "34"); + static constexpr const char_t* FG_MAGENTA = MIJIN_SMART_QUOTE(char_t, "35"); + static constexpr const char_t* FG_CYAN = MIJIN_SMART_QUOTE(char_t, "36"); + static constexpr const char_t* FG_WHITE = MIJIN_SMART_QUOTE(char_t, "37"); + static constexpr const char_t* FG_BRIGHT_BLACK = MIJIN_SMART_QUOTE(char_t, "90"); + static constexpr const char_t* FG_BRIGHT_RED = MIJIN_SMART_QUOTE(char_t, "91"); + static constexpr const char_t* FG_BRIGHT_GREEN = MIJIN_SMART_QUOTE(char_t, "92"); + static constexpr const char_t* FG_BRIGHT_YELLOW = MIJIN_SMART_QUOTE(char_t, "93"); + static constexpr const char_t* FG_BRIGHT_BLUE = MIJIN_SMART_QUOTE(char_t, "94"); + static constexpr const char_t* FG_BRIGHT_MAGENTA = MIJIN_SMART_QUOTE(char_t, "95"); + static constexpr const char_t* FG_BRIGHT_CYAN = MIJIN_SMART_QUOTE(char_t, "96"); + static constexpr const char_t* FG_BRIGHT_WHITE = MIJIN_SMART_QUOTE(char_t, "97"); + + static constexpr const char_t* BG_BLACK = MIJIN_SMART_QUOTE(char_t, "40"); + static constexpr const char_t* BG_RED = MIJIN_SMART_QUOTE(char_t, "41"); + static constexpr const char_t* BG_GREEN = MIJIN_SMART_QUOTE(char_t, "42"); + static constexpr const char_t* BG_YELLOW = MIJIN_SMART_QUOTE(char_t, "43"); + static constexpr const char_t* BG_BLUE = MIJIN_SMART_QUOTE(char_t, "44"); + static constexpr const char_t* BG_MAGENTA = MIJIN_SMART_QUOTE(char_t, "45"); + static constexpr const char_t* BG_CYAN = MIJIN_SMART_QUOTE(char_t, "46"); + static constexpr const char_t* BG_WHITE = MIJIN_SMART_QUOTE(char_t, "47"); + static constexpr const char_t* BG_BRIGHT_BLACK = MIJIN_SMART_QUOTE(char_t, "100"); + static constexpr const char_t* BG_BRIGHT_RED = MIJIN_SMART_QUOTE(char_t, "101"); + static constexpr const char_t* BG_BRIGHT_GREEN = MIJIN_SMART_QUOTE(char_t, "102"); + static constexpr const char_t* BG_BRIGHT_YELLOW = MIJIN_SMART_QUOTE(char_t, "103"); + static constexpr const char_t* BG_BRIGHT_BLUE = MIJIN_SMART_QUOTE(char_t, "104"); + static constexpr const char_t* BG_BRIGHT_MAGENTA = MIJIN_SMART_QUOTE(char_t, "105"); + static constexpr const char_t* BG_BRIGHT_CYAN = MIJIN_SMART_QUOTE(char_t, "106"); + static constexpr const char_t* BG_BRIGHT_WHITE = MIJIN_SMART_QUOTE(char_t, "107"); +}; +MIJIN_DEFINE_CHAR_VERSIONS(AnsiFontEffects) +} + +#endif // !defined(MIJIN_UTIL_ANSI_COLORS_HPP_INCLUDED)