diff --git a/src/builtins/complete.cpp b/src/builtins/complete.cpp index 3243fe1b5..8798b20ab 100644 --- a/src/builtins/complete.cpp +++ b/src/builtins/complete.cpp @@ -389,10 +389,8 @@ maybe_t builtin_complete(parser_t &parser, io_streams_t &streams, const wch if (!have_do_complete_param) parser.libdata().builtin_complete_current_commandline = true; - completion_list_t comp = - complete(do_complete_param, - {completion_request_t::fuzzy_match, completion_request_t::descriptions}, - parser.context()); + completion_list_t comp = complete( + do_complete_param, completion_request_options_t::normal(), parser.context()); for (const auto &next : comp) { // Make a fake commandline, and then apply the completion to it. diff --git a/src/complete.cpp b/src/complete.cpp index e91ef0e82..340b208b5 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -283,7 +283,7 @@ static void unique_completions_retaining_order(completion_list_t *comps) { comps->erase(std::remove_if(comps->begin(), comps->end(), pred), comps->end()); } -void completions_sort_and_prioritize(completion_list_t *comps, completion_request_flags_t flags) { +void completions_sort_and_prioritize(completion_list_t *comps, completion_request_options_t flags) { if (comps->empty()) return; // Find the best rank. @@ -309,7 +309,7 @@ void completions_sort_and_prioritize(completion_list_t *comps, completion_reques // Lastly, if this is for an autosuggestion, prefer to avoid completions that duplicate // arguments, and penalize files that end in tilde - they're frequently autosave files from e.g. // emacs. Also prefer samecase to smartcase. - if (flags & completion_request_t::autosuggestion) { + if (flags.autosuggestion) { stable_sort(comps->begin(), comps->end(), [](const completion_t &a, const completion_t &b) { if (a.match.case_fold != b.match.case_fold) { return a.match.case_fold < b.match.case_fold; @@ -327,7 +327,7 @@ class completer_t { const operation_context_t &ctx; /// Flags associated with the completion request. - const completion_request_flags_t flags; + const completion_request_options_t flags; /// The output completions. completion_receiver_t completions; @@ -337,17 +337,6 @@ class completer_t { using condition_cache_t = std::unordered_map; condition_cache_t condition_cache; - enum complete_type_t { COMPLETE_DEFAULT, COMPLETE_AUTOSUGGEST }; - - complete_type_t type() const { - return (flags & completion_request_t::autosuggestion) ? COMPLETE_AUTOSUGGEST - : COMPLETE_DEFAULT; - } - - bool wants_descriptions() const { return flags & completion_request_t::descriptions; } - - bool fuzzy() const { return flags & completion_request_t::fuzzy_match; } - bool try_complete_variable(const wcstring &str); bool try_complete_user(const wcstring &str); @@ -377,9 +366,9 @@ class completer_t { expand_flags_t expand_flags() const { expand_flags_t result{}; - if (this->type() == COMPLETE_AUTOSUGGEST) result |= expand_flag::skip_cmdsubst; - if (this->fuzzy()) result |= expand_flag::fuzzy_match; - if (this->wants_descriptions()) result |= expand_flag::gen_descriptions; + if (flags.autosuggestion) result |= expand_flag::skip_cmdsubst; + if (flags.fuzzy_match) result |= expand_flag::fuzzy_match; + if (flags.descriptions) result |= expand_flag::gen_descriptions; return result; } @@ -429,7 +418,7 @@ class completer_t { const std::vector &args); public: - completer_t(const operation_context_t &ctx, completion_request_flags_t f) + completer_t(const operation_context_t &ctx, completion_request_options_t f) : ctx(ctx), flags(f), completions(ctx.expansion_limit) {} void perform_for_commandline(wcstring cmdline); @@ -642,7 +631,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd) { if (result == expand_result_t::cancel) { return; } - if (result == expand_result_t::ok && this->wants_descriptions()) { + if (result == expand_result_t::ok && this->flags.descriptions) { this->complete_cmd_desc(str_cmd); } @@ -707,7 +696,7 @@ void completer_t::complete_abbr(const wcstring &cmd) { /// void completer_t::complete_from_args(const wcstring &str, const wcstring &args, const wcstring &desc, complete_flags_t flags) { - bool is_autosuggest = (this->type() == COMPLETE_AUTOSUGGEST); + const bool is_autosuggest = this->flags.autosuggestion; bool saved_interactive = false; statuses_t status; @@ -1070,7 +1059,7 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file, if (!do_file) flags |= expand_flag::skip_wildcards; if (handle_as_special_cd && do_file) { - if (this->type() == COMPLETE_AUTOSUGGEST) { + if (this->flags.autosuggestion) { flags |= expand_flag::special_for_cd_autosuggestion; } flags |= expand_flag::directories_only; @@ -1078,7 +1067,7 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file, } // Squelch file descriptions per issue #254. - if (this->type() == COMPLETE_AUTOSUGGEST || do_file) flags.clear(expand_flag::gen_descriptions); + if (this->flags.autosuggestion || do_file) flags.clear(expand_flag::gen_descriptions); // We have the following cases: // @@ -1132,7 +1121,7 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) { bool res = false; for (const wcstring &env_name : ctx.vars.get_names(0)) { - bool anchor_start = !fuzzy(); + bool anchor_start = !this->flags.fuzzy_match; maybe_t match = string_fuzzy_match_string(var, env_name, anchor_start); if (!match) continue; @@ -1150,8 +1139,8 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) { } wcstring desc; - if (this->wants_descriptions()) { - if (this->type() != COMPLETE_AUTOSUGGEST) { + if (this->flags.descriptions) { + if (this->flags.autosuggestion) { // $history can be huge, don't put all of it in the completion description; see // #6288. if (env_name == L"history") { @@ -1232,7 +1221,7 @@ bool completer_t::try_complete_variable(const wcstring &str) { // Now complete if we have a variable start. Note the variable text may be empty; in that case // don't generate an autosuggestion, but do allow tab completion. - bool allow_empty = !(this->flags & completion_request_t::autosuggestion); + bool allow_empty = !this->flags.autosuggestion; bool text_is_empty = (variable_start == len); bool result = false; if (variable_start != wcstring::npos && (allow_empty || !text_is_empty)) { @@ -1343,7 +1332,7 @@ void completer_t::complete_custom(const wcstring &cmd, const wcstring &cmdline, custom_arg_data_t *ad) { if (ctx.check_cancel()) return; - bool is_autosuggest = this->type() == COMPLETE_AUTOSUGGEST; + bool is_autosuggest = this->flags.autosuggestion; // Perhaps set a transient commandline so that custom completions // buitin_commandline will refer to the wrapped command. But not if // we're doing autosuggestions. @@ -1520,7 +1509,7 @@ void completer_t::perform_for_commandline(wcstring cmdline) { }}; const size_t cursor_pos = cmdline.size(); - const bool is_autosuggest = (flags & completion_request_t::autosuggestion); + const bool is_autosuggest = flags.autosuggestion; // Find the process to operate on. The cursor may be past it (#1261), so backtrack // until we know we're no longer in a space. But the space may actually be part of the @@ -1730,7 +1719,7 @@ void complete_remove_all(const wcstring &cmd, bool cmd_is_path) { completion_map->erase(std::make_pair(cmd, cmd_is_path)); } -completion_list_t complete(const wcstring &cmd_with_subcmds, completion_request_flags_t flags, +completion_list_t complete(const wcstring &cmd_with_subcmds, completion_request_options_t flags, const operation_context_t &ctx) { // Determine the innermost subcommand. const wchar_t *cmdsubst_begin, *cmdsubst_end; diff --git a/src/complete.h b/src/complete.h index 8f198771a..7fff34387 100644 --- a/src/complete.h +++ b/src/complete.h @@ -11,7 +11,6 @@ #include #include "common.h" -#include "enum_set.h" #include "wcstringutil.h" struct completion_mode_t { @@ -95,19 +94,29 @@ class completion_t { using completion_list_t = std::vector; -enum class completion_request_t { - autosuggestion, // indicates the completion is for an autosuggestion - descriptions, // indicates that we want descriptions - fuzzy_match, // indicates that we don't require a prefix match - COUNT -}; +struct completion_request_options_t { + bool autosuggestion{}; // requesting autosuggestion + bool descriptions{}; // make descriptions + bool fuzzy_match{}; // if set, we do not require a prefix match -template <> -struct enum_info_t { - static constexpr auto count = completion_request_t::COUNT; -}; + // Options for an autosuggestion. + static completion_request_options_t autosuggest() { + completion_request_options_t res{}; + res.autosuggestion = true; + res.descriptions = false; + res.fuzzy_match = false; + return res; + } -using completion_request_flags_t = enum_set_t; + // Options for a "normal" completion. + static completion_request_options_t normal() { + completion_request_options_t res{}; + res.autosuggestion = false; + res.descriptions = true; + res.fuzzy_match = true; + return res; + } +}; class completion_t; using completion_list_t = std::vector; @@ -191,7 +200,7 @@ enum complete_option_type_t { /// Sorts and remove any duplicate completions in the completion list, then puts them in priority /// order. void completions_sort_and_prioritize(completion_list_t *comps, - completion_request_flags_t flags = {}); + completion_request_options_t flags = {}); /// Add a completion. /// @@ -236,7 +245,7 @@ void complete_remove_all(const wcstring &cmd, bool cmd_is_path); /// \return all completions of the command cmd. class operation_context_t; -completion_list_t complete(const wcstring &cmd, completion_request_flags_t flags, +completion_list_t complete(const wcstring &cmd, completion_request_options_t flags, const operation_context_t &ctx); /// Return a list of all current completions. diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 341ac4ba1..bc76e25c0 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -3216,7 +3216,7 @@ static void test_complete() { auto parser = parser_t::principal_parser().shared(); - auto do_complete = [&](const wcstring &cmd, completion_request_flags_t flags) { + auto do_complete = [&](const wcstring &cmd, completion_request_options_t flags) { return complete(cmd, flags, operation_context_t{parser, vars, no_cancel}); }; @@ -3254,7 +3254,9 @@ static void test_complete() { completions_sort_and_prioritize(&completions); do_test(completions.empty()); - completions = do_complete(L"$1", completion_request_t::fuzzy_match); + completion_request_options_t fuzzy_options{}; + fuzzy_options.fuzzy_match = true; + completions = do_complete(L"$1", fuzzy_options); completions_sort_and_prioritize(&completions); do_test(completions.size() == 3); do_test(completions.at(0).completion == L"$Bar1"); @@ -3394,7 +3396,7 @@ static void test_complete() { do_test(completions.at(0).completion == L"stfile"); completions = do_complete(L"something abc=stfile", {}); do_test(completions.empty()); - completions = do_complete(L"something abc=stfile", completion_request_t::fuzzy_match); + completions = do_complete(L"something abc=stfile", fuzzy_options); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"abc=testfile"); @@ -3566,7 +3568,7 @@ static void test_completion_insertions() { static void perform_one_autosuggestion_cd_test(const wcstring &command, const wcstring &expected, const environment_t &vars, long line) { completion_list_t comps = - complete(command, completion_request_t::autosuggestion, operation_context_t{vars}); + complete(command, completion_request_options_t::autosuggest(), operation_context_t{vars}); bool expects_error = (expected == L""); @@ -3754,8 +3756,8 @@ static void test_autosuggest_suggest_special() { } static void perform_one_autosuggestion_should_ignore_test(const wcstring &command, long line) { - completion_list_t comps = - complete(command, completion_request_t::autosuggestion, operation_context_t::empty()); + completion_list_t comps = complete(command, completion_request_options_t::autosuggest(), + operation_context_t::empty()); do_test(comps.empty()); if (!comps.empty()) { const wcstring &suggestion = comps.front().completion; diff --git a/src/reader.cpp b/src/reader.cpp index 785f680f8..771f3b669 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1777,7 +1777,7 @@ static std::function get_autosuggestion_performer( if (std::wcschr(L"'\"", last_char) && cursor_at_end) return nothing; // Try normal completions. - completion_request_flags_t complete_flags = completion_request_t::autosuggestion; + completion_request_options_t complete_flags = completion_request_options_t::autosuggest(); completion_list_t completions = complete(search_string, complete_flags, ctx); completions_sort_and_prioritize(&completions, complete_flags); if (!completions.empty()) { @@ -2892,9 +2892,7 @@ void reader_data_t::compute_and_apply_completions(readline_cmd_t c, readline_loo // Ensure that `commandline` inside the completions gets the current state. update_commandline_state(); - completion_request_flags_t complete_flags = {completion_request_t::descriptions, - completion_request_t::fuzzy_match}; - rls.comp = complete(buffcpy, complete_flags, parser_ref->context()); + rls.comp = complete(buffcpy, completion_request_options_t::normal(), parser_ref->context()); // User-supplied completions may have changed the commandline - prevent buffer // overflow.