From ccb652933ba2d050c9dd50809efd351ba04babec Mon Sep 17 00:00:00 2001 From: xieamoe <164259078+xieamoe@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:41:29 -0700 Subject: [PATCH] fmtlib replaced with std::format (#22) * fmtlib replaced with std::format * write join_with() * replace instances of print with println --------- Co-authored-by: Ren Tatsumoto --- src/anki_search.cpp | 50 ++++++++++++++++++++++---------------------- src/echo.cpp | 8 +++---- src/images.cpp | 12 +++++------ src/kana_conv.cpp | 2 +- src/main.cpp | 5 +++-- src/marisa_split.cpp | 24 ++++++++++----------- src/massif.cpp | 14 ++++++------- src/mecab_split.cpp | 23 ++++++++++---------- src/precompiled.h | 4 ++-- src/util.h | 32 ++++++++++++++++++++++++++++ xmake.lua | 8 +++---- 11 files changed, 108 insertions(+), 74 deletions(-) diff --git a/src/anki_search.cpp b/src/anki_search.cpp index 1aeda03..877b27f 100644 --- a/src/anki_search.cpp +++ b/src/anki_search.cpp @@ -167,10 +167,10 @@ auto make_find_cards_request_str(search_params const& params) -> std::string std::string query{ params.gd_word }; if (not params.field_name.empty()) { - query = fmt::format("\"{}:*{}*\"", params.field_name, query); + query = std::format("\"{}:*{}*\"", params.field_name, query); } if (not params.deck_name.empty()) { - query = fmt::format("\"deck:{}\" {}", params.deck_name, query); + query = std::format("\"deck:{}\" {}", params.deck_name, query); } request["params"]["query"] = query; @@ -261,7 +261,7 @@ auto get_note_tags(uint64_t const nid) -> std::string raise_if(not obj["error"].is_null(), "Error getting data from AnkiConnect."); std::string html; for (std::string const tag_name: obj["result"]) { - html += fmt::format(R"EOF({})EOF", tag_name, tag_name); + html += std::format(R"EOF({})EOF", tag_name, tag_name); } return html; } @@ -269,12 +269,12 @@ auto get_note_tags(uint64_t const nid) -> std::string void print_table_header(search_params const& params) { // Print the first row (header) that contains tags, starting with Card ID. - fmt::print(""); - fmt::print("Card ID"); - fmt::print("Deck name"); - for (auto const& field: params.show_fields) { fmt::print("{}", field); } - fmt::print("Tags"); - fmt::print("\n"); + gd::print(""); + gd::print("Card ID"); + gd::print("Deck name"); + for (auto const& field: params.show_fields) { gd::print("{}", field); } + gd::print("Tags"); + gd::println(""); } auto card_json_to_obj(nlohmann::json const& card_json) -> card_info @@ -303,38 +303,38 @@ auto gd_format(std::string const& field_content, std::string const& media_dir_pa static std::regex const img_re{ "(]*src=\")" }; static std::regex const any_undesirables{ R"EOF(\[sound:|\]|<[^<>]+>|["'.,!?]+|…|。|、|!|?| |・|~|\(|\))EOF" }; auto const link_content = strtrim(std::regex_replace(field_content, any_undesirables, " ")); - auto const link_text = std::regex_replace(field_content, img_re, fmt::format("$1file://{}/", media_dir_path)); - return link_content.empty() ? link_text : fmt::format("{}", link_content, link_text); + auto const link_text = std::regex_replace(field_content, img_re, std::format("$1file://{}/", media_dir_path)); + return link_content.empty() ? link_text : std::format("{}", link_content, link_text); } void print_cards_info(search_params const& params) { auto const cids = find_cids(params); if (cids.empty()) { - return fmt::print("No cards found.\n"); + return gd::println("No cards found."); } auto const media_dir_path = fetch_media_dir_path(); - fmt::print("
"); - fmt::print("\n"); + gd::print("
"); + gd::println("
"); print_table_header(params); for (auto const& card: get_cids_info(cids) | std::views::transform(card_json_to_obj)) { - fmt::print("", determine_card_class(card.queue, card.type)); - fmt::print("", card.id, card.id); - fmt::print("", card.deck_name); + gd::print("", determine_card_class(card.queue, card.type)); + gd::print("", card.id, card.id); + gd::print("", card.deck_name); for (auto const& field_name: params.show_fields) { - fmt::print( + gd::print( "", (card.fields.contains(field_name) and not card.fields.at(field_name).empty() ? gd_format(card.fields.at(field_name), media_dir_path) : "Not present") ); } - fmt::print("\n", get_note_tags(card.nid)); - fmt::print("\n"); + gd::println("", get_note_tags(card.nid)); + gd::println(""); } - fmt::print("
{}{}
{}{}{}{}
{}
"); - fmt::print("
\n"); // gd-table-wrap - fmt::print("{}\n", css_style); + gd::print(""); + gd::println(""); // gd-table-wrap + gd::println("{}", css_style); } void search_anki_cards(std::span const args) @@ -342,8 +342,8 @@ void search_anki_cards(std::span const args) try { print_cards_info(fill_args(args)); } catch (gd::help_requested const& ex) { - fmt::print(help_text); + gd::print(help_text); } catch (gd::runtime_error const& ex) { - fmt::print("{}\n", ex.what()); + gd::println("{}", ex.what()); } } diff --git a/src/echo.cpp b/src/echo.cpp index 230e235..b47ee47 100644 --- a/src/echo.cpp +++ b/src/echo.cpp @@ -69,13 +69,13 @@ void print_css(stroke_order_params const& params) }} )EOF"; - fmt::print(css, this_pid, params.font_size, params.font_family); + gd::print(css, this_pid, params.font_size, params.font_family); } void print_with_stroke_order(stroke_order_params const& params) { if (params.gd_word.length() <= params.max_len) { - fmt::print("
{}
\n", this_pid, params.gd_word); + gd::println("
{}
", this_pid, params.gd_word); print_css(params); } } @@ -85,8 +85,8 @@ void stroke_order(std::span const args) try { print_with_stroke_order(fill_args(args)); } catch (gd::help_requested const& ex) { - fmt::print(help_text); + gd::print(help_text); } catch (gd::runtime_error const& ex) { - fmt::print("{}\n", ex.what()); + gd::println("{}", ex.what()); } } diff --git a/src/images.cpp b/src/images.cpp index 869c9f5..1641a8f 100644 --- a/src/images.cpp +++ b/src/images.cpp @@ -84,12 +84,12 @@ void fetch_images(images_params const& params) static std::regex const img_re("]*class=\"mimg[^<>]*>"); auto images_begin = std::sregex_iterator(std::begin(r.text), std::end(r.text), img_re); auto images_end = std::sregex_iterator(); - fmt::print("
\n"); + gd::println("
"); for (auto const& match: std::ranges::subrange(images_begin, images_end) | std::views::take(5)) { - fmt::print("{}\n", match.str()); + gd::println("{}", match.str()); } - fmt::print("
\n"); - fmt::print("{}\n", css_style); + gd::println("
"); + gd::println("{}", css_style); } void images(std::span const args) @@ -97,8 +97,8 @@ void images(std::span const args) try { fetch_images(fill_args(args)); } catch (gd::help_requested const& ex) { - fmt::print(help_text); + gd::print(help_text); } catch (gd::runtime_error const& ex) { - fmt::print("{}\n", ex.what()); + gd::println("{}", ex.what()); } } diff --git a/src/kana_conv.cpp b/src/kana_conv.cpp index f35b329..5daf446 100644 --- a/src/kana_conv.cpp +++ b/src/kana_conv.cpp @@ -39,7 +39,7 @@ auto unicode_char_byte_len(char const& ch) -> CharByteLen // Other Unicode return CharByteLen::FOUR; } - throw gd::runtime_error{ fmt::format("Can't recognize byte: '{:x}'.", ch) }; + throw gd::runtime_error{ std::format("Can't recognize byte: '{:x}'.", ch) }; } auto create_map(std::string_view from, std::string_view to) -> KanaConvMap diff --git a/src/main.cpp b/src/main.cpp index aa8502e..aa98fd9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "massif.h" #include "mecab_split.h" #include "precompiled.h" +#include "util.h" static constexpr std::string_view help_text = R"EOF(usage: {} ACTION [OPTIONS] A set of helpful programs to enhance GoldenDict for immersion learning. @@ -47,12 +48,12 @@ gd-ankisearch --deck-name Mining %GDWORD% auto get_help_str(std::string_view program_name) -> std::string { - return fmt::format(help_text, program_name); + return std::format(help_text, program_name); } auto print_help(std::string_view const program_name) -> void { - fmt::print("{}", get_help_str(program_name)); + gd::print("{}", get_help_str(program_name)); } auto base_name(auto file_path) -> std::string diff --git a/src/marisa_split.cpp b/src/marisa_split.cpp index be3c4e2..8cf8ad8 100644 --- a/src/marisa_split.cpp +++ b/src/marisa_split.cpp @@ -181,10 +181,10 @@ void lookup_words(marisa_params params) marisa::Agent agent; std::ifstream file{ params.path_to_dic }; - raise_if(not file.good(), fmt::format(R"(Error. The dictionary file "{}" does not exist.)", params.path_to_dic)); + raise_if(not file.good(), std::format(R"(Error. The dictionary file "{}" does not exist.)", params.path_to_dic)); trie.load(params.path_to_dic.c_str()); - fmt::println(R"(
)"); + gd::println(R"(
)"); std::ptrdiff_t pos_in_gd_word{ 0 }; std::vector alternatives{}; alternatives.reserve(20); @@ -205,7 +205,7 @@ void lookup_words(marisa_params params) pos_in_gd_word -= static_cast(uni_char.length()); } - fmt::print( + gd::print( R"({})", (pos_in_gd_word > 0 ? "gd-headword" : "gd-word"), bword, @@ -215,23 +215,23 @@ void lookup_words(marisa_params params) } // Show available entries for other substrings. - fmt::println(R"(
)"); + gd::println(R"(
)"); for (auto const& group: alternatives | std::views::filter(&JpSet::size)) { - fmt::println("
    "); + gd::println("
      "); for (auto const& word: group) { - fmt::println( + gd::println( R"(
    • {}
    • )", (word == params.gd_word ? "gd-headword" : ""), word, word ); } - fmt::println("
    "); // close ul + gd::println("
"); // close ul } - fmt::println("
"); // close div.alternatives + gd::println("
"); // close div.alternatives - fmt::println("
"); // close div.gd-marisa - fmt::println("{}", css_style); + gd::println("
"); // close div.gd-marisa + gd::println("{}", css_style); } void marisa_split(std::span const args) @@ -239,8 +239,8 @@ void marisa_split(std::span const args) try { lookup_words(fill_args(args)); } catch (gd::help_requested const& ex) { - fmt::println(help_text); + gd::println(help_text); } catch (gd::runtime_error const& ex) { - fmt::println("{}", ex.what()); + gd::println("{}", ex.what()); } } diff --git a/src/massif.cpp b/src/massif.cpp index 5e98cba..344b9ab 100644 --- a/src/massif.cpp +++ b/src/massif.cpp @@ -74,12 +74,12 @@ struct massif_params void fetch_massif_examples(massif_params const& params) { cpr::Response const r = cpr::Get( - cpr::Url{ fmt::format("https://massif.la/ja/search?q={}", params.gd_word) }, + cpr::Url{ std::format("https://massif.la/ja/search?q={}", params.gd_word) }, cpr::Timeout{ params.max_time }, cpr::VerifySsl{ false } ); raise_if(r.status_code != 200, "Couldn't connect to Massif."); - fmt::print("
    \n"); + gd::println("
      "); for (auto const& line: r.text // | std::views::split('\n') // @@ -88,10 +88,10 @@ void fetch_massif_examples(massif_params const& params) return not str_view.contains("
    • "); }) | std::views::take_while([](auto const str_view) { return not str_view.contains("
    "); })) { - fmt::print("{}\n", line); + gd::println("{}", line); } - fmt::print("
\n"); - fmt::print("{}\n", css_style); + gd::println(""); + gd::println("{}", css_style); } void massif(std::span const args) @@ -99,8 +99,8 @@ void massif(std::span const args) try { fetch_massif_examples(fill_args(args)); } catch (gd::help_requested const& ex) { - fmt::print(help_text); + gd::print(help_text); } catch (gd::runtime_error const& ex) { - fmt::print("{}\n", ex.what()); + gd::println("{}", ex.what()); } } diff --git a/src/mecab_split.cpp b/src/mecab_split.cpp index 8d9b6f9..a7651b5 100644 --- a/src/mecab_split.cpp +++ b/src/mecab_split.cpp @@ -121,7 +121,7 @@ struct mecab_params } else if (key == "--user-dict") { user_dict = value; } else { - throw gd::runtime_error(std::string(fmt::format("Unknown argument name: {}", key))); + throw gd::runtime_error(std::string(std::format("Unknown argument name: {}", key))); } } }; @@ -174,16 +174,17 @@ void lookup_words(mecab_params params) } std::string result = tagger->parse(params.gd_sentence.c_str()); - result = replace_all(result, fmt::format(">{}<", params.gd_word), fmt::format(">{}<", params.gd_word)); - fmt::println(R"EOF(
{}
)EOF", result); - fmt::println("{}", css_style); + result = replace_all(result, std::format(">{}<", params.gd_word), std::format(">{}<", params.gd_word)); + gd::println(R"EOF(
{}
)EOF", result); + gd::println("{}", css_style); // debug info, not shown in GD. - fmt::println(R"EOF(
)EOF"); - fmt::println("dicdir: {}", params.dic_dir.string()); - fmt::println("userdic: {}", params.user_dict.string()); - fmt::println("mecab args: {}", args); - fmt::println(R"EOF(
)EOF"); + gd::println(R"EOF(
)EOF"); + gd::println("dicdir: {}", params.dic_dir.string()); + gd::println("userdic: {}", params.user_dict.string()); + + gd::println("mecab args: [{}]", join_with(args, ", ")); + gd::println(R"EOF(
)EOF"); } void mecab_split(std::span const args) @@ -191,8 +192,8 @@ void mecab_split(std::span const args) try { lookup_words(fill_args(args)); } catch (gd::help_requested const& ex) { - fmt::println(help_text); + gd::println(help_text); } catch (gd::runtime_error const& ex) { - fmt::println("{}", ex.what()); + gd::println("{}", ex.what()); } } diff --git a/src/precompiled.h b/src/precompiled.h index ea71084..2be33f8 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -27,8 +28,7 @@ // Other #include -#include -#include + #include #include #include diff --git a/src/util.h b/src/util.h index f10417b..d9c19c5 100644 --- a/src/util.h +++ b/src/util.h @@ -14,6 +14,25 @@ class runtime_error : public std::runtime_error public: runtime_error(std::string_view const what) : std::runtime_error(std::string{ what }) {} }; + +template +void print(std::string_view format, Args const&... args) +{ + std::string result; + result = std::vformat(format, std::make_format_args(args...)); + std::ios::sync_with_stdio(false); + std::cout << result; +} + +template +void println(std::string_view format, Args const&... args) +{ + std::string result; + result = std::vformat(format, std::make_format_args(args...)); + std::ios::sync_with_stdio(false); + std::cout << result << '\n'; +} + } // namespace gd inline void raise_if(bool expr, std::string_view const message = "Invalid argument.") @@ -85,3 +104,16 @@ inline auto user_home() -> std::filesystem::path { return std::getenv("HOME"); } + +template +auto join_with(std::vector const& seq, std::string_view const sep) -> std::string +{ + std::stringstream ss; + for (size_t idx = 0; idx != seq.size(); ++idx) { + ss << seq.at(idx); + if (idx != seq.size() - 1) { + ss << sep; + } + } + return ss.str(); +} diff --git a/xmake.lua b/xmake.lua index 3d27593..fd631bb 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,6 +1,6 @@ local main_bin_name = "gd-tools" set_license("GPL-3.0") -set_languages("c++2b") +set_languages("c++23") set_toolchains("gcc") set_warnings("allextra", "error") @@ -13,7 +13,7 @@ add_rules("mode.debug", "mode.release") -- https://clangd.llvm.org/installation#project-setup add_rules("plugin.compile_commands.autoupdate", {outputdir = "build"}) -add_requires("mecab", "cpr >= 1.10.5", "fmt >= 10.2", "nlohmann_json", "marisa", "rdricpp") +add_requires("cpr >= 1.10.5", "nlohmann_json", "marisa", "rdricpp", "mecab") if is_mode("debug") then add_defines("DEBUG") @@ -60,7 +60,7 @@ end -- Main target target(main_bin_name) set_kind("binary") - add_packages("cpr", "fmt", "nlohmann_json", "marisa", "rdricpp", "mecab") + add_packages("cpr","nlohmann_json", "marisa", "rdricpp", "mecab") add_files("src/*.cpp") add_cxflags("-D_GLIBCXX_ASSERTIONS") set_pcxxheader("src/precompiled.h") @@ -130,7 +130,7 @@ if has_config("tests") then -- Tests target target("tests") set_kind("binary") - add_packages("cpr", "fmt", "nlohmann_json", "marisa", "catch2", "rdricpp", "mecab") + add_packages("cpr","nlohmann_json", "marisa", "catch2", "rdricpp", "mecab") add_files("src/*.cpp", "tests/*.cpp") remove_files("src/main.cpp") set_pcxxheader("src/precompiled.h")