mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-17 06:52:44 +08:00
Switch completion_request_options_t from a list of flags to a struct
This is simpler and allows potentially hanging more fields off of it later.
This commit is contained in:
parent
1819c7f2b8
commit
17bd7d0e40
|
@ -389,10 +389,8 @@ maybe_t<int> 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.
|
||||
|
|
|
@ -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<wcstring, bool>;
|
||||
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<tok_t> &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<string_fuzzy_match_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;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <vector>
|
||||
|
||||
#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<completion_t>;
|
||||
|
||||
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<completion_request_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<completion_request_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<completion_t>;
|
||||
|
@ -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.
|
||||
|
|
|
@ -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"<error>");
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -1777,7 +1777,7 @@ static std::function<autosuggestion_t(void)> 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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user