From c44b263973ff327d523a0206d81df1c7064a30b2 Mon Sep 17 00:00:00 2001 From: Tsche Date: Thu, 11 Sep 2025 01:36:07 +0000 Subject: [PATCH 1/2] format extensions (colorization, member access etc) --- example/CMakeLists.txt | 16 +- example/format.cpp | 11 + include/rsl/_format_impl/accessor.hpp | 44 ++++ include/rsl/_format_impl/fmt_parser.hpp | 311 ++++++++++++++++++++++++ include/rsl/_format_impl/parser.hpp | 72 ++++++ include/rsl/_format_impl/style.hpp | 35 +++ include/rsl/_format_impl/util.hpp | 40 +++ include/rsl/format | 32 +++ include/rsl/print | 41 ++++ include/rsl/style/terminal.hpp | 33 +++ include/rsl/variant | 4 +- src/print.cpp | 0 test/CMakeLists.txt | 1 + test/format/CMakeLists.txt | 3 + test/format/field_parser.cpp | 120 +++++++++ 15 files changed, 754 insertions(+), 9 deletions(-) create mode 100644 example/format.cpp create mode 100644 include/rsl/_format_impl/accessor.hpp create mode 100644 include/rsl/_format_impl/fmt_parser.hpp create mode 100644 include/rsl/_format_impl/parser.hpp create mode 100644 include/rsl/_format_impl/style.hpp create mode 100644 include/rsl/_format_impl/util.hpp create mode 100644 include/rsl/format create mode 100644 include/rsl/print create mode 100644 include/rsl/style/terminal.hpp create mode 100644 src/print.cpp create mode 100644 test/format/CMakeLists.txt create mode 100644 test/format/field_parser.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 29a335e..e3b8145 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,12 +1,14 @@ function(DEFINE_EXAMPLE TARGET) add_executable(example_${TARGET} "${TARGET}.cpp") - target_link_libraries(example_${TARGET} PRIVATE rsl_util) + target_link_libraries(example_${TARGET} PRIVATE rsl-util) endfunction() -DEFINE_EXAMPLE(assert) +# DEFINE_EXAMPLE(assert) -add_executable(example_review - review.cpp - review_tu2.cpp -) -target_link_libraries(example_review PRIVATE rsl_util) \ No newline at end of file +DEFINE_EXAMPLE(format) + +# add_executable(example_review +# review.cpp +# review_tu2.cpp +# ) +# target_link_libraries(example_review PRIVATE rsl_util) \ No newline at end of file diff --git a/example/format.cpp b/example/format.cpp new file mode 100644 index 0000000..b26e239 --- /dev/null +++ b/example/format.cpp @@ -0,0 +1,11 @@ +#include +struct Foo {int a; char b;}; +int main() { + rsl::println("a {[red]1} asdf {[blue]0} b", 42, 'c'); + rsl::println("a {[cyan]} asdf {[green]} b", 42, 'c'); + rsl::println("a {[yellow]!}{} sfdg {}{[reset]!} b", 42, 'c'); + + rsl::println("b={b}, a={a}", Foo(42, 'c')); + rsl::println("b={0.b}, a={0.a}", Foo(42, 'c')); + rsl::println("b={0.1}, a={0.0}", Foo(42, 'c')); +} \ No newline at end of file diff --git a/include/rsl/_format_impl/accessor.hpp b/include/rsl/_format_impl/accessor.hpp new file mode 100644 index 0000000..8756448 --- /dev/null +++ b/include/rsl/_format_impl/accessor.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include + +namespace rsl::_format_impl { + template +struct MemberAccessor { + template + friend constexpr decltype(auto) operator>>(T&& obj, MemberAccessor) { + return std::forward_like(std::forward(obj).[:Member:]); + } +}; + +template +struct SubscriptAccessor { + template + friend constexpr decltype(auto) operator>>(T&& obj, SubscriptAccessor) { + return std::forward_like(std::forward(obj)[Idx]); + } +}; + +template +struct TupleAccessor { + template + friend constexpr decltype(auto) operator>>(T&& obj, TupleAccessor) { + using std::get; + return get(std::forward(obj)); + } +}; + +template +struct Accessor { + static constexpr std::size_t index = Idx; + + template + static constexpr decltype(auto) get(T&& obj) { + return (std::forward(obj) >> ... >> Fields{}); + } +}; + +template +struct AccessorList {}; +} \ No newline at end of file diff --git a/include/rsl/_format_impl/fmt_parser.hpp b/include/rsl/_format_impl/fmt_parser.hpp new file mode 100644 index 0000000..1c17ccf --- /dev/null +++ b/include/rsl/_format_impl/fmt_parser.hpp @@ -0,0 +1,311 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "accessor.hpp" +#include "parser.hpp" +#include "style.hpp" +#include "util.hpp" + +namespace rsl::_format_impl { + +struct FormatResult { + using join_t = std::string (FormatResult::*)(StyleMap const*) const; + join_t join; + + template + std::string join_impl(StyleMap const* style_map) const { + static constexpr Style::Tag style_tags[] = {Args...}; + + std::string result; + result.reserve(raw.size() - sizeof...(Args)); + + std::size_t index = 0; + for (auto&& substr : std::views::split(raw, style_separator)) { + result += std::string_view(substr); + if (style_map != nullptr && sizeof...(Args) > index) { + result += (*style_map)[style_tags[index++]]; + } + } + return result; + } + + FormatResult(std::string result, join_t joiner) : raw(result), join(joiner) {} + + std::string raw; + [[nodiscard]] std::string with_style(StyleMap const& style) const { + return (this->*join)(&style); + } + [[nodiscard]] std::string unstyled() const { return (this->*join)(nullptr); } + [[nodiscard]] constexpr explicit(false) operator std::string() const { return unstyled(); } +}; + +template +FormatResult format_impl(Args&&... args) { + auto str = [&](AccessorList) { + return std::format(fmt.data(), Xs::get(args...[Xs::index])...); + }(Accessors{}); + return FormatResult(str, extract(Joiner)); +} + +struct FormatString { + std::string string; + std::vector