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")