diff --git a/LICENSE b/LICENSE index f17ec1c..8f8e244 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2012-2024 Dimo Markov +Copyright (c) 2012 Dimo Markov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/include/Logger/Logger.hpp b/include/Logger/Logger.hpp index b185dd8..b8288eb 100644 --- a/include/Logger/Logger.hpp +++ b/include/Logger/Logger.hpp @@ -3,8 +3,7 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #pragma once #include "../../source/Logger.hpp" \ No newline at end of file diff --git a/source/HTML.cpp b/source/HTML.cpp index 33b0879..15601ef 100644 --- a/source/HTML.cpp +++ b/source/HTML.cpp @@ -1,5 +1,11 @@ +/// +/// Langulus::Logger +/// Copyright (c) 2012 Dimo Markov +/// Part of the Langulus framework, see https://langulus.com +/// +/// SPDX-License-Identifier: MIT +/// #include "Logger.hpp" -#include using namespace Langulus; using namespace Langulus::Logger; @@ -7,10 +13,15 @@ using namespace Langulus::Logger; /// Create an HTML file duplicator/redirector /// @param filename - the relative filename of the log file -ToHTML::ToHTML(const std::string& filename) { - mFile.open(filename, std::ios::out | std::ios::app | std::ios::ate); +ToHTML::ToHTML(const std::string& filename) : mFilename {filename} { + mFile.open(mFilename, std::ios::out | std::ios::trunc); if (not mFile) throw std::runtime_error {"Can't open log file"}; + WriteHeader(); +} + +ToHTML::~ToHTML() { + mFile.close(); } /// Write text @@ -23,24 +34,24 @@ void ToHTML::Write(const TextView& text) const noexcept { /// @param style - the style to set void ToHTML::Write(const Style& style) const noexcept { // Always reset before a style change - Write(""); + Write(" "); if (style.has_emphasis()) { const auto em = static_cast(style.get_emphasis()); if (em & static_cast(fmt::emphasis::bold)) Write(""); - if (em & static_cast(fmt::emphasis::faint)) - ; + //if (em & static_cast(fmt::emphasis::faint)) + // ; if (em & static_cast(fmt::emphasis::italic)) Write(""); if (em & static_cast(fmt::emphasis::underline)) Write(""); if (em & static_cast(fmt::emphasis::blink)) Write(""); - if (em & static_cast(fmt::emphasis::reverse)) - ; - if (em & static_cast(fmt::emphasis::conceal)) - ; + //if (em & static_cast(fmt::emphasis::reverse)) + // ; + //if (em & static_cast(fmt::emphasis::conceal)) + // ; if (em & static_cast(fmt::emphasis::strikethrough)) Write(""); } @@ -54,46 +65,46 @@ void ToHTML::Write(const Style& style) const noexcept { Write(""); break; case fmt::terminal_color::red: - Write(""); + Write(""); break; case fmt::terminal_color::green: - Write(""); + Write(""); break; case fmt::terminal_color::yellow: - Write(""); + Write(""); break; case fmt::terminal_color::blue: Write(""); break; case fmt::terminal_color::magenta: - Write(""); + Write(""); break; case fmt::terminal_color::cyan: - Write(""); + Write(""); break; case fmt::terminal_color::white: - Write(""); + Write(""); break; case fmt::terminal_color::bright_black: - Write(""); + Write(""); break; case fmt::terminal_color::bright_red: - Write(""); + Write(""); break; case fmt::terminal_color::bright_green: - Write(""); + Write(""); break; case fmt::terminal_color::bright_yellow: - Write(""); + Write(""); break; case fmt::terminal_color::bright_blue: - Write(""); + Write(""); break; case fmt::terminal_color::bright_magenta: - Write(""); + Write(""); break; case fmt::terminal_color::bright_cyan: - Write(""); + Write(""); break; case fmt::terminal_color::bright_white: Write(""); @@ -110,46 +121,46 @@ void ToHTML::Write(const Style& style) const noexcept { Write(""); break; case fmt::terminal_color::red: - Write(""); + Write(""); break; case fmt::terminal_color::green: - Write(""); + Write(""); break; case fmt::terminal_color::yellow: - Write(""); + Write(""); break; case fmt::terminal_color::blue: Write(""); break; case fmt::terminal_color::magenta: - Write(""); + Write(""); break; case fmt::terminal_color::cyan: - Write(""); + Write(""); break; case fmt::terminal_color::white: - Write(""); + Write(""); break; case fmt::terminal_color::bright_black: - Write(""); + Write(""); break; case fmt::terminal_color::bright_red: - Write(""); + Write(""); break; case fmt::terminal_color::bright_green: - Write(""); + Write(""); break; case fmt::terminal_color::bright_yellow: - Write(""); + Write(""); break; case fmt::terminal_color::bright_blue: - Write(""); + Write(""); break; case fmt::terminal_color::bright_magenta: - Write(""); + Write(""); break; case fmt::terminal_color::bright_cyan: - Write(""); + Write(""); break; case fmt::terminal_color::bright_white: Write(""); @@ -174,4 +185,19 @@ void ToHTML::NewLine() const noexcept { --tabs; } } -} \ No newline at end of file +} + +/// Clear the log file +void ToHTML::Clear() const noexcept { + mFile.close(); + mFile.open(mFilename, std::ios::out | std::ios::trunc); + WriteHeader(); +} + +/// Write file header - general HTML styling options, etc. +void ToHTML::WriteHeader() const { + Write(""); + Write("

Log started - "); + Write(GetAdvancedTime()); + Write("

"); +} diff --git a/source/Logger.cpp b/source/Logger.cpp index aca51f0..d2e9045 100644 --- a/source/Logger.cpp +++ b/source/Logger.cpp @@ -3,8 +3,7 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #include "Logger.hpp" #include @@ -12,18 +11,43 @@ #include #include + using Clock = ::std::chrono::system_clock; +namespace Langulus::Logger +{ + + Interface Instance {}; + MessageSink MessageSinkInstance {}; + + void AttachDuplicator(A::Interface* d) noexcept { + Instance.AttachDuplicator(d); + } + + void DettachDuplicator(A::Interface* d) noexcept { + Instance.DettachDuplicator(d); + } + + void AttachRedirector(A::Interface* r) noexcept { + Instance.AttachRedirector(r); + } + + void DettachRedirector(A::Interface* r) noexcept { + Instance.DettachRedirector(r); + } + +} // namespace Langulus::Logger + using namespace Langulus; using namespace Langulus::Logger; -/// When using fmt::print(style, mask, ...), the style will be reset after -/// message has been written, and I don't want that to happen -/// @param style - the style to set +/// When using fmt::print(style, mask, ...), the style will be reset after +/// message has been written, and I don't want that to happen +/// @param style - the style to set LANGULUS(INLINED) void FmtPrintStyle(const Style& style) { - // Always reset before a style change + // Always reset before a style change fmt::print("{}", "\x1b[0m"); if (style.has_emphasis()) { @@ -42,23 +66,28 @@ void FmtPrintStyle(const Style& style) { } } -/// The global logger instance -Interface Instance {}; +/// Scoped tabulator destruction +ScopedTabs::~ScopedTabs() noexcept { + while (mTabs > 0) { + --mTabs; + Instance.RunCommand(Command::Untab); + } +} -/// Logger construction +/// Logger construction Interface::Interface() { mStyleStack.push(DefaultStyle); } -/// Logger copy-construction +/// Logger copy-construction Interface::Interface(const Interface& other) : mStyleStack {other.mStyleStack} {} -/// Logger destruction +/// Logger destruction Interface::~Interface() {} -/// Generate an exhaustive timestamp in the current system time zone -/// @return the timestamp text as {:%F %T %Z} +/// Generate an exhaustive timestamp in the current system time zone +/// @return the timestamp text as {:%F %T %Z} Text Logger::A::Interface::GetAdvancedTime() noexcept { try { const auto now = Clock::to_time_t(Clock::now()); @@ -67,8 +96,8 @@ Text Logger::A::Interface::GetAdvancedTime() noexcept { catch (...) { return ""; } } -/// Generate a short timestamp in the current system time zone -/// @return the timestamp text as {:%T} +/// Generate a short timestamp in the current system time zone +/// @return the timestamp text as {:%T} Text Logger::A::Interface::GetSimpleTime() noexcept { try { const auto now = Clock::to_time_t(Clock::now()); @@ -77,58 +106,58 @@ Text Logger::A::Interface::GetSimpleTime() noexcept { catch (...) { return ""; } } -/// Write a string view to stdout -/// @param stdString - the text view to write +/// Write a string view to stdout +/// @param stdString - the text view to write void Interface::Write(const TextView& stdString) const noexcept { - // Dispatch to redirectors + // Dispatch to redirectors if (not mRedirectors.empty()) { for (auto attachment : mRedirectors) attachment->Write(stdString); - // The presence of a redirector blocks console printing + // The presence of a redirector blocks console printing return; } try { fmt::print("{}", stdString); } catch (...) { Logger::Append(""); } - // Dispatch to duplicators + // Dispatch to duplicators for (auto attachment : mDuplicators) attachment->Write(stdString); } -/// Change the style -/// @param s - the style +/// Change the style +/// @param s - the style void Interface::Write(const Style& s) const noexcept { - // Dispatch to redirectors + // Dispatch to redirectors if (not mRedirectors.empty()) { for (auto attachment : mRedirectors) attachment->Write(s); - // The presence of a redirector blocks console printing + // The presence of a redirector blocks console printing return; } FmtPrintStyle(s); - // Dispatch to duplicators + // Dispatch to duplicators for (auto attachment : mDuplicators) attachment->Write(s); } - -/// Remove formatting, add a new line, add a timestamp and tabulate -/// @attention top of the style stack is not applied + +/// Remove formatting, add a new line, add a timestamp and tabulate +/// @attention top of the style stack is not applied void Interface::NewLine() const noexcept { - // Dispatch to redirectors + // Dispatch to redirectors if (not mRedirectors.empty()) { for (auto attachment : mRedirectors) attachment->NewLine(); - // The presence of a redirector blocks console printing + // The presence of a redirector blocks console printing return; } - // Clear formatting, add new line, simple time stamp, and tabs + // Clear formatting, add new line, simple time stamp, and tabs fmt::print("\n"); FmtPrintStyle(TimeStampStyle); fmt::print("{}| ", GetSimpleTime()); @@ -142,17 +171,36 @@ void Interface::NewLine() const noexcept { } } - // Dispatch to duplicators + // Dispatch to duplicators for (auto attachment : mDuplicators) attachment->NewLine(); } -/// Execute a logger command -/// @param c - the command to execute +/// Clear the entire log (clear the console window or file) +void Interface::Clear() const noexcept { + // Dispatch to redirectors + if (not mRedirectors.empty()) { + for (auto attachment : mRedirectors) + attachment->Clear(); + + // The presence of a redirector blocks console printing + return; + } + + // Clear the window + fmt::print("{}", "\x1b[2J"); + + // Dispatch to duplicators + for (auto attachment : mDuplicators) + attachment->Clear(); +} + +/// Execute a logger command +/// @param c - the command to execute void Interface::RunCommand(const Command& c) noexcept { switch (c) { case Command::Clear: - fmt::print("{}", "\x1b[2J"); + Clear(); break; case Command::NewLine: NewLine(); @@ -183,6 +231,9 @@ void Interface::RunCommand(const Command& c) noexcept { case Command::Push: mStyleStack.push(mStyleStack.top()); break; + case Command::Stylize: + Write(mStyleStack.top()); + break; case Command::Tab: ++mTabulator; break; @@ -193,32 +244,33 @@ void Interface::RunCommand(const Command& c) noexcept { } } -/// Change the foreground/background color -/// @param c - the color -void Interface::SetColor(const Color& c) noexcept { +/// Change the foreground/background color +/// @param c - the color +/// @return the last style, with coloring applied +const Style& Interface::SetColor(const Color& c) noexcept { auto& style = mStyleStack.top(); const auto oldStyle = style; if (c == Color::NoForeground) { - // Reset the foreground color + // Reset the foreground color style = {}; if (oldStyle.has_background()) style |= fmt::bg(oldStyle.get_background()); } else if (c == Color::NoBackground) { - // Reset the background color + // Reset the background color style = {}; if (oldStyle.has_foreground()) style |= fmt::fg(oldStyle.get_foreground()); } else if ((c >= Color::Black and c < Color::BlackBgr) or (c >= Color::DarkGray and c < Color::DarkGrayBgr)) { - // Create a new foreground color style + // Create a new foreground color style style = fmt::fg(static_cast(c)); if (oldStyle.has_background()) style |= fmt::bg(oldStyle.get_background()); } else { - // Create a new background color style + // Create a new background color style style = fmt::fg(static_cast(c)); if (oldStyle.has_background()) style |= fmt::bg(oldStyle.get_background()); @@ -226,47 +278,136 @@ void Interface::SetColor(const Color& c) noexcept { if (oldStyle.has_emphasis()) style |= oldStyle.get_emphasis(); + return style; } -/// Change the emphasis -/// @param c - the color -void Interface::SetEmphasis(const Emphasis& e) noexcept { +/// Change the emphasis +/// @param c - the color +const Style& Interface::SetEmphasis(const Emphasis& e) noexcept { auto& style = mStyleStack.top(); style |= static_cast(e); + return style; } -/// Change the style -/// @param s - the style -void Interface::SetStyle(const Style& s) noexcept { +/// Change the style +/// @param s - the style +const Style& Interface::SetStyle(const Style& s) noexcept { mStyleStack.top() = s; + return mStyleStack.top(); } -/// Attach another logger, if no redirectors are attached, any logging -/// will be duplicated to the provided interface -/// @attention the logger doesn't have ownership of the attachment -/// @param duplicator - the logger to attach +/// Attach another logger, if no redirectors are attached, any logging +/// will be duplicated to the provided interface +/// @attention the logger doesn't have ownership of the attachment +/// @param duplicator - the logger to attach void Interface::AttachDuplicator(A::Interface* duplicator) noexcept { mDuplicators.push_back(duplicator); } -/// Dettach a duplicator -/// @attention the logger doesn't have ownership of the attachment -/// @param duplicator - the duplicator to dettach +/// Dettach a duplicator +/// @attention the logger doesn't have ownership of the attachment +/// @param duplicator - the duplicator to dettach void Interface::DettachDuplicator(A::Interface* duplicator) noexcept { mDuplicators.remove(duplicator); } -/// Attach another logger, that will receive any logging, but also consume -/// it, so that it doesn't reach the console or any attached duplicators -/// @attention the logger doesn't have ownership of the attachment -/// @param redirector - the logger to attach +/// Attach another logger, that will receive any logging, but also consume +/// it, so that it doesn't reach the console or any attached duplicators +/// @attention the logger doesn't have ownership of the attachment +/// @param redirector - the logger to attach void Interface::AttachRedirector(A::Interface* redirector) noexcept { mRedirectors.push_back(redirector); } -/// Dettach a redirector -/// @attention the logger doesn't have ownership of the attachment -/// @param redirector - the duplicator to dettach +/// Dettach a redirector +/// @attention the logger doesn't have ownership of the attachment +/// @param redirector - the duplicator to dettach void Interface::DettachRedirector(A::Interface* redirector) noexcept { mRedirectors.remove(redirector); } + +/// Does nothing, but allows for grouping logging statements in () +/// Example: Logger::Error() << "yeah" << (Logger::Info() << "no") +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (Logger::A::Interface&) noexcept { + return *this; +} + +/// Push a command +/// @param c - the command to push +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const Command& c) noexcept { + Instance.RunCommand(c); + return *this; +} + +/// Push a foreground color +/// @param c - the command to push +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const Color& c) noexcept { + Instance.SetColor(c); + Instance.RunCommand(Command::Stylize); + return *this; +} + +/// Push an emphasis +/// @param e - the emphasis to push +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const Emphasis& e) noexcept { + Instance.SetEmphasis(e); + Instance.RunCommand(Command::Stylize); + return *this; +} + +/// Push a foreground and background color +/// @param c - the state to push +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const Style& c) noexcept { + Instance.SetStyle(c); + Instance.RunCommand(Command::Stylize); + return *this; +} + +/// Push a number of tabs +/// @param t - the tabs to push +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const Tabs& t) noexcept { + auto tabs = ::std::max(1, t.mTabs); + while (tabs) { + Instance.RunCommand(Command::Tab); + --tabs; + } + + return *this; +} + +/// Write string views +/// @param t - text to write +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const TextView& t) noexcept { + Instance.Write(t); + return *this; +} + +/// Write a nullptr as "null" +/// @return a reference to the logger for chaining +Logger::A::Interface& Logger::A::Interface::operator << (const ::std::nullptr_t&) noexcept { + Instance.Write("null"); + return *this; +} + +/// Push a number of tabs +/// Keeps track of the number of tabs that have been pushed, and then +/// automatically untabs when the Tabs object is destroyed +/// @param t - [in/out] the tabs to push +/// @return a reference to the logger for chaining +ScopedTabs Logger::A::Interface::operator << (Tabs&& t) noexcept { + auto tabs = ::std::max(1, t.mTabs); + while (tabs) { + Instance.RunCommand(Command::Tab); + --tabs; + } + + ++t.mTabs; + return ScopedTabs {t.mTabs}; +} diff --git a/source/Logger.hpp b/source/Logger.hpp index e8098d4..9fb4a10 100644 --- a/source/Logger.hpp +++ b/source/Logger.hpp @@ -3,8 +3,7 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #pragma once #include @@ -15,6 +14,9 @@ #define LANGULUS_API_LOGGER() LANGULUS_IMPORT() #endif +/// Make the rest of the code aware, that Langulus::Logger has been included +#define LANGULUS_LIBRARY_LOGGER() 1 + #include #include #include @@ -111,10 +113,11 @@ namespace Langulus::Logger enum class Command : uint8_t { Clear, // Clear the console NewLine, // Write a new line, with a timestamp and tabulation - Pop, // Pop the color state - Push, // Push the color state + Pop, // Pop the style + Push, // Push the style Invert, // Inverts background and foreground colors - Reset, // Reset the color and formatting state + Reset, // Reset the style + Stylize, // Apply the last style Tab, // Tab once on a new line after this command Untab, // Untab once, again on a new line after this command Time, // Write a short timestamp @@ -138,11 +141,11 @@ namespace Langulus::Logger }; /// Scoped tabulation marker that restores tabbing when destroyed - struct ScopedTabs : public Tabs { + struct ScopedTabs : Tabs { using Tabs::Tabs; constexpr ScopedTabs(ScopedTabs&& other) noexcept : Tabs {::std::forward(other)} {} - ~ScopedTabs() noexcept; + LANGULUS_API(LOGGER) ~ScopedTabs() noexcept; }; namespace A @@ -168,6 +171,7 @@ namespace Langulus::Logger virtual void Write(const TextView&) const noexcept = 0; virtual void Write(const Style&) const noexcept = 0; virtual void NewLine() const noexcept = 0; + virtual void Clear() const noexcept = 0; /// Implicit bool operator in order to use log in 'if' statements /// Example: if (condition && Logger::Info("stuff")) @@ -176,17 +180,18 @@ namespace Langulus::Logger return true; } - Interface& operator << (A::Interface&) noexcept; - Interface& operator << (const TextView&) noexcept; - Interface& operator << (const Command&) noexcept; - Interface& operator << (const Color&) noexcept; - Interface& operator << (const Emphasis&) noexcept; - Interface& operator << (const Style&) noexcept; - Interface& operator << (const Tabs&) noexcept; - Interface& operator << (const ::std::nullptr_t&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (A::Interface&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const TextView&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const Command&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const Color&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const Emphasis&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const Style&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const Tabs&) noexcept; + LANGULUS_API(LOGGER) Interface& operator << (const ::std::nullptr_t&) noexcept; + LANGULUS_API(LOGGER) ScopedTabs operator << (Tabs&&) noexcept; + Interface& operator << (const CT::Sparse auto&) noexcept; Interface& operator << (const ::Langulus::Logger::Formattable auto&) noexcept; - ScopedTabs operator << (Tabs&&) noexcept; }; } // namespace Langulus::Logger::A @@ -228,14 +233,15 @@ namespace Langulus::Logger LANGULUS_API(LOGGER) void Write(const TextView&) const noexcept; LANGULUS_API(LOGGER) void Write(const Style&) const noexcept; LANGULUS_API(LOGGER) void NewLine() const noexcept; + LANGULUS_API(LOGGER) void Clear() const noexcept; /// /// State changers /// LANGULUS_API(LOGGER) void RunCommand(const Command&) noexcept; - LANGULUS_API(LOGGER) void SetStyle(const Style&) noexcept; - LANGULUS_API(LOGGER) void SetColor(const Color&) noexcept; - LANGULUS_API(LOGGER) void SetEmphasis(const Emphasis&) noexcept; + LANGULUS_API(LOGGER) const Style& SetStyle(const Style&) noexcept; + LANGULUS_API(LOGGER) const Style& SetColor(const Color&) noexcept; + LANGULUS_API(LOGGER) const Style& SetEmphasis(const Emphasis&) noexcept; /// /// Attachments @@ -286,6 +292,12 @@ namespace Langulus::Logger template decltype(auto) Prompt(T&&...) noexcept; + LANGULUS_API(LOGGER) void AttachDuplicator(A::Interface*) noexcept; + LANGULUS_API(LOGGER) void DettachDuplicator(A::Interface*) noexcept; + + LANGULUS_API(LOGGER) void AttachRedirector(A::Interface*) noexcept; + LANGULUS_API(LOGGER) void DettachRedirector(A::Interface*) noexcept; + /// /// Helpful redirectors and duplicators @@ -295,37 +307,45 @@ namespace Langulus::Logger /// Consumes all logging messages, so that they don't interfere with /// rendering inside the console. /// Use it like this: - /// Logger::Instance.AttachRedirector(&Logger::MessageSinkInstance); + /// Logger::AttachRedirector(&Logger::MessageSinkInstance); /// - /// Logger::Instance.DettachRedirector(&Logger::MessageSinkInstance); + /// Logger::DettachRedirector(&Logger::MessageSinkInstance); /// /// struct MessageSink final : Logger::A::Interface { void Write(const TextView&) const noexcept {} void Write(const Style&) const noexcept {} void NewLine() const noexcept {} - } MessageSinkInstance; + void Clear() const noexcept {} + }; + + LANGULUS_API(LOGGER) extern MessageSink MessageSinkInstance; /// /// Generates HTML code from logging messages and append them to an /// output file. Can be used both as duplicator or redirector. /// Use it like this: /// Logger::ToHTML logRedirect("outputfile.htm"); - /// Logger::Instance.AttachRedirector(&logRedirect); + /// Logger::AttachRedirector(&logRedirect); /// - /// Logger::Instance.DettachRedirector(&logRedirect); + /// Logger::DettachRedirector(&logRedirect); /// /// struct ToHTML final : Logger::A::Interface { private: + std::string mFilename; mutable std::ofstream mFile; + void WriteHeader() const; + public: - ToHTML(const std::string&); + LANGULUS_API(LOGGER) ToHTML(const std::string&); + LANGULUS_API(LOGGER) ~ToHTML(); - void Write(const TextView&) const noexcept; - void Write(const Style&) const noexcept; - void NewLine() const noexcept; + LANGULUS_API(LOGGER) void Write(const TextView&) const noexcept; + LANGULUS_API(LOGGER) void Write(const Style&) const noexcept; + LANGULUS_API(LOGGER) void NewLine() const noexcept; + LANGULUS_API(LOGGER) void Clear() const noexcept; }; } // namespace Langulus::Logger @@ -335,16 +355,13 @@ namespace Langulus::Logger #include "Logger.inl" -/// Make the rest of the code aware, that Langulus::Logger has been included -#define LANGULUS_LIBRARY_LOGGER() 1 - namespace fmt { /// /// Extend FMT to be capable of logging any exception /// - template + template<::Langulus::CT::Exception T> struct formatter { template constexpr auto parse(CONTEXT& ctx) { @@ -354,10 +371,10 @@ namespace fmt template LANGULUS(INLINED) auto format(T const& e, CONTEXT& ctx) const { #if LANGULUS(DEBUG) - return fmt::format_to(ctx.out(), "{}({} at {})", + return ::fmt::format_to(ctx.out(), "{}({} at {})", e.GetName(), e.GetMessage(), e.GetLocation()); #else - return fmt::format_to(ctx.out(), "{}", e.GetName()); + return ::fmt::format_to(ctx.out(), "{}", e.GetName()); #endif } }; @@ -366,14 +383,14 @@ namespace fmt /// Extend FMT to be capable of logging byte sizes /// template<> - struct formatter { - template - constexpr auto parse(ParseContext& ctx) { + struct formatter<::Langulus::Size> { + template + constexpr auto parse(CONTEXT& ctx) { return ctx.begin(); } - template - auto format(const Langulus::Size& bs, FormatContext& ctx) const { + template + auto format(::Langulus::Size const& bs, CONTEXT& ctx) const { double f; if (bs < 1'024LL) f = static_cast(bs); @@ -392,10 +409,10 @@ namespace fmt else f = bs * 1. / 1'073'741'824LL; double intpart; - if (std::modf(f, &intpart) < 0.001) - return format_to(ctx.out(), "{} {}", (::std::size_t) f, bs.GetSuffix()); + if (::std::modf(f, &intpart) < 0.001) + return ::fmt::format_to(ctx.out(), "{} {}", static_cast<::std::size_t>(f), bs.GetSuffix()); else - return format_to(ctx.out(), "{:.2f} {}", f, bs.GetSuffix()); + return ::fmt::format_to(ctx.out(), "{:.2f} {}", f, bs.GetSuffix()); } }; diff --git a/source/Logger.inl b/source/Logger.inl index bd9b64a..35f6c57 100644 --- a/source/Logger.inl +++ b/source/Logger.inl @@ -3,8 +3,7 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #pragma once #include "Logger.hpp" @@ -13,15 +12,6 @@ namespace Langulus::Logger { - /// Scoped tabulator destruction - LANGULUS(INLINED) - ScopedTabs::~ScopedTabs() noexcept { - while (mTabs > 0) { - --mTabs; - Instance.RunCommand(Command::Untab); - } - } - /// Analyzes text returned by LANGULUS(FUNCTION) in order to isolate the /// name part for logging /// @param text - the text to scan @@ -77,91 +67,14 @@ namespace Langulus::Logger return nodecorations; } - /// Does nothing, but allows for grouping logging statements in () - /// Example: Logger::Error() << "yeah" << (Logger::Info() << "no") - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (A::Interface&) noexcept { - return *this; - } - - /// Push a command - /// @param c - the command to push - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const Command& c) noexcept { - Instance.RunCommand(c); - return *this; - } - - /// Push a foreground color - /// @param c - the command to push - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const Color& c) noexcept { - Instance.SetColor(c); - return *this; - } - - /// Push an emphasis - /// @param e - the emphasis to push - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const Emphasis& e) noexcept { - Instance.SetEmphasis(e); - return *this; - } - - /// Push a foreground and background color - /// @param c - the state to push - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const Style& c) noexcept { - Instance.SetStyle(c); - return *this; - } - - /// Push a number of tabs - /// @param t - the tabs to push - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const Tabs& t) noexcept { - auto tabs = ::std::max(1, t.mTabs); - while (tabs) { - Instance.RunCommand(Command::Tab); - --tabs; - } - - return *this; - } - - /// Write string views - /// @param t - text to write - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const TextView& t) noexcept { - Instance.Write(t); - return *this; - } - - /// Write a nullptr as "null" - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - A::Interface& A::Interface::operator << (const ::std::nullptr_t&) noexcept { - Instance.Write("null"); - return *this; - } - /// Dereference anything sparse, and route it through the logger again /// @param anything - pointer to stringify /// @return a reference to the logger for chaining LANGULUS(INLINED) A::Interface& A::Interface::operator << (const CT::Sparse auto& sparse) noexcept { using T = Deref; - if constexpr (CT::String) { - Instance.Write(sparse); - return *this; - } + if constexpr (CT::String) + return operator << (TextView {sparse}); else { using DT = Deptr; static_assert(CT::Sparse
or ::Langulus::Logger::Formattable
, @@ -179,25 +92,8 @@ namespace Langulus::Logger /// @return a reference to the logger for chaining LANGULUS(INLINED) A::Interface& A::Interface::operator << (const ::Langulus::Logger::Formattable auto& anything) noexcept { - Instance.Write(fmt::format("{}", anything)); - return *this; - } - - /// Push a number of tabs - /// Keeps track of the number of tabs that have been pushed, and then - /// automatically untabs when the Tabs object is destroyed - /// @param t - [in/out] the tabs to push - /// @return a reference to the logger for chaining - LANGULUS(INLINED) - ScopedTabs A::Interface::operator << (Tabs&& t) noexcept { - auto tabs = ::std::max(1, t.mTabs); - while (tabs) { - Instance.RunCommand(Command::Tab); - --tabs; - } - - ++t.mTabs; - return ScopedTabs {t.mTabs}; + const auto formatted = fmt::format("{}", anything); + return operator << (TextView {formatted}); } /// A general new-line write function with color diff --git a/test/Main.cpp b/test/Main.cpp index b764f2c..623440a 100644 --- a/test/Main.cpp +++ b/test/Main.cpp @@ -3,8 +3,7 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #include "Main.hpp" diff --git a/test/Main.hpp b/test/Main.hpp index 0a850dc..a8f30c4 100644 --- a/test/Main.hpp +++ b/test/Main.hpp @@ -3,8 +3,7 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #pragma once #include diff --git a/test/TestLogger.cpp b/test/TestLogger.cpp index 9773ac3..a9a274c 100644 --- a/test/TestLogger.cpp +++ b/test/TestLogger.cpp @@ -3,12 +3,12 @@ /// Copyright (c) 2012 Dimo Markov /// Part of the Langulus framework, see https://langulus.com /// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses +/// SPDX-License-Identifier: MIT /// #include "Main.hpp" #include + SCENARIO("Logging to console", "[logger]") { GIVEN("An initialized logger") { WHEN("Calling Logger::Line()") {