mirror of https://github.com/djcb/mu.git
fmt: more update to use new fmt-based APIs
This commit is contained in:
parent
91c5a9bac5
commit
82235b9d49
|
@ -686,32 +686,3 @@ Mu::fputs_encoded (const std::string& str, FILE *stream)
|
||||||
|
|
||||||
return (rv == EOF) ? false: true;
|
return (rv == EOF) ? false: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((format(printf, 2, 0)))
|
|
||||||
static bool
|
|
||||||
print_args (FILE *stream, const char *frm, va_list args)
|
|
||||||
{
|
|
||||||
char *str;
|
|
||||||
gboolean rv;
|
|
||||||
|
|
||||||
str = g_strdup_vprintf (frm, args);
|
|
||||||
rv = fputs_encoded (str, stream);
|
|
||||||
g_free (str);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Mu::print_encoded (const char *frm, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
gboolean rv;
|
|
||||||
|
|
||||||
g_return_val_if_fail (frm, false);
|
|
||||||
|
|
||||||
va_start (args, frm);
|
|
||||||
rv = print_args (stdout, frm, args);
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** Copyright (C) 2020-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
** Copyright (C) 2020-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public License
|
** modify it under the terms of the GNU Lesser General Public License
|
||||||
|
@ -107,6 +107,7 @@ inline void mu_printerrln(fmt::format_string<T...> frm, T&&... args) noexcept {
|
||||||
fmt::println(stderr, frm, std::forward<T>(args)...);
|
fmt::println(stderr, frm, std::forward<T>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fprmatting
|
* Fprmatting
|
||||||
*/
|
*/
|
||||||
|
@ -197,22 +198,27 @@ static inline std::string join(const std::vector<std::string>& svec, char sepa)
|
||||||
bool fputs_encoded (const std::string& str, FILE *stream);
|
bool fputs_encoded (const std::string& str, FILE *stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* print a formatted string (assumed to be in utf8-format) to stdout,
|
* print a fmt-style formatted string (assumed to be in utf8-format) to stdout,
|
||||||
* converted to the current locale
|
* converted to the current locale
|
||||||
*
|
*
|
||||||
* @param a standard printf() format string, followed by a parameter list
|
* @param a standard fmt-style format string, followed by a parameter list
|
||||||
*
|
*
|
||||||
* @return true if printing worked, false otherwise
|
* @return true if printing worked, false otherwise
|
||||||
*/
|
*/
|
||||||
bool print_encoded (const char *frm, ...) G_GNUC_PRINTF(1,2);
|
template<typename...T>
|
||||||
|
static inline bool mu_print_encoded(fmt::format_string<T...> frm, T&&... args) noexcept {
|
||||||
|
return fputs_encoded(fmt::format(frm, std::forward<T>(args)...),
|
||||||
|
::stdout);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a date string to the corresponding time_t
|
* Parse a date string to the corresponding time_t
|
||||||
* *
|
* *
|
||||||
* @param date the date expressed a YYYYMMDDHHMMSS or any n... of the first
|
* @param date the date expressed a YYYYMMDDHHMMSS or any n... of the first
|
||||||
* characters, using the local timezone.
|
* characters, using the local timezone. Non-digits are ignored,
|
||||||
* @param first whether to fill out incomplete dates to the start or the end;
|
* so 2018-05-05 is equivalent to 20180505.
|
||||||
* ie. either 1972 -> 197201010000 or 1972 -> 197212312359
|
* @param first whether to fill out incomplete dates to the start (@true) or the
|
||||||
|
* end (@false); ie. either 1972 -> 197201010000 or 1972 -> 197212312359
|
||||||
*
|
*
|
||||||
* @return the corresponding time_t or Nothing if parsing failed.
|
* @return the corresponding time_t or Nothing if parsing failed.
|
||||||
*/
|
*/
|
||||||
|
@ -302,17 +308,15 @@ to_us(Duration d)
|
||||||
struct StopWatch {
|
struct StopWatch {
|
||||||
using Clock = std::chrono::steady_clock;
|
using Clock = std::chrono::steady_clock;
|
||||||
StopWatch(const std::string name) : start_{Clock::now()}, name_{name} {}
|
StopWatch(const std::string name) : start_{Clock::now()}, name_{name} {}
|
||||||
~StopWatch()
|
~StopWatch() {
|
||||||
{
|
|
||||||
const auto us{static_cast<double>(to_us(Clock::now() - start_))};
|
const auto us{static_cast<double>(to_us(Clock::now() - start_))};
|
||||||
if (us > 2000000)
|
if (us > 2000000)
|
||||||
g_debug("sw: %s: finished after %0.1f s", name_.c_str(), us / 1000000);
|
mu_debug("sw: {}: finished after {:.1f} s", name_, us / 1000000);
|
||||||
else if (us > 2000)
|
else if (us > 2000)
|
||||||
g_debug("sw: %s: finished after %0.1f ms", name_.c_str(), us / 1000);
|
mu_debug("sw: {}: finished after {:.1f} ms", name_, us / 1000);
|
||||||
else
|
else
|
||||||
g_debug("sw: %s: finished after %g us", name_.c_str(), us);
|
mu_debug("sw: {}: finished after {} us", name_, us);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Clock::time_point start_;
|
Clock::time_point start_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
@ -383,9 +387,9 @@ to_string_gchar(gchar*&& str)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lexicals Number are lexicographically sortable string representations
|
* Lexnums are lexicographically sortable string representations of non-negative
|
||||||
* of numbers. Start with 'g' + length of number in hex, followed by
|
* integers. Start with 'f' + length of hex-representation number, followed by
|
||||||
* the ascii for the hex represntation. So,
|
* the hex representation itself. So,
|
||||||
*
|
*
|
||||||
* 0 -> 'g0'
|
* 0 -> 'g0'
|
||||||
* 1 -> 'g1'
|
* 1 -> 'g1'
|
||||||
|
@ -476,54 +480,6 @@ void seq_for_each(const Sequence& seq, UnaryOp op) {
|
||||||
std::for_each(seq.cbegin(), seq.cend(), op);
|
std::for_each(seq.cbegin(), seq.cend(), op);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* array of associated pair elements -- like an alist
|
|
||||||
* but based on std::array and thus can be constexpr
|
|
||||||
*/
|
|
||||||
template<typename T1, typename T2, std::size_t N>
|
|
||||||
using AssocPairs = std::array<std::pair<T1, T2>, N>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the first value of the pair where the second element is @param s.
|
|
||||||
*
|
|
||||||
* @param p AssocPairs
|
|
||||||
* @param s some second pair value
|
|
||||||
*
|
|
||||||
* @return the matching first pair value, or Nothing if not found.
|
|
||||||
*/
|
|
||||||
template<typename P>
|
|
||||||
constexpr Option<typename P::value_type::first_type>
|
|
||||||
to_first(const P& p, typename P::value_type::second_type s)
|
|
||||||
{
|
|
||||||
for (const auto& item: p)
|
|
||||||
if (item.second == s)
|
|
||||||
return item.first;
|
|
||||||
return Nothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the second value of the pair where the first element is @param f.
|
|
||||||
*
|
|
||||||
* @param p AssocPairs
|
|
||||||
* @param f some first pair value
|
|
||||||
*
|
|
||||||
* @return the matching second pair value, or Nothing if not found.
|
|
||||||
*/
|
|
||||||
template<typename P>
|
|
||||||
constexpr Option<typename P::value_type::second_type>
|
|
||||||
to_second(const P& p, typename P::value_type::first_type f)
|
|
||||||
{
|
|
||||||
for (const auto& item: p)
|
|
||||||
if (item.first == f)
|
|
||||||
return item.second;
|
|
||||||
return Nothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert string view in something printable with %.*s
|
|
||||||
*/
|
|
||||||
#define STR_V(sv__) static_cast<int>((sv__).size()), (sv__).data()
|
|
||||||
|
|
||||||
struct MaybeAnsi {
|
struct MaybeAnsi {
|
||||||
explicit MaybeAnsi(bool use_color) : color_{use_color} {}
|
explicit MaybeAnsi(bool use_color) : color_{use_color} {}
|
||||||
|
|
||||||
|
@ -555,7 +511,8 @@ struct MaybeAnsi {
|
||||||
private:
|
private:
|
||||||
std::string ansi(Color c, bool fg = true) const
|
std::string ansi(Color c, bool fg = true) const
|
||||||
{
|
{
|
||||||
return color_ ? format("\x1b[%dm", static_cast<int>(c) + (fg ? 0 : 10)) : "";
|
return color_ ? mu_format("\x1b[{}m",
|
||||||
|
static_cast<int>(c) + (fg ? 0 : 10)) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool color_;
|
const bool color_;
|
||||||
|
@ -574,12 +531,10 @@ private:
|
||||||
#define MU_TO_NUM(ET, ELM) std::underlying_type_t<ET>(ELM)
|
#define MU_TO_NUM(ET, ELM) std::underlying_type_t<ET>(ELM)
|
||||||
#define MU_TO_ENUM(ET, NUM) static_cast<ET>(NUM)
|
#define MU_TO_ENUM(ET, NUM) static_cast<ET>(NUM)
|
||||||
#define MU_ENABLE_BITOPS(ET) \
|
#define MU_ENABLE_BITOPS(ET) \
|
||||||
constexpr ET operator&(ET e1, ET e2) \
|
constexpr ET operator&(ET e1, ET e2) { \
|
||||||
{ \
|
|
||||||
return MU_TO_ENUM(ET, MU_TO_NUM(ET, e1) & MU_TO_NUM(ET, e2)); \
|
return MU_TO_ENUM(ET, MU_TO_NUM(ET, e1) & MU_TO_NUM(ET, e2)); \
|
||||||
} \
|
} \
|
||||||
constexpr ET operator|(ET e1, ET e2) \
|
constexpr ET operator|(ET e1, ET e2) { \
|
||||||
{ \
|
|
||||||
return MU_TO_ENUM(ET, MU_TO_NUM(ET, e1) | MU_TO_NUM(ET, e2)); \
|
return MU_TO_ENUM(ET, MU_TO_NUM(ET, e1) | MU_TO_NUM(ET, e2)); \
|
||||||
} \
|
} \
|
||||||
constexpr ET operator~(ET e) { return MU_TO_ENUM(ET, ~(MU_TO_NUM(ET, e))); } \
|
constexpr ET operator~(ET e) { return MU_TO_ENUM(ET, ~(MU_TO_NUM(ET, e))); } \
|
||||||
|
|
|
@ -282,35 +282,6 @@ test_locale_workaround()
|
||||||
g_assert_true(locale_workaround());
|
g_assert_true(locale_workaround());
|
||||||
}
|
}
|
||||||
|
|
||||||
enum struct TestEnum { A, B, C };
|
|
||||||
constexpr AssocPairs<TestEnum, std::string_view, 3>
|
|
||||||
test_epairs = {{
|
|
||||||
{TestEnum::A, "a"},
|
|
||||||
{TestEnum::B, "b"},
|
|
||||||
{TestEnum::C, "c"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
static constexpr Option<std::string_view>
|
|
||||||
to_name(TestEnum te)
|
|
||||||
{
|
|
||||||
return to_second(test_epairs, te);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr Option<TestEnum>
|
|
||||||
to_type(std::string_view name)
|
|
||||||
{
|
|
||||||
return to_first(test_epairs, name);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_enum_pairs(void)
|
|
||||||
{
|
|
||||||
assert_equal(to_name(TestEnum::A).value(), "a");
|
|
||||||
g_assert_true(to_type("c").value() == TestEnum::C);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_summarize(void)
|
test_summarize(void)
|
||||||
|
@ -353,7 +324,6 @@ main(int argc, char* argv[])
|
||||||
g_test_add_func("/utils/define-bitmap", test_define_bitmap);
|
g_test_add_func("/utils/define-bitmap", test_define_bitmap);
|
||||||
g_test_add_func("/utils/to-from-lexnum", test_to_from_lexnum);
|
g_test_add_func("/utils/to-from-lexnum", test_to_from_lexnum);
|
||||||
g_test_add_func("/utils/locale-workaround", test_locale_workaround);
|
g_test_add_func("/utils/locale-workaround", test_locale_workaround);
|
||||||
g_test_add_func("/utils/enum-pairs", test_enum_pairs);
|
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,14 +112,10 @@ output_plain(ItemType itype, OptContact contact, const Options& opts)
|
||||||
const auto col2{opts.nocolor ? "" : MU_COLOR_GREEN};
|
const auto col2{opts.nocolor ? "" : MU_COLOR_GREEN};
|
||||||
const auto coldef{opts.nocolor ? "" : MU_COLOR_DEFAULT};
|
const auto coldef{opts.nocolor ? "" : MU_COLOR_DEFAULT};
|
||||||
|
|
||||||
print_encoded("%s%s%s%s%s%s%s\n",
|
mu_print_encoded("{}{}{}{}{}{}{}\n",
|
||||||
col1,
|
col1, contact->name, coldef,
|
||||||
contact->name.c_str(),
|
contact->name.empty() ? "" : " ",
|
||||||
coldef,
|
col2, contact->email, coldef);
|
||||||
contact->name.empty() ? "" : " ",
|
|
||||||
col2,
|
|
||||||
contact->email.c_str(),
|
|
||||||
coldef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -129,8 +125,8 @@ output_mutt_alias(ItemType itype, OptContact contact, const Options& opts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto nick{guess_nick(*contact)};
|
const auto nick{guess_nick(*contact)};
|
||||||
print_encoded("alias %s %s <%s>\n", nick.c_str(),
|
mu_print_encoded("alias {} {} <{}>\n", nick, contact->name, contact->email);
|
||||||
contact->name.c_str(), contact->email.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -139,12 +135,8 @@ output_mutt_address_book(ItemType itype, OptContact contact, const Options& opts
|
||||||
if (itype == ItemType::Header)
|
if (itype == ItemType::Header)
|
||||||
mu_print ("Matching addresses in the mu database:\n");
|
mu_print ("Matching addresses in the mu database:\n");
|
||||||
|
|
||||||
if (!contact)
|
if (contact)
|
||||||
return;
|
mu_print_encoded("{}\t{}\t\n", contact->email, contact->name);
|
||||||
|
|
||||||
print_encoded("%s\t%s\t\n",
|
|
||||||
contact->email.c_str(),
|
|
||||||
contact->name.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -155,10 +147,8 @@ output_wanderlust(ItemType itype, OptContact contact, const Options& opts)
|
||||||
|
|
||||||
auto nick=guess_nick(*contact);
|
auto nick=guess_nick(*contact);
|
||||||
|
|
||||||
print_encoded("%s \"%s\" \"%s\"\n",
|
mu_print_encoded("{} \"{}\" \"{}\"\n", contact->email, nick, contact->name);
|
||||||
contact->email.c_str(),
|
|
||||||
nick.c_str(),
|
|
||||||
contact->name.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -167,9 +157,8 @@ output_org_contact(ItemType itype, OptContact contact, const Options& opts)
|
||||||
if (!contact || contact->name.empty())
|
if (!contact || contact->name.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
print_encoded("* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n",
|
mu_print_encoded("* {}\n:PROPERTIES:\n:EMAIL: {}\n:END:\n\n",
|
||||||
contact->name.c_str(),
|
contact->name, contact->email);
|
||||||
contact->email.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -196,9 +185,9 @@ output_csv(ItemType itype, OptContact contact, const Options& opts)
|
||||||
if (!contact)
|
if (!contact)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
print_encoded("%s,%s\n",
|
mu_print_encoded("{},{}\n",
|
||||||
contact->name.empty() ? "" : Mu::quote(contact->name).c_str(),
|
contact->name.empty() ? "" : Mu::quote(contact->name),
|
||||||
Mu::quote(contact->email).c_str());
|
Mu::quote(contact->email));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -211,22 +200,22 @@ output_json(ItemType itype, OptContact contact, const Options& opts)
|
||||||
mu_println (" {{");
|
mu_println (" {{");
|
||||||
|
|
||||||
const std::string name = contact->name.empty() ? "null" : Mu::quote(contact->name);
|
const std::string name = contact->name.empty() ? "null" : Mu::quote(contact->name);
|
||||||
print_encoded(
|
mu_print_encoded(
|
||||||
" \"email\" : \"%s\",\n"
|
" \"email\" : \"{}\",\n"
|
||||||
" \"name\" : %s,\n"
|
" \"name\" : {},\n"
|
||||||
" \"display\" : %s,\n"
|
" \"display\" : {},\n"
|
||||||
" \"last-seen\" : %" PRId64 ",\n"
|
" \"last-seen\" : {},\n"
|
||||||
" \"last-seen-iso\" : \"%s\",\n"
|
" \"last-seen-iso\" : \"{}\",\n"
|
||||||
" \"personal\" : %s,\n"
|
" \"personal\" : {},\n"
|
||||||
" \"frequency\" : %zu\n",
|
" \"frequency\" : {}\n",
|
||||||
contact->email.c_str(),
|
contact->email,
|
||||||
name.c_str(),
|
name,
|
||||||
Mu::quote(contact->display_name()).c_str(),
|
Mu::quote(contact->display_name()),
|
||||||
contact->message_date,
|
contact->message_date,
|
||||||
time_to_string("%FT%TZ", contact->message_date, true/*utc*/).c_str(),
|
time_to_string("%FT%TZ", contact->message_date, true/*utc*/),
|
||||||
contact->personal ? "true" : "false",
|
contact->personal ? "true" : "false",
|
||||||
contact->frequency);
|
contact->frequency);
|
||||||
mu_print (" }}");
|
mu_print(" }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itype == ItemType::Footer)
|
if (itype == ItemType::Footer)
|
||||||
|
|
|
@ -117,8 +117,7 @@ show_part(const MessagePart& part, size_t index, bool color)
|
||||||
|
|
||||||
/* /\* disposition *\/ */
|
/* /\* disposition *\/ */
|
||||||
color_maybe(MU_COLOR_MAGENTA);
|
color_maybe(MU_COLOR_MAGENTA);
|
||||||
print_encoded(" [%s]", part.is_attachment() ?
|
mu_print_encoded(" [{}]", part.is_attachment() ? "attachment" : "inline");
|
||||||
"attachment" : "inline");
|
|
||||||
/* size */
|
/* size */
|
||||||
if (part.size() > 0) {
|
if (part.size() > 0) {
|
||||||
color_maybe(MU_COLOR_CYAN);
|
color_maybe(MU_COLOR_CYAN);
|
||||||
|
|
|
@ -98,13 +98,6 @@ topic_fields(const Options& opts)
|
||||||
fields.add_row({"field-name", "alias", "short", "search",
|
fields.add_row({"field-name", "alias", "short", "search",
|
||||||
"value", "sexp", "example query", "description"});
|
"value", "sexp", "example query", "description"});
|
||||||
|
|
||||||
auto disp= [&](std::string_view sv)->std::string {
|
|
||||||
if (sv.empty())
|
|
||||||
return "";
|
|
||||||
else
|
|
||||||
return format("%.*s", STR_V(sv));
|
|
||||||
};
|
|
||||||
|
|
||||||
auto searchable=[&](const Field& field)->std::string {
|
auto searchable=[&](const Field& field)->std::string {
|
||||||
if (field.is_boolean_term())
|
if (field.is_boolean_term())
|
||||||
return "boolean";
|
return "boolean";
|
||||||
|
@ -130,8 +123,8 @@ topic_fields(const Options& opts)
|
||||||
searchable(field),
|
searchable(field),
|
||||||
field.is_value() ? "yes" : "no",
|
field.is_value() ? "yes" : "no",
|
||||||
field.include_in_sexp() ? "yes" : "no",
|
field.include_in_sexp() ? "yes" : "no",
|
||||||
disp(field.example_query),
|
field.example_query,
|
||||||
disp(field.description)});
|
field.description});
|
||||||
++row;
|
++row;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ body_or_summary(const Message& message, const Options& opts)
|
||||||
const auto summ{summarize(body->c_str(), *opts.view.summary_len)};
|
const auto summ{summarize(body->c_str(), *opts.view.summary_len)};
|
||||||
print_field("Summary", summ, color);
|
print_field("Summary", summ, color);
|
||||||
} else {
|
} else {
|
||||||
print_encoded("%s", body->c_str());
|
mu_print_encoded("{}", *body);
|
||||||
if (!g_str_has_suffix(body->c_str(), "\n"))
|
if (!g_str_has_suffix(body->c_str(), "\n"))
|
||||||
mu_println("");
|
mu_println("");
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,53 @@ using namespace Mu;
|
||||||
* helpers
|
* helpers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* array of associated pair elements -- like an alist
|
||||||
|
* but based on std::array and thus can be constexpr
|
||||||
|
*/
|
||||||
|
template<typename T1, typename T2, std::size_t N>
|
||||||
|
using AssocPairs = std::array<std::pair<T1, T2>, N>;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first value of the pair where the second element is @param s.
|
||||||
|
*
|
||||||
|
* @param p AssocPairs
|
||||||
|
* @param s some second pair value
|
||||||
|
*
|
||||||
|
* @return the matching first pair value, or Nothing if not found.
|
||||||
|
*/
|
||||||
|
template<typename P>
|
||||||
|
constexpr Option<typename P::value_type::first_type>
|
||||||
|
to_first(const P& p, typename P::value_type::second_type s)
|
||||||
|
{
|
||||||
|
for (const auto& item: p)
|
||||||
|
if (item.second == s)
|
||||||
|
return item.first;
|
||||||
|
return Nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the second value of the pair where the first element is @param f.
|
||||||
|
*
|
||||||
|
* @param p AssocPairs
|
||||||
|
* @param f some first pair value
|
||||||
|
*
|
||||||
|
* @return the matching second pair value, or Nothing if not found.
|
||||||
|
*/
|
||||||
|
template<typename P>
|
||||||
|
constexpr Option<typename P::value_type::second_type>
|
||||||
|
to_second(const P& p, typename P::value_type::first_type f)
|
||||||
|
{
|
||||||
|
for (const auto& item: p)
|
||||||
|
if (item.first == f)
|
||||||
|
return item.second;
|
||||||
|
return Nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options-specific array-bases type that maps some enum to a <name, description> pair
|
* Options-specific array-bases type that maps some enum to a <name, description> pair
|
||||||
*/
|
*/
|
||||||
|
@ -316,7 +363,7 @@ sub_find(CLI::App& sub, Options& opts)
|
||||||
smap.emplace(std::string(1, field.shortcut), field.id);
|
smap.emplace(std::string(1, field.shortcut), field.id);
|
||||||
if (!sopts.empty())
|
if (!sopts.empty())
|
||||||
sopts += ", ";
|
sopts += ", ";
|
||||||
sopts += format("%.*s|%c", STR_V(field.name), field.shortcut);
|
sopts += mu_format("{}|{}", field.name, field.shortcut);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sub.add_option("--sortfield,-s", opts.find.sortfield,
|
sub.add_option("--sortfield,-s", opts.find.sortfield,
|
||||||
|
@ -326,7 +373,8 @@ sub_find(CLI::App& sub, Options& opts)
|
||||||
->default_val(Field::Id::Date)
|
->default_val(Field::Id::Date)
|
||||||
->transform(CLI::CheckedTransformer(smap));
|
->transform(CLI::CheckedTransformer(smap));
|
||||||
|
|
||||||
sub.add_flag("--reverse,-z", opts.find.reverse, "Sort in descending order");
|
sub.add_flag("--reverse,-z", opts.find.reverse,
|
||||||
|
"Sort in descending order");
|
||||||
|
|
||||||
sub.add_option("--bookmark,-b", opts.find.bookmark,
|
sub.add_option("--bookmark,-b", opts.find.bookmark,
|
||||||
"Use bookmarked query")
|
"Use bookmarked query")
|
||||||
|
@ -347,7 +395,8 @@ sub_find(CLI::App& sub, Options& opts)
|
||||||
"Command to execute on message file")
|
"Command to execute on message file")
|
||||||
->type_name("<command>");
|
->type_name("<command>");
|
||||||
|
|
||||||
sub.add_option("query", opts.find.query, "Search query pattern(s)")
|
sub.add_option("query", opts.find.query,
|
||||||
|
"Search query pattern(s)")
|
||||||
->type_name("<query>");
|
->type_name("<query>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,12 +841,45 @@ test_ids()
|
||||||
|
|
||||||
#ifdef BUILD_TESTS
|
#ifdef BUILD_TESTS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum struct TestEnum { A, B, C };
|
||||||
|
constexpr AssocPairs<TestEnum, std::string_view, 3>
|
||||||
|
test_epairs = {{
|
||||||
|
{TestEnum::A, "a"},
|
||||||
|
{TestEnum::B, "b"},
|
||||||
|
{TestEnum::C, "c"},
|
||||||
|
}};
|
||||||
|
|
||||||
|
static constexpr Option<std::string_view>
|
||||||
|
to_name(TestEnum te)
|
||||||
|
{
|
||||||
|
return to_second(test_epairs, te);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Option<TestEnum>
|
||||||
|
to_type(std::string_view name)
|
||||||
|
{
|
||||||
|
return to_first(test_epairs, name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_enum_pairs(void)
|
||||||
|
{
|
||||||
|
assert_equal(to_name(TestEnum::A).value(), "a");
|
||||||
|
g_assert_true(to_type("c").value() == TestEnum::C);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
mu_test_init(&argc, &argv);
|
mu_test_init(&argc, &argv);
|
||||||
|
|
||||||
g_test_add_func("/options/ids", test_ids);
|
g_test_add_func("/options/ids", test_ids);
|
||||||
|
g_test_add_func("/option/enum-pairs", test_enum_pairs);
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue