diff --git a/src/bot/base_commands.cpp b/src/bot/base_commands.cpp index d2d16c4..9fb5546 100644 --- a/src/bot/base_commands.cpp +++ b/src/bot/base_commands.cpp @@ -29,7 +29,7 @@ using namespace std::literals; command quit_command{ [](command_context& context) { using namespace jessilib::io; text quit_text{ u8"Closing jessibot", text::property::bold, color{ 0xFF0000 } }; // TODO: localize - context.publicReply(formatted_message{ "{}", quit_text }); + context.publicReply(formatted_message{ u8"{}", quit_text }); notify_shutdown(); }, u8"quit" }; @@ -40,19 +40,19 @@ command help_command{ [](command_context& context) { if (table_name.empty()) { text error_text{ u8"ERROR", text::property::bold, color{ 0xFF0000 } }; // TODO: localize - context.publicReply(formatted_message{ "{} command context is missing permission table name", error_text }); + context.publicReply(formatted_message{ u8"{} command context is missing permission table name", error_text }); return; } // table examples: "console", "irc", "irc+", "irc%", "irc@"; should table instead be 'tables'? text table_text{ table_name, text::property::bold, color{ 0x0000FF } }; - context.publicReply(formatted_message{ "Commands for table '{}':", table_text }); + context.publicReply(formatted_message{ u8"Commands for table '{}':", table_text }); // TODO: read some permission table and filter commands based upon permission and context information const command_manager& manager = command_manager::instance(); manager.foreach([&context](basic_command* in_command) { - context.publicReply(formatted_message{ "{}", in_command->label() }); + context.publicReply(formatted_message{ u8"{}", in_command->label() }); return true; }); }, u8"help" }; diff --git a/src/bot/console/console.cpp b/src/bot/console/console.cpp index 055ec9e..fd868f2 100644 --- a/src/bot/console/console.cpp +++ b/src/bot/console/console.cpp @@ -38,8 +38,8 @@ void console_input_loop() { if (!command_manager::instance().execute_command(context)) { text error_text{ u8"ERROR", text::property::bold, color{ 0xFF0000 }}; text keyword_text{ context.keyword(), text::property::bold, color{ 0x0000FF }}; - auto result = process_message(formatted_message{"{} Command \"{}\" not found", error_text, keyword_text}); - std::cout << result << std::endl; + auto result = process_message(formatted_message{u8"{} Command \"{}\" not found", error_text, keyword_text}); + std::wcout << jessilib::string_cast(result) << std::endl; } } } diff --git a/src/bot/console/console_command_context.cpp b/src/bot/console/console_command_context.cpp index 3974f1b..ee37627 100644 --- a/src/bot/console/console_command_context.cpp +++ b/src/bot/console/console_command_context.cpp @@ -47,7 +47,7 @@ jessilib::object console_command_context::details() const { return s_details; } -std::string console_command_context::getText(std::string_view tag) const { +std::u8string console_command_context::getText(std::u8string_view tag) const { return { tag.begin(), tag.end() }; // TODO: implement properly } diff --git a/src/bot/console/console_command_context.hpp b/src/bot/console/console_command_context.hpp index ef07c70..74dc0eb 100644 --- a/src/bot/console/console_command_context.hpp +++ b/src/bot/console/console_command_context.hpp @@ -33,7 +33,7 @@ public: /** Additional contextual details */ jessilib::object details() const override; - std::string getText(std::string_view tag) const override; + std::u8string getText(std::u8string_view tag) const override; }; // class console_command_context } // namespace io diff --git a/src/external/fmt b/src/external/fmt index 812733c..9d5b9de 160000 --- a/src/external/fmt +++ b/src/external/fmt @@ -1 +1 @@ -Subproject commit 812733cc963b2e1d96f6ad2cb2d441c6fe8e4a5b +Subproject commit 9d5b9defde1334726d35c0d21b6225511ed3976e diff --git a/src/include/jessilib/io/ansi/ansi_text.hpp b/src/include/jessilib/io/ansi/ansi_text.hpp index 35ee08c..c039d51 100644 --- a/src/include/jessilib/io/ansi/ansi_text.hpp +++ b/src/include/jessilib/io/ansi/ansi_text.hpp @@ -29,7 +29,7 @@ class text_wrapper : public text {}; // Control characters static constexpr uint8_t ESCAPE_CHR{ 0x1B }; -static constexpr std::string_view ESCAPE{ "\x1B[" }; +static constexpr std::u8string_view ESCAPE{ u8"\x1B[" }; // ESCAPE + '[' + + 'm' // Graphics modes @@ -42,16 +42,16 @@ static constexpr uint8_t CONCEALED{ '8' }; static constexpr uint8_t GRAPHICS_SEP{ ';' }; static constexpr uint8_t GRAPHICS_END{ 'm' }; -static constexpr std::string_view COLOR_HEX{ "38;2" }; -static constexpr std::string_view COLOR_DEFAULT{ "39" }; -static constexpr std::string_view COLOR_BG_HEX{ "48;2" }; -static constexpr std::string_view COLOR_BG_DEFAULT{ "49" }; +static constexpr std::u8string_view COLOR_HEX{ u8"38;2" }; +static constexpr std::u8string_view COLOR_DEFAULT{ u8"39" }; +static constexpr std::u8string_view COLOR_BG_HEX{ u8"48;2" }; +static constexpr std::u8string_view COLOR_BG_DEFAULT{ u8"49" }; } // namespace ansi template<> -inline std::string text_to_string(const ansi::text_wrapper& in_text) { - std::string result; +inline std::u8string text_to_string(const ansi::text_wrapper& in_text) { + std::u8string result; result.reserve(in_text.string().size() + 8); auto set_graphic_option = [&result](auto in_option) { @@ -65,7 +65,12 @@ inline std::string text_to_string(const ansi::text_wrapper& } // Append graphics option - result += in_option; + if constexpr (std::is_same_v) { + result += jessilib::string_view_cast(in_option); + } + else { + result += in_option; + } }; // Set graphics properties @@ -100,7 +105,7 @@ inline std::string text_to_string(const ansi::text_wrapper& } // Append textual string - result += jessilib::ustring_to_mbstring(std::u8string_view{in_text.string()}).second; + result += in_text.string(); // Reset (if needed) if (in_text.properties() != text::property::normal) { @@ -117,10 +122,10 @@ inline std::string text_to_string(const ansi::text_wrapper& } // namespace jessilib template<> -struct fmt::formatter : formatter { +struct fmt::formatter : formatter { template auto format(const jessilib::io::ansi::text_wrapper& in_text, FormatContext& in_context) { // Pass result to base - return formatter::format(jessilib::io::text_to_string(in_text), in_context); + return formatter::format(jessilib::io::text_to_string(in_text), in_context); } }; diff --git a/src/include/jessilib/io/command_context.hpp b/src/include/jessilib/io/command_context.hpp index 0a14f12..4257b8f 100644 --- a/src/include/jessilib/io/command_context.hpp +++ b/src/include/jessilib/io/command_context.hpp @@ -43,7 +43,7 @@ public: /** Additional contextual details */ virtual object details() const = 0; // Additional details - virtual std::string getText(std::string_view tag) const = 0; // Get localized text + virtual std::u8string getText(std::u8string_view tag) const = 0; // Get localized text private: string_type m_input; diff --git a/src/include/jessilib/io/irc/irc_text.hpp b/src/include/jessilib/io/irc/irc_text.hpp index 2a77719..a68a90c 100644 --- a/src/include/jessilib/io/irc/irc_text.hpp +++ b/src/include/jessilib/io/irc/irc_text.hpp @@ -18,7 +18,7 @@ #pragma once -#include "io/message.hpp" +#include "jessilib/io/message.hpp" namespace jessilib { namespace io { @@ -45,19 +45,19 @@ static constexpr color s_irc_colors[] { #endif // JESSILIB_IRC_SIMPLE_COLORS }; -static constexpr std::string_view s_irc_color_codes[] { +static constexpr std::u8string_view s_irc_color_codes[] { // Basic 16 colors (0-15) - "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", + u8"00", u8"01", u8"02", u8"03", u8"04", u8"05", u8"06", u8"07", u8"08", u8"09", u8"10", u8"11", u8"12", u8"13", u8"14", u8"15", #ifndef JESSILIB_IRC_SIMPLE_COLORS // Extended colors (16-98, making a total of 99 color choices) - "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", - "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", - "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", - "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", - "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", - "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", - "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98" + u8"16", u8"17", u8"18", u8"19", u8"20", u8"21", u8"22", u8"23", u8"24", u8"25", u8"26", u8"27", + u8"28", u8"29", u8"30", u8"31", u8"32", u8"33", u8"34", u8"35", u8"36", u8"37", u8"38", u8"39", + u8"40", u8"41", u8"42", u8"43", u8"44", u8"45", u8"46", u8"47", u8"48", u8"49", u8"50", u8"51", + u8"52", u8"53", u8"54", u8"55", u8"56", u8"57", u8"58", u8"59", u8"60", u8"61", u8"62", u8"63", + u8"64", u8"65", u8"66", u8"67", u8"68", u8"69", u8"70", u8"71", u8"72", u8"73", u8"74", u8"75", + u8"76", u8"77", u8"78", u8"79", u8"80", u8"81", u8"82", u8"83", u8"84", u8"85", u8"86", u8"87", + u8"88", u8"89", u8"90", u8"91", u8"92", u8"93", u8"94", u8"95", u8"96", u8"97", u8"98" #endif // JESSILIB_IRC_SIMPLE_COLORS }; @@ -98,7 +98,7 @@ constexpr color normalize_color(color in_color) { return s_irc_colors[from_color(in_color)]; } -constexpr std::string_view color_to_code(color in_color) { +constexpr std::u8string_view color_to_code(color in_color) { return s_irc_color_codes[from_color(in_color)]; } @@ -112,7 +112,7 @@ static constexpr uint8_t COLOR_HEX{ 0x04 }; static constexpr uint8_t REVERSE{ 0x16 }; static constexpr uint8_t NORMAL{ 0x0F }; -text::property properties_to_toggle(text::property in_active_properties, text::property in_text_properties, uint8_t in_active_color, uint8_t in_text_color, uint8_t in_active_color_bg, uint8_t in_text_color_bg) { +inline text::property properties_to_toggle(text::property in_active_properties, text::property in_text_properties, uint8_t in_active_color, uint8_t in_text_color, uint8_t in_active_color_bg, uint8_t in_text_color_bg) { text::property_backing_t active_properties_backing = static_cast(in_active_properties); text::property_backing_t text_properties_backing = static_cast(in_text_properties); @@ -138,8 +138,8 @@ text::property properties_to_toggle(text::property in_active_properties, text::p } // namespace irc template<> -inline std::string text_to_string(const irc::text_wrapper& in_text) { - std::string result; +inline std::u8string text_to_string(const irc::text_wrapper& in_text) { + std::u8string result; result.reserve(in_text.string().size() + 8); // Prepend properties @@ -178,10 +178,10 @@ inline std::string text_to_string(const irc::text_wrapper& in } // namespace jessilib template<> -struct fmt::formatter : formatter { +struct fmt::formatter : formatter { template auto format(const jessilib::io::irc::text_wrapper& in_text, FormatContext& in_context) { // Pass result to base - return formatter::format(jessilib::io::text_to_string(in_text), in_context); + return formatter::format(jessilib::io::text_to_string(in_text), in_context); } }; diff --git a/src/include/jessilib/io/message.hpp b/src/include/jessilib/io/message.hpp index fbe9395..a295dae 100644 --- a/src/include/jessilib/io/message.hpp +++ b/src/include/jessilib/io/message.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "jessilib/unicode.hpp" #include "color.hpp" @@ -155,13 +156,13 @@ private: class formatted_message { public: template - formatted_message(std::string in_format, Args&& ... args) + formatted_message(std::u8string in_format, Args&& ... args) : m_format{ std::move(in_format) }, m_message{ std::forward(args)... } { // Empty ctor body } - const std::string& format() const { + const std::u8string& format() const { return m_format; } @@ -170,12 +171,12 @@ public: } private: - std::string m_format; + std::u8string m_format; std::vector m_message; }; template -std::string text_to_string(const WrapperT& in_text) { +std::u8string text_to_string(const WrapperT& in_text) { return in_text.string(); } @@ -209,18 +210,23 @@ std::string process_message(const jessilib::io::message& msg) { } template -std::string process_message(const jessilib::io::formatted_message& msg) { - using format_arg = fmt::format_args::format_arg; - std::vector args; +std::u8string process_message(const jessilib::io::formatted_message& msg) { + using FormatCharT = char8_t; + using format_args_type = fmt::basic_format_args>; + using format_arg_type = format_args_type::format_arg; + using format_context_type = fmt::buffer_context; + using string_view_type = fmt::v8::basic_string_view; // Populate args + std::vector args; for (auto& text : msg.get_message()) { - args.emplace_back(fmt::detail::make_arg(wrap_text(text))); + args.emplace_back(fmt::detail::make_arg(wrap_text(text))); } // Pass args into vformat - fmt::format_args text_args{ args.data(), static_cast(args.size()) }; - return fmt::vformat(msg.format(), text_args); + format_args_type text_args{ args.data(), static_cast(args.size()) }; + string_view_type fmt_view{ msg.format().data(), msg.format().size() }; + return fmt::vformat(fmt_view, text_args); } } // namespace io