diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index 9f4c75d00..54df50511 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -329,8 +329,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { recursion_level++; std::vector comp; - complete(do_complete_param, &comp, - COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_FUZZY_MATCH, parser.vars()); + complete(do_complete_param, &comp, completion_request_t::fuzzy_match, parser.vars()); for (size_t i = 0; i < comp.size(); i++) { const completion_t &next = comp.at(i); diff --git a/src/complete.cpp b/src/complete.cpp index 4252fee87..3f3d97828 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -287,7 +287,7 @@ void completions_sort_and_prioritize(std::vector *comps, // Lastly, if this is for an autosuggestion, prefer to avoid completions that duplicate // arguments. - if (flags & COMPLETION_REQUEST_AUTOSUGGESTION) + if (flags & completion_request_t::autosuggestion) stable_sort(comps->begin(), comps->end(), compare_completions_by_duplicate_arguments); } @@ -313,18 +313,17 @@ class completer_t { enum complete_type_t { COMPLETE_DEFAULT, COMPLETE_AUTOSUGGEST }; complete_type_t type() const { - return flags & COMPLETION_REQUEST_AUTOSUGGESTION ? COMPLETE_AUTOSUGGEST : COMPLETE_DEFAULT; + return (flags & completion_request_t::autosuggestion) ? COMPLETE_AUTOSUGGEST + : COMPLETE_DEFAULT; } - bool wants_descriptions() const { - return static_cast(flags & COMPLETION_REQUEST_DESCRIPTIONS); - } + bool wants_descriptions() const { return flags & completion_request_t::descriptions; } - bool fuzzy() const { return static_cast(flags & COMPLETION_REQUEST_FUZZY_MATCH); } + bool fuzzy() const { return flags & completion_request_t::fuzzy_match; } fuzzy_match_type_t max_fuzzy_match_type() const { // If we are doing fuzzy matching, request all types; if not request only prefix matching. - if (flags & COMPLETION_REQUEST_FUZZY_MATCH) return fuzzy_match_none; + if (fuzzy()) return fuzzy_match_none; return fuzzy_match_prefix_case_insensitive; } @@ -1226,7 +1225,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_AUTOSUGGESTION); + bool allow_empty = !(this->flags & completion_request_t::autosuggestion); bool text_is_empty = (variable_start == len); bool result = false; if (variable_start != wcstring::npos && (allow_empty || !text_is_empty)) { @@ -1414,7 +1413,7 @@ void completer_t::perform() { // first of the sequence of nodes without source locations at the very end of the parse // tree). bool do_file = true; - if (flags & COMPLETION_REQUEST_AUTOSUGGESTION) { + if (flags & completion_request_t::autosuggestion) { if (position_in_statement < pos) { do_file = false; } else if (pos > 0) { @@ -1551,7 +1550,7 @@ void completer_t::perform() { // buitin_commandline will refer to the wrapped command. But not if // we're doing autosuggestions. std::unique_ptr bcst; - if (depth > 0 && !(flags & COMPLETION_REQUEST_AUTOSUGGESTION)) { + if (depth > 0 && !(flags & completion_request_t::autosuggestion)) { bcst = make_unique(cmdline); } // Now invoke any custom completions for this command. @@ -1567,7 +1566,7 @@ void completer_t::perform() { handle_as_special_cd = (current_command_unescape == L"cd"); // And if we're autosuggesting, and the token is empty, don't do file suggestions. - if ((flags & COMPLETION_REQUEST_AUTOSUGGESTION) && + if ((flags & completion_request_t::autosuggestion) && current_argument_unescape.empty()) { do_file = false; } diff --git a/src/complete.h b/src/complete.h index 3af4cafc1..c4532fc7e 100644 --- a/src/complete.h +++ b/src/complete.h @@ -12,6 +12,8 @@ #include "common.h" +#include "enum_set.h" + struct completion_mode_t { /// If set, skip file completions. bool no_files{false}; @@ -99,14 +101,19 @@ class completion_t { void prepend_token_prefix(const wcstring &prefix); }; -enum { - COMPLETION_REQUEST_DEFAULT = 0, - COMPLETION_REQUEST_AUTOSUGGESTION = 1 - << 0, // indicates the completion is for an autosuggestion - COMPLETION_REQUEST_DESCRIPTIONS = 1 << 1, // indicates that we want descriptions - COMPLETION_REQUEST_FUZZY_MATCH = 1 << 2 // indicates that we don't require a prefix match +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 }; -typedef uint32_t completion_request_flags_t; + +template <> +struct enum_info_t { + static constexpr auto count = completion_request_t::COUNT; +}; + +using completion_request_flags_t = enum_set_t; enum complete_option_type_t { option_type_args_only, // no option @@ -118,7 +125,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(std::vector *comps, - completion_request_flags_t flags = COMPLETION_REQUEST_DEFAULT); + completion_request_flags_t flags = {}); /// Add a completion. /// diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 9cb125fef..1df50f1df 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2493,7 +2493,7 @@ static void test_complete() { test_complete_vars_t vars; completion_list_t completions; - complete(L"$", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"$", &completions, {}, vars); completions_sort_and_prioritize(&completions); do_test(completions.size() == 6); do_test(completions.at(0).completion == L"Bar1"); @@ -2504,7 +2504,7 @@ static void test_complete() { do_test(completions.at(5).completion == L"Foo3"); completions.clear(); - complete(L"$F", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"$F", &completions, {}, vars); completions_sort_and_prioritize(&completions); do_test(completions.size() == 3); do_test(completions.at(0).completion == L"oo1"); @@ -2512,13 +2512,12 @@ static void test_complete() { do_test(completions.at(2).completion == L"oo3"); completions.clear(); - complete(L"$1", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"$1", &completions, {}, vars); completions_sort_and_prioritize(&completions); do_test(completions.empty()); completions.clear(); - complete(L"$1", &completions, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_FUZZY_MATCH, - vars); + complete(L"$1", &completions, completion_request_t::fuzzy_match, vars); completions_sort_and_prioritize(&completions); do_test(completions.size() == 2); do_test(completions.at(0).completion == L"$Bar1"); @@ -2530,25 +2529,23 @@ static void test_complete() { if (system("chmod 700 'test/complete_test/testfile'")) err(L"chmod failed"); completions.clear(); - complete(L"echo (test/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo (test/complete_test/testfil", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"e"); completions.clear(); - complete(L"echo (ls test/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT, - vars); + complete(L"echo (ls test/complete_test/testfil", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"e"); completions.clear(); - complete(L"echo (command ls test/complete_test/testfil", &completions, - COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo (command ls test/complete_test/testfil", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"e"); // Completing after spaces - see #2447 completions.clear(); - complete(L"echo (ls test/complete_test/has\\ ", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo (ls test/complete_test/has\\ ", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"space"); @@ -2561,23 +2558,23 @@ static void test_complete() { // Complete a function name. completions.clear(); - complete(L"echo (scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo (scuttlebut", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"t"); // But not with the command prefix. completions.clear(); - complete(L"echo (command scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo (command scuttlebut", &completions, {}, vars); do_test(completions.size() == 0); // Not with the builtin prefix. completions.clear(); - complete(L"echo (builtin scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo (builtin scuttlebut", &completions, {}, vars); do_test(completions.size() == 0); // Not after a redirection. completions.clear(); - complete(L"echo hi > scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo hi > scuttlebut", &completions, {}, vars); do_test(completions.size() == 0); // Trailing spaces (#1261). @@ -2586,81 +2583,81 @@ static void test_complete() { 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); + complete(L"foobarbaz ", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"qux"); // Don't complete variable names in single quotes (#1023). completions.clear(); - complete(L"echo '$Foo", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo '$Foo", &completions, {}, vars); do_test(completions.empty()); completions.clear(); - complete(L"echo \\$Foo", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo \\$Foo", &completions, {}, vars); do_test(completions.empty()); // File completions. completions.clear(); - complete(L"cat test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat test/complete_test/te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); completions.clear(); - complete(L"echo sup > test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo sup > test/complete_test/te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); completions.clear(); - complete(L"echo sup > test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"echo sup > test/complete_test/te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); if (!pushd("test/complete_test")) return; - complete(L"cat te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); do_test(!(completions.at(0).flags & COMPLETE_REPLACES_TOKEN)); do_test(!(completions.at(0).flags & COMPLETE_DUPLICATES_ARGUMENT)); completions.clear(); - complete(L"cat testfile te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat testfile te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); do_test(completions.at(0).flags & COMPLETE_DUPLICATES_ARGUMENT); completions.clear(); - complete(L"cat testfile TE", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat testfile TE", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"testfile"); do_test(completions.at(0).flags & COMPLETE_REPLACES_TOKEN); do_test(completions.at(0).flags & COMPLETE_DUPLICATES_ARGUMENT); completions.clear(); - complete(L"something --abc=te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"something --abc=te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); completions.clear(); - complete(L"something -abc=te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"something -abc=te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); completions.clear(); - complete(L"something abc=te", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"something abc=te", &completions, {}, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); completions.clear(); - complete(L"something abc=stfile", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"something abc=stfile", &completions, {}, vars); do_test(completions.size() == 0); completions.clear(); - complete(L"something abc=stfile", &completions, COMPLETION_REQUEST_FUZZY_MATCH, vars); + complete(L"something abc=stfile", &completions, completion_request_t::fuzzy_match, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"abc=testfile"); // Zero escapes can cause problems. See issue #1631. completions.clear(); - complete(L"cat foo\\0", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat foo\\0", &completions, {}, vars); do_test(completions.empty()); completions.clear(); - complete(L"cat foo\\0bar", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat foo\\0bar", &completions, {}, vars); do_test(completions.empty()); completions.clear(); - complete(L"cat \\0", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat \\0", &completions, {}, vars); do_test(completions.empty()); completions.clear(); - complete(L"cat te\\0", &completions, COMPLETION_REQUEST_DEFAULT, vars); + complete(L"cat te\\0", &completions, {}, vars); do_test(completions.empty()); popd(); @@ -2672,7 +2669,7 @@ static void test_complete() { fd.name = L"testabbrsonetwothreefour"; function_add(fd, parser_t::principal_parser()); int ret = pvars.set_one(L"_fish_abbr_testabbrsonetwothreezero", ENV_LOCAL, L"expansion"); - complete(L"testabbrsonetwothree", &completions, COMPLETION_REQUEST_DEFAULT, pvars); + complete(L"testabbrsonetwothree", &completions, {}, pvars); do_test(ret == 0); do_test(completions.size() == 2); do_test(completions.at(0).completion == L"four"); @@ -2752,7 +2749,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) { std::vector comps; - complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, vars); + complete(command, &comps, completion_request_t::autosuggestion, vars); bool expects_error = (expected == L""); @@ -2788,7 +2785,7 @@ static void perform_one_autosuggestion_cd_test(const wcstring &command, const wc static void perform_one_completion_cd_test(const wcstring &command, const wcstring &expected, const environment_t &vars, long line) { std::vector comps; - complete(command, &comps, COMPLETION_REQUEST_DEFAULT, vars); + complete(command, &comps, {}, vars); bool expects_error = (expected == L""); @@ -2928,7 +2925,7 @@ 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, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, null_environment_t{}); + complete(command, &comps, completion_request_t::autosuggestion, null_environment_t{}); do_test(comps.empty()); if (!comps.empty()) { const wcstring &suggestion = comps.front().completion; diff --git a/src/reader.cpp b/src/reader.cpp index c7c986c52..38ede99b8 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1325,7 +1325,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_AUTOSUGGESTION; + completion_request_flags_t complete_flags = completion_request_t::autosuggestion; std::vector completions; complete(search_string, &completions, complete_flags, *vars); completions_sort_and_prioritize(&completions, complete_flags); @@ -2583,9 +2583,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat const wcstring buffcpy = wcstring(cmdsub_begin, token_end); // std::fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); - complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | - COMPLETION_REQUEST_DESCRIPTIONS | - COMPLETION_REQUEST_FUZZY_MATCH; + completion_request_flags_t complete_flags = {completion_request_t::descriptions, + completion_request_t::fuzzy_match}; complete_func(buffcpy, &rls.comp, complete_flags, vars); // Munge our completions.