diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 808f250..492a4f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,8 +13,8 @@ PRIVATE # Sources yycc/string/reinterpret.cpp yycc/string/op.cpp - yycc/string/stream.cpp yycc/patch/fopen.cpp + yycc/patch/stream.cpp yycc/rust/panic.cpp yycc/rust/env.cpp yycc/windows/com.cpp @@ -31,10 +31,11 @@ PRIVATE yycc/carton/tabulate.cpp yycc/carton/ironpad.cpp yycc/carton/csconsole.cpp - yycc/carton/clap/option.cpp - yycc/carton/clap/variable.cpp - yycc/carton/clap/summary.cpp - yycc/carton/clap/application.cpp + #yycc/carton/clap/option.cpp + #yycc/carton/clap/variable.cpp + #yycc/carton/clap/summary.cpp + #yycc/carton/clap/application.cpp + #yycc/carton/clap/manual.cpp ) target_sources(YYCCommonplace PUBLIC @@ -54,10 +55,10 @@ FILES yycc/flag_enum.hpp yycc/string/reinterpret.hpp yycc/string/op.hpp - yycc/string/stream.hpp - yycc/string/format.hpp yycc/patch/ptr_pad.hpp yycc/patch/fopen.hpp + yycc/patch/stream.hpp + yycc/patch/format.hpp yycc/num/parse.hpp yycc/num/stringify.hpp yycc/num/safe_cast.hpp @@ -93,6 +94,7 @@ FILES yycc/carton/clap/variable.hpp yycc/carton/clap/summary.hpp yycc/carton/clap/application.hpp + yycc/carton/clap/manual.hpp ) # Setup header infomations target_include_directories(YYCCommonplace diff --git a/src/yycc/carton/clap/application.cpp b/src/yycc/carton/clap/application.cpp index 2175eaa..32dc4a6 100644 --- a/src/yycc/carton/clap/application.cpp +++ b/src/yycc/carton/clap/application.cpp @@ -1,12 +1,12 @@ #include "application.hpp" -#define NS_YYCC_CLAP ::yycc::carton::clap +#define CLAP ::yycc::carton::clap namespace yycc::carton::clap::application { - using Summary = NS_YYCC_CLAP::summary::Summary; - using OptionCollection = NS_YYCC_CLAP::option::OptionCollection; - using VariableCollection = NS_YYCC_CLAP::variable::VariableCollection; + using Summary = CLAP::summary::Summary; + using OptionCollection = CLAP::option::OptionCollection; + using VariableCollection = CLAP::variable::VariableCollection; Application::Application(Summary &&summary, OptionCollection &&options, VariableCollection &&variables) : summary(std::move(summary)), options(std::move(options)), variables(std::move(variables)) {} diff --git a/src/yycc/carton/clap/application.hpp b/src/yycc/carton/clap/application.hpp index 58c8ead..3690e30 100644 --- a/src/yycc/carton/clap/application.hpp +++ b/src/yycc/carton/clap/application.hpp @@ -2,6 +2,7 @@ #include "summary.hpp" #include "option.hpp" #include "variable.hpp" +#include "../../macro/class_copy_move.hpp" #define NS_YYCC_CLAP ::yycc::carton::clap diff --git a/src/yycc/carton/clap/manual.cpp b/src/yycc/carton/clap/manual.cpp new file mode 100644 index 0000000..c04b544 --- /dev/null +++ b/src/yycc/carton/clap/manual.cpp @@ -0,0 +1,69 @@ +#include "manual.hpp" +#include "../termcolor.hpp" +#include "../../patch/stream.hpp" +#include "../../string/op.hpp" + +#define CLAP ::yycc::carton::clap +#define TABULATE ::yycc::carton::tabulate +#define TERMCOLOR ::yycc::carton::termcolor +#define OP ::yycc::carton::op + +using namespace ::yycc::patch::stream; + +namespace yycc::carton::clap::manual::Manual { + +#pragma region Manual Translation + + ManualTr::ManualTr() : + author_and_version(u8"Invented by {0}. Version {1}."), usage_title(u8"Usage:"), usage_body(u8"{0} ..."), + avail_opt(u8"Available options:"), avail_var(u8"Available environment variables:") {} + + ManualTr::~ManualTr() {} + +#pragma endregion + +#pragma region Manual + + using Application = CLAP::application::Application; + using Tabulate = TABULATE::Tabulate; + + Manual::Manual(const Application &app, ManualTr &&trctx) : trctx(std::move(trctx)), app(app), opt_printer(3), var_printer(2) { + this->setup_table(); + this->fill_opt_table(); + this->fill_var_table(); + } + + Manual::~Manual() {} + + void Manual::setup_table() { + this->opt_printer.show_header(false); + this->opt_printer.show_bar(false); + this->opt_printer.set_prefix(u8" "); + + this->var_printer.show_header(false); + this->var_printer.show_bar(false); + this->var_printer.set_prefix(u8" "); + } + + void Manual::fill_opt_table() { + const auto &options = app.get_options(); + for (const auto ®_opt : options.all_options()) { + const auto &opt = reg_opt.get_option(); + } + } + + void Manual::fill_var_table() {} + + void Manual::print_version(std::ostream &dst) const { + const auto &summary = this->app.get_summary(); + + dst << std::format + dst << summary.get_description() << std::endl; + dst << std::endl; + } + + void Manual::print_help(std::ostream &dst) const {} + +#pragma endregion + +} // namespace yycc::carton::clap::manual::Manual diff --git a/src/yycc/carton/clap/manual.hpp b/src/yycc/carton/clap/manual.hpp new file mode 100644 index 0000000..8ce2751 --- /dev/null +++ b/src/yycc/carton/clap/manual.hpp @@ -0,0 +1,49 @@ +#pragma once +#include "application.hpp" +#include "../../macro/class_copy_move.hpp" +#include "../tabulate.hpp" +#include + +#define NS_YYCC_CLAP ::yycc::carton::clap +#define NS_YYCC_TABULATE ::yycc::carton::tabulate + +namespace yycc::carton::clap::manual::Manual { + + struct ManualTr { + public: + ManualTr(); + ~ManualTr(); + YYCC_DEFAULT_COPY_MOVE(ManualTr); + + public: + std::u8string author_and_version; + std::u8string usage_title, usage_body; + std::u8string avail_opt, avail_var; + }; + + class Manual { + public: + Manual(const NS_YYCC_CLAP::application::Application& app, ManualTr&& trctx = ManualTr()); + ~Manual(); + YYCC_DEFAULT_COPY_MOVE(Manual); + + private: + void setup_table(); + void fill_opt_table(); + void fill_var_table(); + + public: + void print_version(std::ostream& dst = std::cout) const; + void print_help(std::ostream& dst = std::cout) const; + + private: + ManualTr trctx; + const NS_YYCC_CLAP::application::Application app; + NS_YYCC_TABULATE::Tabulate opt_printer; + NS_YYCC_TABULATE::Tabulate var_printer; + }; + +} + +#undef NS_YYCC_TABULATE +#undef NS_YYCC_CLAP diff --git a/src/yycc/carton/clap/option.cpp b/src/yycc/carton/clap/option.cpp index 8a72083..74f8df6 100644 --- a/src/yycc/carton/clap/option.cpp +++ b/src/yycc/carton/clap/option.cpp @@ -1,6 +1,6 @@ #include "option.hpp" #include "../../string/op.hpp" -#include "../../string/format.hpp" +#include "../../patch/format.hpp" #include #include diff --git a/src/yycc/carton/clap/variable.cpp b/src/yycc/carton/clap/variable.cpp index 3a3ed1a..346f0b2 100644 --- a/src/yycc/carton/clap/variable.cpp +++ b/src/yycc/carton/clap/variable.cpp @@ -1,5 +1,5 @@ #include "variable.hpp" -#include "../../string/format.hpp" +#include "../../patch/format.hpp" #include #include diff --git a/src/yycc/carton/ironpad.cpp b/src/yycc/carton/ironpad.cpp index c9403ec..70286bc 100644 --- a/src/yycc/carton/ironpad.cpp +++ b/src/yycc/carton/ironpad.cpp @@ -82,6 +82,8 @@ namespace yycc::carton::ironpad { m_UserCallback = callback; // mark registered m_IsRegistered = true; + + return true; } /** * @brief Try to unregister unhandled exception handler. diff --git a/src/yycc/string/format.hpp b/src/yycc/patch/format.hpp similarity index 69% rename from src/yycc/string/format.hpp rename to src/yycc/patch/format.hpp index b2bf73a..a2394d7 100644 --- a/src/yycc/string/format.hpp +++ b/src/yycc/patch/format.hpp @@ -8,15 +8,46 @@ * By including this file directly, you will have abilities that use UTF8 string as argument in \c std::format with \c char char type. */ #pragma once -#include "reinterpret.hpp" +#include "../string/reinterpret.hpp" #include #include #include #define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret +#pragma region Utf8 Format + +namespace yycc::patch::format { + + // TODO: order all use of std::format redirect to this function. + + template + std::string format(std::format_string fmt, Args&&... args) { + return std::vformat(fmt.get(), std::make_format_args(args...)); + } + + template + std::u8string format(const std::u8string_view& fmt, Args&&... args) { + return NS_YYCC_STRING_REINTERPRET::as_utf8( + std::vformat(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(fmt), std::make_format_args(args...))); + } + +} // namespace yycc::patch::format + +#pragma endregion + #pragma region Utf8 Formatter +// Add std::formatter specialization for "char8_t" +template<> +struct std::formatter { + constexpr auto parse(auto& ctx) { return underlying_formatter.parse(ctx); } + auto format(const char8_t& str, auto& ctx) const { return underlying_formatter.format(NS_YYCC_STRING_REINTERPRET::as_ordinary(str), ctx); } + +private: + std::formatter underlying_formatter{}; +}; + // Add std::formatter specialization for "char8_t*" template<> struct std::formatter { @@ -43,7 +74,9 @@ private: template struct std::formatter { constexpr auto parse(auto& ctx) { return underlying_formatter.parse(ctx); } - auto format(const char8_t (&str)[N], auto& ctx) const { return underlying_formatter.format(std::basic_string_view(str, N), ctx); } + auto format(const char8_t (&str)[N], auto& ctx) const { + return underlying_formatter.format(std::basic_string_view(NS_YYCC_STRING_REINTERPRET::as_ordinary(str), N - 1), ctx); + } private: std::formatter, char> underlying_formatter{}; diff --git a/src/yycc/string/stream.cpp b/src/yycc/patch/stream.cpp similarity index 88% rename from src/yycc/string/stream.cpp rename to src/yycc/patch/stream.cpp index 1090842..34933fe 100644 --- a/src/yycc/string/stream.cpp +++ b/src/yycc/patch/stream.cpp @@ -1,9 +1,9 @@ #include "stream.hpp" -#include "reinterpret.hpp" +#include "../string/reinterpret.hpp" #define REINTERPRET ::yycc::string::reinterpret -namespace yycc::string::stream { +namespace yycc::patch::stream { std::ostream& operator<<(std::ostream& os, const std::u8string_view& u8str) { os << REINTERPRET::as_ordinary_view(u8str); diff --git a/src/yycc/string/stream.hpp b/src/yycc/patch/stream.hpp similarity index 86% rename from src/yycc/string/stream.hpp rename to src/yycc/patch/stream.hpp index 4a5b4df..4bcb281 100644 --- a/src/yycc/string/stream.hpp +++ b/src/yycc/patch/stream.hpp @@ -6,9 +6,9 @@ * @brief This namespace add UTF8 support for \c std::ostream. * @details * The operator overloads written in this namespace will give \c std::ostream ability to write UTF8 string and its char. - * For using this feature, please directly use using namespace yycc::string:stream; to import this namespace. + * For using this feature, please directly use using namespace yycc::patch:stream; to import this namespace. */ -namespace yycc::string::stream { +namespace yycc::patch::stream { std::ostream& operator<<(std::ostream& os, const std::u8string_view& u8str); std::ostream& operator<<(std::ostream& os, const char8_t* u8str); diff --git a/src/yycc/string/reinterpret.cpp b/src/yycc/string/reinterpret.cpp index 8f9e859..e12abc5 100644 --- a/src/yycc/string/reinterpret.cpp +++ b/src/yycc/string/reinterpret.cpp @@ -2,6 +2,9 @@ namespace yycc::string::reinterpret { + char8_t as_utf8(const char& src) { + return static_cast(src); + } const char8_t* as_utf8(const char* src) { return reinterpret_cast(src); } @@ -15,6 +18,9 @@ namespace yycc::string::reinterpret { return std::u8string_view(reinterpret_cast(src.data()), src.size()); } + char as_ordinary(char8_t src) { + return static_cast(src); + } const char* as_ordinary(const char8_t* src) { return reinterpret_cast(src); } diff --git a/src/yycc/string/reinterpret.hpp b/src/yycc/string/reinterpret.hpp index f5acb1e..67e86c6 100644 --- a/src/yycc/string/reinterpret.hpp +++ b/src/yycc/string/reinterpret.hpp @@ -11,52 +11,64 @@ */ namespace yycc::string::reinterpret { + /** + * @brief Reinterpret ordinary char type to UTF-8 char type. + * @param[in] src Source ordinary char value. + * @return UTF8 char value. + */ + char8_t as_utf8(const char& src); /** * @brief Reinterpret ordinary C-string to UTF-8 string (const version). - * @param src Source ordinary string + * @param[in] src Source ordinary string * @return Pointer to UTF-8 encoded string */ const char8_t* as_utf8(const char* src); /** * @brief Reinterpret ordinary C-string as an UTF-8 string (non-const version). - * @param src Source ordinary string + * @param[in] src Source ordinary string * @return Pointer to UTF-8 encoded string */ char8_t* as_utf8(char* src); /** * @brief Reinterpret ordinary string view to copied UTF-8 string. - * @param src Source ordinary string view + * @param[in] src Source ordinary string view * @return UTF-8 encoded string */ std::u8string as_utf8(const std::string_view& src); /** * @brief Reinterpret ordinary string view to UTF-8 string view. - * @param src Source ordinary string view + * @param[in] src Source ordinary string view * @return UTF-8 encoded string view */ std::u8string_view as_utf8_view(const std::string_view& src); + /** + * @brief Reinterpret UTF-8 char type to ordinary char type. + * @param[in] src Source UTF-8 char value. + * @return Ordinary char value. + */ + char as_ordinary(char8_t src); /** * @brief Reinterpret UTF-8 C-string to ordinary string (const version). - * @param src Source UTF-8 string + * @param[in] src Source UTF-8 string * @return Pointer to ordinary string */ const char* as_ordinary(const char8_t* src); /** * @brief Reinterpret UTF-8 C-string to ordinary string (non-const version). - * @param src Source UTF-8 string + * @param[in] src Source UTF-8 string * @return Pointer to ordinary string */ char* as_ordinary(char8_t* src); /** * @brief Reinterpret UTF-8 string view to ordinary string. - * @param src Source UTF-8 string view + * @param[in] src Source UTF-8 string view * @return Ordinary string */ std::string as_ordinary(const std::u8string_view& src); /** * @brief Reinterpret UTF-8 string view to ordinary string view - * @param src Source UTF-8 string view + * @param[in] src Source UTF-8 string view * @return Ordinary string view */ std::string_view as_ordinary_view(const std::u8string_view& src); diff --git a/testbench/CMakeLists.txt b/testbench/CMakeLists.txt index 167b75e..6da20b3 100644 --- a/testbench/CMakeLists.txt +++ b/testbench/CMakeLists.txt @@ -18,10 +18,11 @@ PRIVATE yycc/constraint/builder.cpp yycc/patch/ptr_pad.cpp yycc/patch/fopen.cpp + yycc/patch/stream.cpp + yycc/patch/format.cpp yycc/rust/env.cpp yycc/string/reinterpret.cpp yycc/string/op.cpp - yycc/string/stream.cpp yycc/num/parse.cpp yycc/num/stringify.cpp yycc/num/op.cpp diff --git a/testbench/yycc/patch/format.cpp b/testbench/yycc/patch/format.cpp new file mode 100644 index 0000000..b33b667 --- /dev/null +++ b/testbench/yycc/patch/format.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +#define FORMAT ::yycc::patch::format + +namespace yycctest::patch::format { + + static constexpr char8_t PROBE[] = u8"hello"; + static std::u8string PROBE_STRING(PROBE); + static constexpr std::u8string_view PROBE_STRING_VIEW(PROBE); + + TEST(PatchFormat, OrdinaryFormat) { + auto rv = FORMAT::format("{}{}{}{}{}{} world!", + PROBE[0], + PROBE_STRING.data(), + PROBE_STRING.c_str(), + PROBE, + PROBE_STRING, + PROBE_STRING_VIEW); + EXPECT_EQ(rv, "104hellohellohellohellohello world!"); + } + + TEST(PatchFormat, Utf8Format) { + auto rv = FORMAT::format(u8"{}{}{}{}{}{} world!", + PROBE[0], + PROBE_STRING.data(), + PROBE_STRING.c_str(), + PROBE, + PROBE_STRING, + PROBE_STRING_VIEW); + EXPECT_EQ(rv, u8"104hellohellohellohellohello world!"); + } + +} diff --git a/testbench/yycc/string/stream.cpp b/testbench/yycc/patch/stream.cpp similarity index 73% rename from testbench/yycc/string/stream.cpp rename to testbench/yycc/patch/stream.cpp index 001264a..69a75e7 100644 --- a/testbench/yycc/string/stream.cpp +++ b/testbench/yycc/patch/stream.cpp @@ -1,28 +1,28 @@ #include #include -#include +#include #include #include #define REINTERPRET ::yycc::string::reinterpret using namespace std::literals::string_view_literals; -using namespace ::yycc::string::stream; +using namespace ::yycc::patch::stream; -namespace yycctest::string::stream { +namespace yycctest::patch::stream { - TEST(StringStream, StringView) { + TEST(PatchStream, StringView) { std::stringstream ss; ss << u8"hello"sv; EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), u8"hello"sv); } - TEST(StringStream, CStrPtr) { + TEST(PatchStream, CStrPtr) { std::stringstream ss; ss << u8"hello"; EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), u8"hello"); } - TEST(StringStream, Character) { + TEST(PatchStream, Character) { std::stringstream ss; ss << u8'y'; EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), u8"y"); diff --git a/testbench/yycc/string/reinterpret.cpp b/testbench/yycc/string/reinterpret.cpp index 4297fae..0dbe128 100644 --- a/testbench/yycc/string/reinterpret.cpp +++ b/testbench/yycc/string/reinterpret.cpp @@ -6,6 +6,7 @@ #include #define REINTERPRET ::yycc::string::reinterpret +#define AS_UINT8(p) static_cast(p) #define CONST_VOID_PTR(p) reinterpret_cast(p) #define VOID_PTR(p) reinterpret_cast(p) @@ -13,6 +14,16 @@ namespace yycctest::string::reinterpret { static std::u8string PROBE(u8"Test"); + TEST(StringReinterpret, Character) { + const auto& src = PROBE[0]; + const auto dst = REINTERPRET::as_ordinary(src); + const auto new_src = REINTERPRET::as_utf8(dst); + + // Value should be the same after casting. + EXPECT_EQ(AS_UINT8(src), AS_UINT8(dst)); + EXPECT_EQ(AS_UINT8(src), AS_UINT8(new_src)); + } + TEST(StringReinterpret, ConstPointer) { const auto* src = PROBE.data(); const auto* dst = REINTERPRET::as_ordinary(src); @@ -33,7 +44,7 @@ namespace yycctest::string::reinterpret { EXPECT_EQ(VOID_PTR(src), VOID_PTR(new_src)); } - TEST(StringReinterpret, String) { + TEST(StringReinterpret, StlString) { auto src = std::u8string(PROBE); auto dst = REINTERPRET::as_ordinary(src); auto new_src = REINTERPRET::as_utf8(dst); @@ -45,7 +56,7 @@ namespace yycctest::string::reinterpret { EXPECT_TRUE(std::memcmp(src.data(), new_src.data(), src.length()) == 0); } - TEST(StringReinterpret, StringView) { + TEST(StringReinterpret, StlStringView) { auto src = std::u8string_view(PROBE); auto dst = REINTERPRET::as_ordinary_view(src); auto new_src = REINTERPRET::as_utf8_view(dst);