diff --git a/src/complete.cpp b/src/complete.cpp index be995e652..e5f6673c0 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -196,6 +196,10 @@ const option_list_t &completion_entry_t::get_options() const { return options; } +description_func_t const_desc(const wcstring &s) { + return [=](const wcstring &ignored) { return s; }; +} + /// Clear the COMPLETE_AUTO_SPACE flag, and set COMPLETE_NO_SPACE appropriately depending on the /// suffix of the string. static complete_flags_t resolve_auto_space(const wcstring &comp, complete_flags_t flags) { @@ -342,9 +346,8 @@ class completer_t { bool condition_test(const wcstring &condition); - void complete_strings(const wcstring &wc_escaped, const wchar_t *desc, - wcstring (*desc_func)(const wcstring &), - std::vector &possible_comp, complete_flags_t flags); + void complete_strings(const wcstring &wc_escaped, const description_func_t &desc_func, + const std::vector &possible_comp, complete_flags_t flags); expand_flags_t expand_flags() const { // Never do command substitution in autosuggestions. Sadly, we also can't yet do job @@ -520,20 +523,15 @@ static void parse_cmd_string(const wcstring &str, wcstring &path, wcstring &cmd) /// the prefix, possibly containing wildcards. The wildcard should not have /// been unescaped, i.e. '*' should be used for any string, not the /// ANY_STRING character. -/// @param desc -/// the default description, used for completions with no embedded -/// description. The description _may_ contain a COMPLETE_SEP character, if -/// not, one will be prefixed to it /// @param desc_func -/// the function that generates a description for those completions witout an +/// the function that generates a description for those completions without an /// embedded description /// @param possible_comp /// the list of possible completions to iterate over /// @param flags /// The flags -void completer_t::complete_strings(const wcstring &wc_escaped, const wchar_t *desc, - wcstring (*desc_func)(const wcstring &), - std::vector &possible_comp, +void completer_t::complete_strings(const wcstring &wc_escaped, const description_func_t &desc_func, + const std::vector &possible_comp, complete_flags_t flags) { wcstring tmp = wc_escaped; if (!expand_one(tmp, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_WILDCARDS | this->expand_flags(), NULL)) @@ -546,7 +544,7 @@ void completer_t::complete_strings(const wcstring &wc_escaped, const wchar_t *de const wchar_t *next_str = temp.empty() ? NULL : temp.c_str(); if (next_str) { - wildcard_complete(next_str, wc.c_str(), desc, desc_func, &this->completions, + wildcard_complete(next_str, wc.c_str(), desc_func, &this->completions, this->expand_flags(), flags); } } @@ -683,7 +681,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool append_completion(&possible_comp, std::move(name)); } - this->complete_strings(str_cmd, 0, &complete_function_desc, possible_comp, 0); + this->complete_strings(str_cmd, complete_function_desc, possible_comp, 0); } possible_comp.clear(); @@ -691,7 +689,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool if (use_builtin) { // Append all matching builtins builtin_get_names(&possible_comp); - this->complete_strings(str_cmd, 0, &builtin_get_desc, possible_comp, 0); + this->complete_strings(str_cmd, builtin_get_desc, possible_comp, 0); } } } @@ -733,7 +731,7 @@ void completer_t::complete_from_args(const wcstring &str, const wcstring &args, proc_pop_interactive(); } - this->complete_strings(escape_string(str, ESCAPE_ALL), desc.c_str(), 0, possible_comp, flags); + this->complete_strings(escape_string(str, ESCAPE_ALL), const_desc(desc), possible_comp, flags); } static size_t leading_dash_count(const wchar_t *str) { diff --git a/src/complete.h b/src/complete.h index db9b650b8..2d665879c 100644 --- a/src/complete.h +++ b/src/complete.h @@ -49,6 +49,12 @@ enum { }; typedef int complete_flags_t; +/// std::function which accepts a completion string and returns its description. +using description_func_t = std::function; + +/// Helper to return a description_func_t for a constant string. +description_func_t const_desc(const wcstring &s); + class completion_t { private: // No public default constructor. diff --git a/src/wildcard.cpp b/src/wildcard.cpp index 3cc28fd20..d0b65a229 100644 --- a/src/wildcard.cpp +++ b/src/wildcard.cpp @@ -158,8 +158,8 @@ static enum fuzzy_match_type_t wildcard_match_internal(const wchar_t *str, const // This does something horrible refactored from an even more horrible function. static wcstring resolve_description(const wchar_t *full_completion, wcstring *completion, - const wchar_t *explicit_desc, - wcstring (*desc_func)(const wcstring &)) { + expand_flags_t expand_flags, + const description_func_t &desc_func) { size_t complete_sep_loc = completion->find(PROG_COMPLETE_SEP); if (complete_sep_loc != wcstring::npos) { // This completion has an embedded description, do not use the generic description. @@ -167,23 +167,17 @@ static wcstring resolve_description(const wchar_t *full_completion, wcstring *co completion->resize(complete_sep_loc); return description; } - - const wcstring func_result = (desc_func ? desc_func(full_completion) : wcstring()); - if (!func_result.empty()) { - return func_result; - } - return explicit_desc ? explicit_desc : L""; + if (expand_flags & EXPAND_NO_DESCRIPTIONS) return {}; + return desc_func ? desc_func(full_completion) : wcstring{}; } // A transient parameter pack needed by wildcard_complete. struct wc_complete_pack_t { const wcstring &orig; // the original string, transient - const wchar_t *desc; // literal description - wcstring (*desc_func)(const wcstring &); // function for generating descriptions + const description_func_t &desc_func; // function for generating descriptions expand_flags_t expand_flags; - wc_complete_pack_t(const wcstring &str, const wchar_t *des, wcstring (*df)(const wcstring &), - expand_flags_t fl) - : orig(str), desc(des), desc_func(df), expand_flags(fl) {} + wc_complete_pack_t(const wcstring &str, const description_func_t &df, expand_flags_t fl) + : orig(str), desc_func(df), expand_flags(fl) {} }; // Weirdly specific and non-reusable helper function that makes its one call site much clearer. @@ -244,7 +238,7 @@ static bool wildcard_complete_internal(const wchar_t *str, const wchar_t *wc, assert(!full_replacement || wcslen(wc) <= wcslen(str)); wcstring out_completion = full_replacement ? params.orig : str + wcslen(wc); wcstring out_desc = - resolve_description(str, &out_completion, params.desc, params.desc_func); + resolve_description(str, &out_completion, params.expand_flags, params.desc_func); // Note: out_completion may be empty if the completion really is empty, e.g. tab-completing // 'foo' when a file 'foo' exists. @@ -316,12 +310,13 @@ static bool wildcard_complete_internal(const wchar_t *str, const wchar_t *wc, DIE("unreachable code reached"); } -bool wildcard_complete(const wcstring &str, const wchar_t *wc, const wchar_t *desc, - wcstring (*desc_func)(const wcstring &), std::vector *out, - expand_flags_t expand_flags, complete_flags_t flags) { +bool wildcard_complete(const wcstring &str, const wchar_t *wc, + const std::function &desc_func, + std::vector *out, expand_flags_t expand_flags, + complete_flags_t flags) { // Note out may be NULL. assert(wc != NULL); - wc_complete_pack_t params(str, desc, desc_func, expand_flags); + wc_complete_pack_t params(str, desc_func, expand_flags); return wildcard_complete_internal(str.c_str(), wc, params, flags, out, true /* first call */); } @@ -393,7 +388,7 @@ static bool wildcard_test_flags_then_complete(const wcstring &filepath, const wc const wchar_t *wc, expand_flags_t expand_flags, std::vector *out) { // Check if it will match before stat(). - if (!wildcard_complete(filename, wc, NULL, NULL, NULL, expand_flags, 0)) { + if (!wildcard_complete(filename, wc, {}, NULL, expand_flags, 0)) { return false; } @@ -448,11 +443,12 @@ static bool wildcard_test_flags_then_complete(const wcstring &filepath, const wc // Append a / if this is a directory. Note this requirement may be the only reason we have to // call stat() in some cases. + auto desc_func = const_desc(desc); if (is_directory) { - return wildcard_complete(filename + L'/', wc, desc.c_str(), NULL, out, expand_flags, + return wildcard_complete(filename + L'/', wc, desc_func, out, expand_flags, COMPLETE_NO_SPACE); } - return wildcard_complete(filename, wc, desc.c_str(), NULL, out, expand_flags, 0); + return wildcard_complete(filename, wc, desc_func, out, expand_flags, 0); } class wildcard_expander_t { diff --git a/src/wildcard.h b/src/wildcard.h index 5229ee027..77b58c67c 100644 --- a/src/wildcard.h +++ b/src/wildcard.h @@ -61,8 +61,8 @@ bool wildcard_has(const wcstring &, bool internal); bool wildcard_has(const wchar_t *, bool internal); /// Test wildcard completion. -bool wildcard_complete(const wcstring &str, const wchar_t *wc, const wchar_t *desc, - wcstring (*desc_func)(const wcstring &), std::vector *out, - expand_flags_t expand_flags, complete_flags_t flags); +bool wildcard_complete(const wcstring &str, const wchar_t *wc, const description_func_t &desc_func, + std::vector *out, expand_flags_t expand_flags, + complete_flags_t flags); #endif