diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index 107c79213..990b20bee 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -29,8 +29,8 @@ /// Silly function. static void builtin_complete_add2(const wchar_t *cmd, bool cmd_is_path, const wchar_t *short_opt, const wcstring_list_t &gnu_opts, const wcstring_list_t &old_opts, - int result_mode, const wchar_t *condition, const wchar_t *comp, - const wchar_t *desc, int flags) { + completion_mode_t result_mode, const wchar_t *condition, + const wchar_t *comp, const wchar_t *desc, int flags) { for (const wchar_t *s = short_opt; *s; s++) { complete_add(cmd, cmd_is_path, wcstring{*s}, option_type_short, result_mode, condition, comp, desc, flags); @@ -55,7 +55,7 @@ static void builtin_complete_add2(const wchar_t *cmd, bool cmd_is_path, const wc /// Silly function. static void builtin_complete_add(const wcstring_list_t &cmds, const wcstring_list_t &paths, const wchar_t *short_opt, wcstring_list_t &gnu_opt, - wcstring_list_t &old_opt, int result_mode, + wcstring_list_t &old_opt, completion_mode_t result_mode, const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, int flags) { for (const wcstring &cmd : cmds) { @@ -114,7 +114,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); - int result_mode = SHARED; + completion_mode_t result_mode{}; int remove = 0; wcstring short_opt; wcstring_list_t gnu_opt, old_opt; @@ -152,15 +152,16 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { case 'x': { - result_mode |= EXCLUSIVE; + result_mode.no_files = true; + result_mode.requires_param = true; break; } case 'f': { - result_mode |= NO_FILES; + result_mode.no_files = true; break; } case 'r': { - result_mode |= NO_COMMON; + result_mode.requires_param = true; break; } case 'k': { diff --git a/src/complete.cpp b/src/complete.cpp index 02c1e0983..4cb981eb2 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -97,9 +97,8 @@ typedef struct complete_entry_opt { wcstring desc; // Condition under which to use the option. wcstring condition; - // Must be one of the values SHARED, NO_FILES, NO_COMMON, EXCLUSIVE, and determines how - // completions should be performed on the argument after the switch. - int result_mode; + // Determines how completions should be performed on the argument after the switch. + completion_mode_t result_mode; // Completion flags. complete_flags_t flags; @@ -440,8 +439,9 @@ static completion_entry_t &complete_get_exact_entry(completion_entry_set_t &comp } void complete_add(const wchar_t *cmd, bool cmd_is_path, const wcstring &option, - complete_option_type_t option_type, int result_mode, const wchar_t *condition, - const wchar_t *comp, const wchar_t *desc, complete_flags_t flags) { + complete_option_type_t option_type, completion_mode_t result_mode, + const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, + complete_flags_t flags) { CHECK(cmd, ); // option should be empty iff the option type is arguments only. assert(option.empty() == (option_type == option_type_args_only)); @@ -852,7 +852,7 @@ static bool short_ok(const wcstring &arg, const complete_entry_opt_t *entry, break; } } - if (match == NULL || (match->result_mode & NO_COMMON)) { + if (match == NULL || (match->result_mode.requires_param)) { result = false; break; } @@ -946,8 +946,8 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt, for (const complete_entry_opt_t &o : options) { const wchar_t *arg = param_match2(&o, str.c_str()); if (arg != NULL && this->condition_test(o.condition)) { - if (o.result_mode & NO_COMMON) use_common = false; - if (o.result_mode & NO_FILES) use_files = false; + if (o.result_mode.requires_param) use_common = false; + if (o.result_mode.no_files) use_files = false; complete_from_args(arg, o.comp, o.localized_desc(), o.flags); } } @@ -962,8 +962,8 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt, if (o.type == option_type_single_long && param_match(&o, popt.c_str()) && this->condition_test(o.condition)) { old_style_match = true; - if (o.result_mode & NO_COMMON) use_common = false; - if (o.result_mode & NO_FILES) use_files = false; + if (o.result_mode.requires_param) use_common = false; + if (o.result_mode.no_files) use_files = false; complete_from_args(str, o.comp, o.localized_desc(), o.flags); } } @@ -976,12 +976,12 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt, // token, so that it can be differed from a regular argument. // Here we are testing the previous argument for a GNU-style match, // to see how we should complete the current argument - if (o.type == option_type_double_long && !(o.result_mode & NO_COMMON)) + if (o.type == option_type_double_long && !o.result_mode.requires_param) continue; if (param_match(&o, popt.c_str()) && this->condition_test(o.condition)) { - if (o.result_mode & NO_COMMON) use_common = false; - if (o.result_mode & NO_FILES) use_files = false; + if (o.result_mode.requires_param) use_common = false; + if (o.result_mode.no_files) use_files = false; complete_from_args(str, o.comp, o.localized_desc(), o.flags); } } @@ -998,7 +998,7 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt, // If this entry is for the base command, check if any of the arguments match. if (!this->condition_test(o.condition)) continue; if (o.option.empty()) { - use_files = use_files && ((o.result_mode & NO_FILES) == 0); + use_files = use_files && ((o.result_mode.no_files) == 0); complete_from_args(str, o.comp, o.localized_desc(), o.flags); } @@ -1043,7 +1043,7 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt, } has_arg = !o.comp.empty(); - req_arg = (o.result_mode & NO_COMMON); + req_arg = o.result_mode.requires_param; if (o.type == option_type_double_long && (has_arg && !req_arg)) { // Optional arguments to a switch can only be handled using the '=', so we add it as @@ -1616,10 +1616,15 @@ wcstring complete_print() { for (const completion_entry_t &e : all_completions) { const option_list_t &options = e.get_options(); for (const complete_entry_opt_t &o : options) { - const wchar_t *modestr[] = {L"", L" --no-files", L" --require-parameter", - L" --exclusive"}; - - append_format(out, L"complete%ls", modestr[o.result_mode]); + const wchar_t *modestr = L""; + if (o.result_mode.no_files && o.result_mode.requires_param) { + modestr = L" --exclusive"; + } else if (o.result_mode.no_files) { + modestr = L" --no-files"; + } else if (o.result_mode.requires_param) { + modestr = L" --require-parameter"; + } + append_format(out, L"complete%ls", modestr); append_switch(out, e.cmd_is_path ? L"path" : L"command", escape_string(e.cmd, ESCAPE_ALL)); diff --git a/src/complete.h b/src/complete.h index fd33ba24e..91806bd58 100644 --- a/src/complete.h +++ b/src/complete.h @@ -12,15 +12,13 @@ #include "common.h" -/// Use all completions. -#define SHARED 0 -/// Do not use file completion. -#define NO_FILES 1 -/// Require a parameter after completion. -#define NO_COMMON 2 -/// Only use the argument list specifies with completion after option. This is the same as (NO_FILES -/// | NO_COMMON). -#define EXCLUSIVE 3 +struct completion_mode_t { + /// If set, skip file completions. + bool no_files{false}; + + /// If set, require a parameter after completion. + bool requires_param{false}; +}; /// Separator between completion and description. #define COMPLETE_SEP L'\004' @@ -148,19 +146,16 @@ void completions_sort_and_prioritize(std::vector *comps, /// \param option The name of an option. /// \param option_type The type of option: can be option_type_short (-x), /// option_type_single_long (-foo), option_type_double_long (--bar). -/// \param result_mode Whether to search further completions when this completion has been -/// succesfully matched. If result_mode is SHARED, any other completions may also be used. If -/// result_mode is NO_FILES, file completion should not be used, but other completions may be used. -/// If result_mode is NO_COMMON, on option may follow it - only a parameter. If result_mode is -/// EXCLUSIVE, no option may follow it, and file completion is not performed. +/// \param result_mode Controls how to search further completions when this completion has been +/// succesfully matched. /// \param comp A space separated list of completions which may contain subshells. /// \param desc A description of the completion. /// \param condition a command to be run to check it this completion should be used. If \c condition /// is empty, the completion is always used. /// \param flags A set of completion flags void complete_add(const wchar_t *cmd, bool cmd_is_path, const wcstring &option, - complete_option_type_t option_type, int result_mode, const wchar_t *condition, - const wchar_t *comp, const wchar_t *desc, int flags); + complete_option_type_t option_type, completion_mode_t result_mode, + const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, int flags); /// Remove a previously defined completion. void complete_remove(const wcstring &cmd, bool cmd_is_path, const wcstring &option, diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index e60a6712d..fa293f8dd 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2579,7 +2579,9 @@ static void test_complete() { do_test(completions.size() == 0); // Trailing spaces (#1261). - complete_add(L"foobarbaz", false, wcstring(), option_type_args_only, NO_FILES, NULL, L"qux", + completion_mode_t no_files{}; + no_files.no_files = true; + complete_add(L"foobarbaz", false, wcstring(), option_type_args_only, no_files, NULL, L"qux", NULL, COMPLETE_AUTO_SPACE); completions.clear(); complete(L"foobarbaz ", &completions, COMPLETION_REQUEST_DEFAULT, vars);