mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-21 02:54:11 +08:00
Switch expand_flags_t to enum_set
This commit is contained in:
parent
dcaac58f45
commit
d8ab6290e8
@ -359,11 +359,11 @@ class completer_t {
|
||||
expand_flags_t expand_flags() const {
|
||||
// Never do command substitution in autosuggestions. Sadly, we also can't yet do job
|
||||
// expansion because it's not thread safe.
|
||||
expand_flags_t result = 0;
|
||||
if (this->type() == COMPLETE_AUTOSUGGEST) result |= EXPAND_SKIP_CMDSUBST;
|
||||
expand_flags_t result{};
|
||||
if (this->type() == COMPLETE_AUTOSUGGEST) result |= expand_flag::EXPAND_SKIP_CMDSUBST;
|
||||
|
||||
// Allow fuzzy matching.
|
||||
if (this->fuzzy()) result |= EXPAND_FUZZY_MATCH;
|
||||
if (this->fuzzy()) result |= expand_flag::EXPAND_FUZZY_MATCH;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -545,7 +545,10 @@ void completer_t::complete_strings(const wcstring &wc_escaped, const description
|
||||
const std::vector<completion_t> &possible_comp,
|
||||
complete_flags_t flags) {
|
||||
wcstring tmp = wc_escaped;
|
||||
if (!expand_one(tmp, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_WILDCARDS | this->expand_flags(), vars))
|
||||
if (!expand_one(tmp,
|
||||
this->expand_flags() | expand_flag::EXPAND_SKIP_CMDSUBST |
|
||||
expand_flag::EXPAND_SKIP_WILDCARDS,
|
||||
vars))
|
||||
return;
|
||||
|
||||
const wcstring wc = parse_util_unescape_wildcards(tmp);
|
||||
@ -665,10 +668,11 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
|
||||
|
||||
if (use_command) {
|
||||
// Append all possible executables
|
||||
expand_result_t result = expand_string(str_cmd, &this->completions,
|
||||
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS |
|
||||
EXECUTABLES_ONLY | this->expand_flags(),
|
||||
vars, NULL);
|
||||
expand_result_t result =
|
||||
expand_string(str_cmd, &this->completions,
|
||||
this->expand_flags() | expand_flag::EXPAND_SPECIAL_FOR_COMMAND |
|
||||
expand_flag::EXPAND_FOR_COMPLETIONS | expand_flag::EXECUTABLES_ONLY,
|
||||
vars, NULL);
|
||||
if (result != expand_result_t::error && this->wants_descriptions()) {
|
||||
this->complete_cmd_desc(str_cmd);
|
||||
}
|
||||
@ -680,8 +684,9 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
|
||||
expand_result_t ignore =
|
||||
// Append all matching directories
|
||||
expand_string(str_cmd, &this->completions,
|
||||
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(), vars,
|
||||
NULL);
|
||||
this->expand_flags() | expand_flag::EXPAND_FOR_COMPLETIONS |
|
||||
expand_flag::DIRECTORIES_ONLY,
|
||||
vars, NULL);
|
||||
UNUSED(ignore);
|
||||
}
|
||||
|
||||
@ -747,9 +752,10 @@ void completer_t::complete_from_args(const wcstring &str, const wcstring &args,
|
||||
proc_push_interactive(0);
|
||||
}
|
||||
|
||||
expand_flags_t eflags = 0;
|
||||
expand_flags_t eflags{};
|
||||
if (is_autosuggest) {
|
||||
eflags |= EXPAND_NO_DESCRIPTIONS | EXPAND_SKIP_CMDSUBST;
|
||||
eflags |= expand_flag::EXPAND_NO_DESCRIPTIONS;
|
||||
eflags |= expand_flag::EXPAND_SKIP_CMDSUBST;
|
||||
}
|
||||
|
||||
std::vector<completion_t> possible_comp;
|
||||
@ -1061,19 +1067,22 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt,
|
||||
/// Perform generic (not command-specific) expansions on the specified string.
|
||||
void completer_t::complete_param_expand(const wcstring &str, bool do_file,
|
||||
bool handle_as_special_cd) {
|
||||
expand_flags_t flags = EXPAND_SKIP_CMDSUBST | EXPAND_FOR_COMPLETIONS | this->expand_flags();
|
||||
expand_flags_t flags = this->expand_flags() | expand_flag::EXPAND_SKIP_CMDSUBST |
|
||||
expand_flag::EXPAND_FOR_COMPLETIONS;
|
||||
|
||||
if (!do_file) flags |= EXPAND_SKIP_WILDCARDS;
|
||||
if (!do_file) flags |= expand_flag::EXPAND_SKIP_WILDCARDS;
|
||||
|
||||
if (handle_as_special_cd && do_file) {
|
||||
if (this->type() == COMPLETE_AUTOSUGGEST) {
|
||||
flags |= EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST;
|
||||
flags |= expand_flag::EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST;
|
||||
}
|
||||
flags |= DIRECTORIES_ONLY | EXPAND_SPECIAL_FOR_CD | EXPAND_NO_DESCRIPTIONS;
|
||||
flags |= expand_flags_t{expand_flag::DIRECTORIES_ONLY, expand_flag::EXPAND_SPECIAL_FOR_CD,
|
||||
expand_flag::EXPAND_NO_DESCRIPTIONS};
|
||||
}
|
||||
|
||||
// Squelch file descriptions per issue #254.
|
||||
if (this->type() == COMPLETE_AUTOSUGGEST || do_file) flags |= EXPAND_NO_DESCRIPTIONS;
|
||||
if (this->type() == COMPLETE_AUTOSUGGEST || do_file)
|
||||
flags |= expand_flag::EXPAND_NO_DESCRIPTIONS;
|
||||
|
||||
// We have the following cases:
|
||||
//
|
||||
@ -1110,7 +1119,7 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file,
|
||||
if (complete_from_start) {
|
||||
// Don't do fuzzy matching for files if the string begins with a dash (issue #568). We could
|
||||
// consider relaxing this if there was a preceding double-dash argument.
|
||||
if (string_prefixes_string(L"-", str)) flags &= ~EXPAND_FUZZY_MATCH;
|
||||
if (string_prefixes_string(L"-", str)) flags.clear(expand_flag::EXPAND_FUZZY_MATCH);
|
||||
|
||||
if (expand_string(str, &this->completions, flags, vars, NULL) == expand_result_t::error) {
|
||||
debug(3, L"Error while expanding string '%ls'", str.c_str());
|
||||
|
@ -25,6 +25,7 @@ class enum_set_t : private std::bitset<enum_count<T>()> {
|
||||
static size_t index_of(T t) { return static_cast<size_t>(t); }
|
||||
|
||||
explicit enum_set_t(unsigned long raw) : super(raw) {}
|
||||
explicit enum_set_t(super sup) : super(sup) {}
|
||||
|
||||
public:
|
||||
enum_set_t() = default;
|
||||
@ -52,6 +53,32 @@ class enum_set_t : private std::bitset<enum_count<T>()> {
|
||||
bool operator==(const enum_set_t &rhs) const { return super::operator==(rhs); }
|
||||
|
||||
bool operator!=(const enum_set_t &rhs) const { return super::operator!=(rhs); }
|
||||
|
||||
/// OR in a single flag, returning a new set.
|
||||
enum_set_t operator|(T rhs) const {
|
||||
enum_set_t result = *this;
|
||||
result.set(rhs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Compute the union of two sets.
|
||||
enum_set_t operator|(enum_set_t rhs) const { return from_raw(to_raw() | rhs.to_raw()); }
|
||||
|
||||
/// OR in a single flag, modifying the set in place.
|
||||
enum_set_t operator|=(T rhs) {
|
||||
*this = *this | rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set this to the union of two sets.
|
||||
enum_set_t operator|=(enum_set_t rhs) {
|
||||
*this = *this | rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Test a value of a single flag. Note this does not return an enum_set_t; there is no such
|
||||
/// boolean conversion. This simply makes flags work more naturally as bit masks.
|
||||
bool operator&(T rhs) const { return get(rhs); }
|
||||
};
|
||||
|
||||
/// An array of Elem indexed by an enum class.
|
||||
|
@ -511,7 +511,7 @@ static expand_result_t expand_braces(const wcstring &instr, expand_flags_t flags
|
||||
}
|
||||
|
||||
if (brace_count > 0) {
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS)) {
|
||||
if (!(flags & expand_flag::EXPAND_FOR_COMPLETIONS)) {
|
||||
syntax_error = true;
|
||||
} else {
|
||||
// The user hasn't typed an end brace yet; make one up and append it, then expand
|
||||
@ -527,7 +527,7 @@ static expand_result_t expand_braces(const wcstring &instr, expand_flags_t flags
|
||||
}
|
||||
|
||||
// Note: this code looks very fishy, apparently it has never worked.
|
||||
return expand_braces(mod, 1, out, errors);
|
||||
return expand_braces(mod, expand_flag::EXPAND_SKIP_CMDSUBST, out, errors);
|
||||
}
|
||||
}
|
||||
|
||||
@ -898,7 +898,7 @@ class expander_t {
|
||||
};
|
||||
|
||||
expand_result_t expander_t::stage_cmdsubst(wcstring input, std::vector<completion_t> *out) {
|
||||
if (EXPAND_SKIP_CMDSUBST & flags) {
|
||||
if (flags & expand_flag::EXPAND_SKIP_CMDSUBST) {
|
||||
size_t cur = 0, start = 0, end;
|
||||
switch (parse_util_locate_cmdsubst_range(input, &cur, nullptr, &start, &end, true)) {
|
||||
case 0:
|
||||
@ -924,7 +924,7 @@ expand_result_t expander_t::stage_variables(wcstring input, std::vector<completi
|
||||
wcstring next;
|
||||
unescape_string(input, &next, UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE);
|
||||
|
||||
if (EXPAND_SKIP_VARIABLES & flags) {
|
||||
if (flags & expand_flag::EXPAND_SKIP_VARIABLES) {
|
||||
for (size_t i = 0; i < next.size(); i++) {
|
||||
if (next.at(i) == VARIABLE_EXPAND) {
|
||||
next[i] = L'$';
|
||||
@ -946,7 +946,7 @@ expand_result_t expander_t::stage_braces(wcstring input, std::vector<completion_
|
||||
}
|
||||
|
||||
expand_result_t expander_t::stage_home_and_self(wcstring input, std::vector<completion_t> *out) {
|
||||
if (!(EXPAND_SKIP_HOME_DIRECTORIES & flags)) {
|
||||
if (!(flags & expand_flag::EXPAND_SKIP_HOME_DIRECTORIES)) {
|
||||
expand_home_directory(input, vars);
|
||||
}
|
||||
expand_percent_self(input);
|
||||
@ -958,13 +958,14 @@ expand_result_t expander_t::stage_wildcards(wcstring path_to_expand,
|
||||
std::vector<completion_t> *out) {
|
||||
expand_result_t result = expand_result_t::ok;
|
||||
|
||||
remove_internal_separator(&path_to_expand, flags & EXPAND_SKIP_WILDCARDS);
|
||||
remove_internal_separator(&path_to_expand, flags & expand_flag::EXPAND_SKIP_WILDCARDS);
|
||||
const bool has_wildcard = wildcard_has(path_to_expand, true /* internal, i.e. ANY_STRING */);
|
||||
const bool for_completions = flags & expand_flag::EXPAND_FOR_COMPLETIONS;
|
||||
const bool skip_wildcards = flags & expand_flag::EXPAND_SKIP_WILDCARDS;
|
||||
|
||||
if (has_wildcard && (flags & EXECUTABLES_ONLY)) {
|
||||
if (has_wildcard && (flags & expand_flag::EXECUTABLES_ONLY)) {
|
||||
; // don't do wildcard expansion for executables, see issue #785
|
||||
} else if (((flags & EXPAND_FOR_COMPLETIONS) && (!(flags & EXPAND_SKIP_WILDCARDS))) ||
|
||||
has_wildcard) {
|
||||
} else if ((for_completions && !skip_wildcards) || has_wildcard) {
|
||||
// We either have a wildcard, or we don't have a wildcard but we're doing completion
|
||||
// expansion (so we want to get the completion of a file path). Note that if
|
||||
// EXPAND_SKIP_WILDCARDS is set, we stomped wildcards in remove_internal_separator above, so
|
||||
@ -974,8 +975,8 @@ expand_result_t expander_t::stage_wildcards(wcstring path_to_expand,
|
||||
// which may be CDPATH if the special flag is set.
|
||||
const wcstring working_dir = vars.get_pwd_slash();
|
||||
wcstring_list_t effective_working_dirs;
|
||||
bool for_cd = static_cast<bool>(flags & EXPAND_SPECIAL_FOR_CD);
|
||||
bool for_command = static_cast<bool>(flags & EXPAND_SPECIAL_FOR_COMMAND);
|
||||
bool for_cd = flags & expand_flag::EXPAND_SPECIAL_FOR_CD;
|
||||
bool for_command = flags & expand_flag::EXPAND_SPECIAL_FOR_COMMAND;
|
||||
if (!for_cd && !for_command) {
|
||||
// Common case.
|
||||
effective_working_dirs.push_back(working_dir);
|
||||
@ -1038,7 +1039,7 @@ expand_result_t expander_t::stage_wildcards(wcstring path_to_expand,
|
||||
// Can't fully justify this check. I think it's that SKIP_WILDCARDS is used when completing
|
||||
// to mean don't do file expansions, so if we're not doing file expansions, just drop this
|
||||
// completion on the floor.
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS)) {
|
||||
if (!(flags & expand_flag::EXPAND_FOR_COMPLETIONS)) {
|
||||
append_completion(out, std::move(path_to_expand));
|
||||
}
|
||||
}
|
||||
@ -1050,7 +1051,7 @@ expand_result_t expander_t::expand_string(wcstring input,
|
||||
expand_flags_t flags, const environment_t &vars,
|
||||
parse_error_list_t *errors) {
|
||||
// Early out. If we're not completing, and there's no magic in the input, we're done.
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS) && expand_is_clean(input)) {
|
||||
if (!(flags & expand_flag::EXPAND_FOR_COMPLETIONS) && expand_is_clean(input)) {
|
||||
append_completion(out_completions, std::move(input));
|
||||
return expand_result_t::ok;
|
||||
}
|
||||
@ -1092,7 +1093,7 @@ expand_result_t expander_t::expand_string(wcstring input,
|
||||
|
||||
if (total_result != expand_result_t::error) {
|
||||
// Hack to un-expand tildes (see #647).
|
||||
if (!(flags & EXPAND_SKIP_HOME_DIRECTORIES)) {
|
||||
if (!(flags & expand_flag::EXPAND_SKIP_HOME_DIRECTORIES)) {
|
||||
unexpand_tildes(input, vars, &completions);
|
||||
}
|
||||
out_completions->insert(out_completions->end(),
|
||||
@ -1113,12 +1114,12 @@ bool expand_one(wcstring &string, expand_flags_t flags, const environment_t &var
|
||||
parse_error_list_t *errors) {
|
||||
std::vector<completion_t> completions;
|
||||
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS) && expand_is_clean(string)) {
|
||||
if (!flags.get(expand_flag::EXPAND_FOR_COMPLETIONS) && expand_is_clean(string)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, vars, errors) !=
|
||||
expand_result_t::error &&
|
||||
if (expand_string(string, &completions, flags | expand_flag::EXPAND_NO_DESCRIPTIONS, vars,
|
||||
errors) != expand_result_t::error &&
|
||||
completions.size() == 1) {
|
||||
string = std::move(completions.at(0).completion);
|
||||
return true;
|
||||
@ -1137,9 +1138,11 @@ expand_result_t expand_to_command_and_args(const wcstring &instr, const environm
|
||||
}
|
||||
|
||||
std::vector<completion_t> completions;
|
||||
expand_result_t expand_err = expand_string(
|
||||
instr, &completions, EXPAND_SKIP_CMDSUBST | EXPAND_NO_DESCRIPTIONS | EXPAND_SKIP_JOBS, vars,
|
||||
errors);
|
||||
expand_result_t expand_err =
|
||||
expand_string(instr, &completions,
|
||||
{expand_flag::EXPAND_SKIP_CMDSUBST, expand_flag::EXPAND_NO_DESCRIPTIONS,
|
||||
expand_flag::EXPAND_SKIP_JOBS},
|
||||
vars, errors);
|
||||
if (expand_err == expand_result_t::ok || expand_err == expand_result_t::wildcard_match) {
|
||||
// The first completion is the command, any remaning are arguments.
|
||||
bool first = true;
|
||||
|
41
src/expand.h
41
src/expand.h
@ -14,6 +14,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
#include "enum_set.h"
|
||||
#include "maybe.h"
|
||||
#include "parse_constants.h"
|
||||
|
||||
@ -21,43 +22,51 @@ class environment_t;
|
||||
class env_var_t;
|
||||
class environment_t;
|
||||
|
||||
enum {
|
||||
enum class expand_flag {
|
||||
/// Flag specifying that cmdsubst expansion should be skipped.
|
||||
EXPAND_SKIP_CMDSUBST = 1 << 0,
|
||||
EXPAND_SKIP_CMDSUBST,
|
||||
/// Flag specifying that variable expansion should be skipped.
|
||||
EXPAND_SKIP_VARIABLES = 1 << 1,
|
||||
EXPAND_SKIP_VARIABLES,
|
||||
/// Flag specifying that wildcard expansion should be skipped.
|
||||
EXPAND_SKIP_WILDCARDS = 1 << 2,
|
||||
EXPAND_SKIP_WILDCARDS,
|
||||
/// The expansion is being done for tab or auto completions. Returned completions may have the
|
||||
/// wildcard as a prefix instead of a match.
|
||||
EXPAND_FOR_COMPLETIONS = 1 << 3,
|
||||
EXPAND_FOR_COMPLETIONS,
|
||||
/// Only match files that are executable by the current user.
|
||||
EXECUTABLES_ONLY = 1 << 4,
|
||||
EXECUTABLES_ONLY,
|
||||
/// Only match directories.
|
||||
DIRECTORIES_ONLY = 1 << 5,
|
||||
DIRECTORIES_ONLY,
|
||||
/// Don't generate descriptions.
|
||||
EXPAND_NO_DESCRIPTIONS = 1 << 6,
|
||||
EXPAND_NO_DESCRIPTIONS,
|
||||
/// Don't expand jobs (but you can still expand processes). This is because
|
||||
/// job expansion is not thread safe.
|
||||
EXPAND_SKIP_JOBS = 1 << 7,
|
||||
EXPAND_SKIP_JOBS,
|
||||
/// Don't expand home directories.
|
||||
EXPAND_SKIP_HOME_DIRECTORIES = 1 << 8,
|
||||
EXPAND_SKIP_HOME_DIRECTORIES,
|
||||
/// Allow fuzzy matching.
|
||||
EXPAND_FUZZY_MATCH = 1 << 9,
|
||||
EXPAND_FUZZY_MATCH,
|
||||
/// Disallow directory abbreviations like /u/l/b for /usr/local/bin. Only applicable if
|
||||
/// EXPAND_FUZZY_MATCH is set.
|
||||
EXPAND_NO_FUZZY_DIRECTORIES = 1 << 10,
|
||||
EXPAND_NO_FUZZY_DIRECTORIES,
|
||||
/// Do expansions specifically to support cd. This means using CDPATH as a list of potential
|
||||
/// working directories, and to use logical instead of physical paths.
|
||||
EXPAND_SPECIAL_FOR_CD = 1 << 11,
|
||||
EXPAND_SPECIAL_FOR_CD,
|
||||
/// Do expansions specifically for cd autosuggestion. This is to differentiate between cd
|
||||
/// completions and cd autosuggestions.
|
||||
EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST = 1 << 12,
|
||||
EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST,
|
||||
/// Do expansions specifically to support external command completions. This means using PATH as
|
||||
/// a list of potential working directories.
|
||||
EXPAND_SPECIAL_FOR_COMMAND = 1 << 13
|
||||
EXPAND_SPECIAL_FOR_COMMAND,
|
||||
|
||||
COUNT,
|
||||
};
|
||||
typedef int expand_flags_t;
|
||||
|
||||
template <>
|
||||
struct enum_info_t<expand_flag> {
|
||||
static constexpr auto count = expand_flag::COUNT;
|
||||
};
|
||||
|
||||
using expand_flags_t = enum_set_t<expand_flag>;
|
||||
|
||||
class completion_t;
|
||||
|
||||
|
@ -305,6 +305,10 @@ static void test_enum_set() {
|
||||
do_test(es != enum_set_t<test_enum>::from_raw(1));
|
||||
|
||||
es.set(test_enum::beta);
|
||||
do_test(es.get(test_enum::beta));
|
||||
do_test(!es.get(test_enum::alpha));
|
||||
do_test(es & test_enum::beta);
|
||||
do_test(!(es & test_enum::alpha));
|
||||
do_test(es.to_raw() == 2);
|
||||
do_test(es == enum_set_t<test_enum>::from_raw(2));
|
||||
do_test(es == enum_set_t<test_enum>{test_enum::beta});
|
||||
@ -312,6 +316,10 @@ static void test_enum_set() {
|
||||
do_test(es.any());
|
||||
do_test(!es.none());
|
||||
|
||||
do_test((enum_set_t<test_enum>{test_enum::beta} | test_enum::alpha).to_raw() == 3);
|
||||
do_test((enum_set_t<test_enum>{test_enum::beta} | enum_set_t<test_enum>{test_enum::alpha})
|
||||
.to_raw() == 3);
|
||||
|
||||
unsigned idx = 0;
|
||||
for (auto v : enum_iter_t<test_enum>{}) {
|
||||
do_test(static_cast<unsigned>(v) == idx);
|
||||
@ -970,7 +978,8 @@ static void test_parser() {
|
||||
|
||||
say(L"Testing eval_args");
|
||||
completion_list_t comps;
|
||||
parser_t::expand_argument_list(L"alpha 'beta gamma' delta", 0, null_environment_t{}, &comps);
|
||||
parser_t::expand_argument_list(L"alpha 'beta gamma' delta", expand_flags_t{},
|
||||
null_environment_t{}, &comps);
|
||||
do_test(comps.size() == 3);
|
||||
do_test(comps.at(0).completion == L"alpha");
|
||||
do_test(comps.at(1).completion == L"beta gamma");
|
||||
@ -1656,13 +1665,15 @@ static bool expand_test(const wchar_t *in, expand_flags_t flags, ...) {
|
||||
/// Test globbing and other parameter expansion.
|
||||
static void test_expand() {
|
||||
say(L"Testing parameter expansion");
|
||||
const expand_flags_t noflags{};
|
||||
|
||||
expand_test(L"foo", 0, L"foo", 0, L"Strings do not expand to themselves");
|
||||
expand_test(L"a{b,c,d}e", 0, L"abe", L"ace", L"ade", 0, L"Bracket expansion is broken");
|
||||
expand_test(L"a*", EXPAND_SKIP_WILDCARDS, L"a*", 0, L"Cannot skip wildcard expansion");
|
||||
expand_test(L"/bin/l\\0", EXPAND_FOR_COMPLETIONS, 0,
|
||||
expand_test(L"foo", noflags, L"foo", 0, L"Strings do not expand to themselves");
|
||||
expand_test(L"a{b,c,d}e", noflags, L"abe", L"ace", L"ade", 0, L"Bracket expansion is broken");
|
||||
expand_test(L"a*", expand_flag::EXPAND_SKIP_WILDCARDS, L"a*", 0,
|
||||
L"Cannot skip wildcard expansion");
|
||||
expand_test(L"/bin/l\\0", expand_flag::EXPAND_FOR_COMPLETIONS, 0,
|
||||
L"Failed to handle null escape in expansion");
|
||||
expand_test(L"foo\\$bar", EXPAND_SKIP_VARIABLES, L"foo$bar", 0,
|
||||
expand_test(L"foo\\$bar", expand_flag::EXPAND_SKIP_VARIABLES, L"foo$bar", 0,
|
||||
L"Failed to handle dollar sign in variable-skipping expansion");
|
||||
|
||||
// bb
|
||||
@ -1700,89 +1711,91 @@ static void test_expand() {
|
||||
// (https://github.com/fish-shell/fish-shell/issues/270). But it does have to match literal
|
||||
// components (e.g. "./*" has to match the same as "*".
|
||||
const wchar_t *const wnull = NULL;
|
||||
expand_test(L"test/fish_expand_test/.*", 0, L"test/fish_expand_test/.foo", wnull,
|
||||
expand_test(L"test/fish_expand_test/.*", noflags, L"test/fish_expand_test/.foo", wnull,
|
||||
L"Expansion not correctly handling dotfiles");
|
||||
|
||||
expand_test(L"test/fish_expand_test/./.*", 0, L"test/fish_expand_test/./.foo", wnull,
|
||||
expand_test(L"test/fish_expand_test/./.*", noflags, L"test/fish_expand_test/./.foo", wnull,
|
||||
L"Expansion not correctly handling literal path components in dotfiles");
|
||||
|
||||
expand_test(L"test/fish_expand_test/*/xxx", 0, L"test/fish_expand_test/bax/xxx",
|
||||
expand_test(L"test/fish_expand_test/*/xxx", noflags, L"test/fish_expand_test/bax/xxx",
|
||||
L"test/fish_expand_test/baz/xxx", wnull, L"Glob did the wrong thing 1");
|
||||
|
||||
expand_test(L"test/fish_expand_test/*z/xxx", 0, L"test/fish_expand_test/baz/xxx", wnull,
|
||||
expand_test(L"test/fish_expand_test/*z/xxx", noflags, L"test/fish_expand_test/baz/xxx", wnull,
|
||||
L"Glob did the wrong thing 2");
|
||||
|
||||
expand_test(L"test/fish_expand_test/**z/xxx", 0, L"test/fish_expand_test/baz/xxx", wnull,
|
||||
expand_test(L"test/fish_expand_test/**z/xxx", noflags, L"test/fish_expand_test/baz/xxx", wnull,
|
||||
L"Glob did the wrong thing 3");
|
||||
|
||||
expand_test(L"test/fish_expand_test////baz/xxx", 0, L"test/fish_expand_test////baz/xxx", wnull,
|
||||
L"Glob did the wrong thing 3");
|
||||
expand_test(L"test/fish_expand_test////baz/xxx", noflags, L"test/fish_expand_test////baz/xxx",
|
||||
wnull, L"Glob did the wrong thing 3");
|
||||
|
||||
expand_test(L"test/fish_expand_test/b**", 0, L"test/fish_expand_test/bb",
|
||||
expand_test(L"test/fish_expand_test/b**", noflags, L"test/fish_expand_test/bb",
|
||||
L"test/fish_expand_test/bb/x", L"test/fish_expand_test/bar",
|
||||
L"test/fish_expand_test/bax", L"test/fish_expand_test/bax/xxx",
|
||||
L"test/fish_expand_test/baz", L"test/fish_expand_test/baz/xxx",
|
||||
L"test/fish_expand_test/baz/yyy", wnull, L"Glob did the wrong thing 4");
|
||||
|
||||
// A trailing slash should only produce directories.
|
||||
expand_test(L"test/fish_expand_test/b*/", 0, L"test/fish_expand_test/bb/",
|
||||
expand_test(L"test/fish_expand_test/b*/", noflags, L"test/fish_expand_test/bb/",
|
||||
L"test/fish_expand_test/baz/", L"test/fish_expand_test/bax/", wnull,
|
||||
L"Glob did the wrong thing 5");
|
||||
|
||||
expand_test(L"test/fish_expand_test/b**/", 0, L"test/fish_expand_test/bb/",
|
||||
expand_test(L"test/fish_expand_test/b**/", noflags, L"test/fish_expand_test/bb/",
|
||||
L"test/fish_expand_test/baz/", L"test/fish_expand_test/bax/", wnull,
|
||||
L"Glob did the wrong thing 6");
|
||||
|
||||
expand_test(L"test/fish_expand_test/**/q", 0, L"test/fish_expand_test/lol/nub/q", wnull,
|
||||
expand_test(L"test/fish_expand_test/**/q", noflags, L"test/fish_expand_test/lol/nub/q", wnull,
|
||||
L"Glob did the wrong thing 7");
|
||||
|
||||
expand_test(L"test/fish_expand_test/BA", EXPAND_FOR_COMPLETIONS, L"test/fish_expand_test/bar",
|
||||
L"test/fish_expand_test/bax/", L"test/fish_expand_test/baz/", wnull,
|
||||
L"Case insensitive test did the wrong thing");
|
||||
expand_test(L"test/fish_expand_test/BA", expand_flag::EXPAND_FOR_COMPLETIONS,
|
||||
L"test/fish_expand_test/bar", L"test/fish_expand_test/bax/",
|
||||
L"test/fish_expand_test/baz/", wnull, L"Case insensitive test did the wrong thing");
|
||||
|
||||
expand_test(L"test/fish_expand_test/BA", EXPAND_FOR_COMPLETIONS, L"test/fish_expand_test/bar",
|
||||
L"test/fish_expand_test/bax/", L"test/fish_expand_test/baz/", wnull,
|
||||
L"Case insensitive test did the wrong thing");
|
||||
expand_test(L"test/fish_expand_test/BA", expand_flag::EXPAND_FOR_COMPLETIONS,
|
||||
L"test/fish_expand_test/bar", L"test/fish_expand_test/bax/",
|
||||
L"test/fish_expand_test/baz/", wnull, L"Case insensitive test did the wrong thing");
|
||||
|
||||
expand_test(L"test/fish_expand_test/bb/yyy", EXPAND_FOR_COMPLETIONS,
|
||||
expand_test(L"test/fish_expand_test/bb/yyy", expand_flag::EXPAND_FOR_COMPLETIONS,
|
||||
/* nothing! */ wnull, L"Wrong fuzzy matching 1");
|
||||
|
||||
expand_test(L"test/fish_expand_test/bb/x", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH, L"",
|
||||
wnull, // we just expect the empty string since this is an exact match
|
||||
L"Wrong fuzzy matching 2");
|
||||
expand_test(
|
||||
L"test/fish_expand_test/bb/x",
|
||||
expand_flags_t{expand_flag::EXPAND_FOR_COMPLETIONS, expand_flag::EXPAND_FUZZY_MATCH}, L"",
|
||||
wnull, // we just expect the empty string since this is an exact match
|
||||
L"Wrong fuzzy matching 2");
|
||||
|
||||
// Some vswprintfs refuse to append ANY_STRING in a format specifiers, so don't use
|
||||
// format_string here.
|
||||
const expand_flags_t fuzzy_comp{expand_flag::EXPAND_FOR_COMPLETIONS,
|
||||
expand_flag::EXPAND_FUZZY_MATCH};
|
||||
const wcstring any_str_str(1, ANY_STRING);
|
||||
expand_test(L"test/fish_expand_test/b/xx*", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH,
|
||||
expand_test(L"test/fish_expand_test/b/xx*", fuzzy_comp,
|
||||
(L"test/fish_expand_test/bax/xx" + any_str_str).c_str(),
|
||||
(L"test/fish_expand_test/baz/xx" + any_str_str).c_str(), wnull,
|
||||
L"Wrong fuzzy matching 3");
|
||||
|
||||
expand_test(L"test/fish_expand_test/b/yyy", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH,
|
||||
L"test/fish_expand_test/baz/yyy", wnull, L"Wrong fuzzy matching 4");
|
||||
expand_test(L"test/fish_expand_test/b/yyy", fuzzy_comp, L"test/fish_expand_test/baz/yyy", wnull,
|
||||
L"Wrong fuzzy matching 4");
|
||||
|
||||
expand_test(L"test/fish_expand_test/aa/x", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH,
|
||||
L"test/fish_expand_test/aaa2/x", wnull, L"Wrong fuzzy matching 5");
|
||||
expand_test(L"test/fish_expand_test/aa/x", fuzzy_comp, L"test/fish_expand_test/aaa2/x", wnull,
|
||||
L"Wrong fuzzy matching 5");
|
||||
|
||||
expand_test(L"test/fish_expand_test/aaa/x", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH, wnull,
|
||||
expand_test(L"test/fish_expand_test/aaa/x", fuzzy_comp, wnull,
|
||||
L"Wrong fuzzy matching 6 - shouldn't remove valid directory names (#3211)");
|
||||
|
||||
if (!expand_test(L"test/fish_expand_test/.*", 0, L"test/fish_expand_test/.foo", 0)) {
|
||||
if (!expand_test(L"test/fish_expand_test/.*", noflags, L"test/fish_expand_test/.foo", 0)) {
|
||||
err(L"Expansion not correctly handling dotfiles");
|
||||
}
|
||||
if (!expand_test(L"test/fish_expand_test/./.*", 0, L"test/fish_expand_test/./.foo", 0)) {
|
||||
if (!expand_test(L"test/fish_expand_test/./.*", noflags, L"test/fish_expand_test/./.foo", 0)) {
|
||||
err(L"Expansion not correctly handling literal path components in dotfiles");
|
||||
}
|
||||
|
||||
if (!pushd("test/fish_expand_test")) return;
|
||||
|
||||
expand_test(L"b/xx", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH, L"bax/xxx", L"baz/xxx", wnull,
|
||||
L"Wrong fuzzy matching 5");
|
||||
expand_test(L"b/xx", fuzzy_comp, L"bax/xxx", L"baz/xxx", wnull, L"Wrong fuzzy matching 5");
|
||||
|
||||
// multiple slashes with fuzzy matching - #3185
|
||||
expand_test(L"l///n", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH, L"lol///nub/", wnull,
|
||||
L"Wrong fuzzy matching 6");
|
||||
expand_test(L"l///n", fuzzy_comp, L"lol///nub/", wnull, L"Wrong fuzzy matching 6");
|
||||
|
||||
popd();
|
||||
}
|
||||
@ -2255,7 +2268,7 @@ static bool run_test_test(int expected, const wcstring &str) {
|
||||
|
||||
// We need to tokenize the string in the same manner a normal shell would do. This is because we
|
||||
// need to test things like quoted strings that have leading and trailing whitespace.
|
||||
parser_t::expand_argument_list(str, 0, null_environment_t{}, &comps);
|
||||
parser_t::expand_argument_list(str, expand_flags_t{}, null_environment_t{}, &comps);
|
||||
for (completion_list_t::const_iterator it = comps.begin(), end = comps.end(); it != end; ++it) {
|
||||
argv.push_back(it->completion);
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ bool autosuggest_validate_from_history(const history_item_t &item,
|
||||
|
||||
if (parsed_command == L"cd" && !cd_dir.empty()) {
|
||||
// We can possibly handle this specially.
|
||||
if (expand_one(cd_dir, EXPAND_SKIP_CMDSUBST, vars)) {
|
||||
if (expand_one(cd_dir, expand_flag::EXPAND_SKIP_CMDSUBST, vars)) {
|
||||
handled = true;
|
||||
bool is_help =
|
||||
string_prefixes_string(cd_dir, L"--help") || string_prefixes_string(cd_dir, L"-h");
|
||||
@ -926,7 +926,7 @@ void highlighter_t::color_arguments(const std::vector<tnode_t<g::argument>> &arg
|
||||
if (cmd_is_cd) {
|
||||
// Mark this as an error if it's not 'help' and not a valid cd path.
|
||||
wcstring param = arg.get_source(this->buff);
|
||||
if (expand_one(param, EXPAND_SKIP_CMDSUBST, vars)) {
|
||||
if (expand_one(param, expand_flag::EXPAND_SKIP_CMDSUBST, vars)) {
|
||||
bool is_help = string_prefixes_string(param, L"--help") ||
|
||||
string_prefixes_string(param, L"-h");
|
||||
if (!is_help && this->io_ok &&
|
||||
@ -969,7 +969,7 @@ void highlighter_t::color_redirection(tnode_t<g::redirection> redirection_node)
|
||||
// I/O is disallowed, so we don't have much hope of catching anything but gross
|
||||
// errors. Assume it's valid.
|
||||
target_is_valid = true;
|
||||
} else if (!expand_one(target, EXPAND_SKIP_CMDSUBST, vars)) {
|
||||
} else if (!expand_one(target, expand_flag::EXPAND_SKIP_CMDSUBST, vars)) {
|
||||
// Could not be expanded.
|
||||
target_is_valid = false;
|
||||
} else {
|
||||
|
@ -127,7 +127,10 @@ tnode_t<g::plain_statement> parse_execution_context_t::infinite_recursive_statem
|
||||
.try_get_child<g::plain_statement, 0>();
|
||||
if (plain_statement) {
|
||||
maybe_t<wcstring> cmd = command_for_plain_statement(plain_statement, pstree->src);
|
||||
if (cmd && expand_one(*cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES, nullenv) &&
|
||||
if (cmd &&
|
||||
expand_one(*cmd,
|
||||
{expand_flag::EXPAND_SKIP_CMDSUBST, expand_flag::EXPAND_SKIP_VARIABLES},
|
||||
nullenv) &&
|
||||
cmd == forbidden_function_name) {
|
||||
// This is it.
|
||||
infinite_recursive_statement = plain_statement;
|
||||
@ -376,7 +379,7 @@ parse_execution_result_t parse_execution_context_t::run_for_statement(
|
||||
// in just one.
|
||||
tnode_t<g::tok_string> var_name_node = header.child<1>();
|
||||
wcstring for_var_name = get_source(var_name_node);
|
||||
if (!expand_one(for_var_name, 0, parser->vars())) {
|
||||
if (!expand_one(for_var_name, expand_flags_t{}, parser->vars())) {
|
||||
report_error(var_name_node, FAILED_EXPANSION_VARIABLE_NAME_ERR_MSG, for_var_name.c_str());
|
||||
return parse_execution_errored;
|
||||
}
|
||||
@ -449,8 +452,8 @@ parse_execution_result_t parse_execution_context_t::run_switch_statement(
|
||||
// Expand it. We need to offset any errors by the position of the string.
|
||||
std::vector<completion_t> switch_values_expanded;
|
||||
parse_error_list_t errors;
|
||||
auto expand_ret = expand_string(switch_value, &switch_values_expanded, EXPAND_NO_DESCRIPTIONS,
|
||||
parser->vars(), &errors);
|
||||
auto expand_ret = expand_string(switch_value, &switch_values_expanded,
|
||||
expand_flag::EXPAND_NO_DESCRIPTIONS, parser->vars(), &errors);
|
||||
parse_error_offset_source_start(&errors, switch_value_n.source_range()->start);
|
||||
|
||||
switch (expand_ret) {
|
||||
@ -906,8 +909,8 @@ parse_execution_result_t parse_execution_context_t::expand_arguments_from_nodes(
|
||||
// Expand this string.
|
||||
parse_error_list_t errors;
|
||||
arg_expanded.clear();
|
||||
auto expand_ret =
|
||||
expand_string(arg_str, &arg_expanded, EXPAND_NO_DESCRIPTIONS, parser->vars(), &errors);
|
||||
auto expand_ret = expand_string(arg_str, &arg_expanded, expand_flag::EXPAND_NO_DESCRIPTIONS,
|
||||
parser->vars(), &errors);
|
||||
parse_error_offset_source_start(&errors, arg_node.source_range()->start);
|
||||
switch (expand_ret) {
|
||||
case expand_result_t::error: {
|
||||
@ -956,7 +959,8 @@ bool parse_execution_context_t::determine_io_chain(tnode_t<g::arguments_or_redir
|
||||
|
||||
// PCA: I can't justify this EXPAND_SKIP_VARIABLES flag. It was like this when I got here.
|
||||
bool target_expanded =
|
||||
expand_one(target, no_exec ? EXPAND_SKIP_VARIABLES : 0, parser->vars());
|
||||
expand_one(target, no_exec ? expand_flag::EXPAND_SKIP_VARIABLES : expand_flags_t{},
|
||||
parser->vars());
|
||||
if (!target_expanded || target.empty()) {
|
||||
// TODO: Improve this error message.
|
||||
errored =
|
||||
|
@ -1197,7 +1197,7 @@ static bool detect_errors_in_plain_statement(const wcstring &buff_src,
|
||||
|
||||
// Check that we don't do an invalid builtin (issue #1252).
|
||||
if (!errored && decoration == parse_statement_decoration_builtin &&
|
||||
expand_one(*unexp_command, 0, null_environment_t{}, parse_errors) &&
|
||||
expand_one(*unexp_command, expand_flags_t{}, null_environment_t{}, parse_errors) &&
|
||||
!builtin_exists(*unexp_command)) {
|
||||
errored = append_syntax_error(parse_errors, source_start, UNKNOWN_BUILTIN_ERR_MSG,
|
||||
unexp_command->c_str());
|
||||
|
@ -167,7 +167,7 @@ static wcstring resolve_description(const wcstring &full_completion, wcstring *c
|
||||
completion->resize(complete_sep_loc);
|
||||
return description;
|
||||
}
|
||||
if (expand_flags & EXPAND_NO_DESCRIPTIONS) return {};
|
||||
if (expand_flags & expand_flag::EXPAND_NO_DESCRIPTIONS) return {};
|
||||
return desc_func ? desc_func(full_completion) : wcstring{};
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ static bool wildcard_complete_internal(const wchar_t *str, const wchar_t *wc,
|
||||
|
||||
// If we're allowing fuzzy match, any match is OK. Otherwise we require a prefix match.
|
||||
bool match_acceptable;
|
||||
if (params.expand_flags & EXPAND_FUZZY_MATCH) {
|
||||
if (params.expand_flags & expand_flag::EXPAND_FUZZY_MATCH) {
|
||||
match_acceptable = match.type != fuzzy_match_none;
|
||||
} else {
|
||||
match_acceptable = match_type_shares_prefix(match.type);
|
||||
@ -415,12 +415,12 @@ static bool wildcard_test_flags_then_complete(const wcstring &filepath, const wc
|
||||
const bool is_directory = stat_res == 0 && S_ISDIR(stat_buf.st_mode);
|
||||
const bool is_executable = stat_res == 0 && S_ISREG(stat_buf.st_mode);
|
||||
|
||||
const bool need_directory = expand_flags & DIRECTORIES_ONLY;
|
||||
const bool need_directory = expand_flags & expand_flag::DIRECTORIES_ONLY;
|
||||
if (need_directory && !is_directory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool executables_only = expand_flags & EXECUTABLES_ONLY;
|
||||
const bool executables_only = expand_flags & expand_flag::EXECUTABLES_ONLY;
|
||||
if (executables_only && (!is_executable || waccess(filepath, X_OK) != 0)) {
|
||||
return false;
|
||||
}
|
||||
@ -432,7 +432,7 @@ static bool wildcard_test_flags_then_complete(const wcstring &filepath, const wc
|
||||
|
||||
// Compute the description.
|
||||
wcstring desc;
|
||||
if (!(expand_flags & EXPAND_NO_DESCRIPTIONS)) {
|
||||
if (!(expand_flags & expand_flag::EXPAND_NO_DESCRIPTIONS)) {
|
||||
desc = file_get_desc(filepath, lstat_res, lstat_buf, stat_res, stat_buf, stat_errno);
|
||||
|
||||
if (file_size >= 0) {
|
||||
@ -507,8 +507,7 @@ class wildcard_expander_t {
|
||||
|
||||
void add_expansion_result(const wcstring &result) {
|
||||
// This function is only for the non-completions case.
|
||||
assert(!static_cast<bool>(this->flags &
|
||||
EXPAND_FOR_COMPLETIONS)); //!OCLINT(multiple unary operator)
|
||||
assert(!(this->flags & expand_flag::EXPAND_FOR_COMPLETIONS));
|
||||
if (this->completion_set.insert(result).second) {
|
||||
append_completion(this->resolved_completions, result);
|
||||
this->did_add = true;
|
||||
@ -569,13 +568,13 @@ class wildcard_expander_t {
|
||||
void try_add_completion_result(const wcstring &filepath, const wcstring &filename,
|
||||
const wcstring &wildcard, const wcstring &prefix) {
|
||||
// This function is only for the completions case.
|
||||
assert(this->flags & EXPAND_FOR_COMPLETIONS);
|
||||
assert(this->flags & expand_flag::EXPAND_FOR_COMPLETIONS);
|
||||
|
||||
wcstring abs_path = this->working_directory;
|
||||
append_path_component(abs_path, filepath);
|
||||
|
||||
// We must normalize the path to allow 'cd ..' to operate on logical paths.
|
||||
if (flags & EXPAND_SPECIAL_FOR_CD) abs_path = normalize_path(abs_path);
|
||||
if (flags & expand_flag::EXPAND_SPECIAL_FOR_CD) abs_path = normalize_path(abs_path);
|
||||
|
||||
size_t before = this->resolved_completions->size();
|
||||
if (wildcard_test_flags_then_complete(abs_path, filename, wildcard.c_str(), this->flags,
|
||||
@ -597,7 +596,7 @@ class wildcard_expander_t {
|
||||
// hierarchy we can, and then appending any components to each new result.
|
||||
// Only descend deepest unique for cd autosuggest and not for cd tab completion
|
||||
// (issue #4402).
|
||||
if (flags & EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST) {
|
||||
if (flags & expand_flag::EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST) {
|
||||
wcstring unique_hierarchy = this->descend_unique_hierarchy(abs_path);
|
||||
if (!unique_hierarchy.empty()) {
|
||||
for (size_t i = before; i < after; i++) {
|
||||
@ -615,7 +614,7 @@ class wildcard_expander_t {
|
||||
DIR *open_dir(const wcstring &base_dir) const {
|
||||
wcstring path = this->working_directory;
|
||||
append_path_component(path, base_dir);
|
||||
if (flags & EXPAND_SPECIAL_FOR_CD) {
|
||||
if (flags & expand_flag::EXPAND_SPECIAL_FOR_CD) {
|
||||
// cd operates on logical paths.
|
||||
// for example, cd ../<tab> should complete "without resolving symlinks".
|
||||
path = normalize_path(path);
|
||||
@ -661,7 +660,7 @@ void wildcard_expander_t::expand_trailing_slash(const wcstring &base_dir, const
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(flags & EXPAND_FOR_COMPLETIONS)) {
|
||||
if (!(flags & expand_flag::EXPAND_FOR_COMPLETIONS)) {
|
||||
// Trailing slash and not accepting incomplete, e.g. `echo /xyz/`. Insert this file if it
|
||||
// exists.
|
||||
if (waccess(base_dir, F_OK) == 0) {
|
||||
@ -784,7 +783,7 @@ void wildcard_expander_t::expand_last_segment(const wcstring &base_dir, DIR *bas
|
||||
const wcstring &wc, const wcstring &prefix) {
|
||||
wcstring name_str;
|
||||
while (wreaddir(base_dir_fp, name_str)) {
|
||||
if (flags & EXPAND_FOR_COMPLETIONS) {
|
||||
if (flags & expand_flag::EXPAND_FOR_COMPLETIONS) {
|
||||
this->try_add_completion_result(base_dir + name_str, name_str, wc, prefix);
|
||||
} else {
|
||||
// Normal wildcard expansion, not for completions.
|
||||
@ -855,11 +854,11 @@ void wildcard_expander_t::expand(const wcstring &base_dir, const wchar_t *wc,
|
||||
// Maybe try a fuzzy match (#94) if nothing was found with the literal match. Respect
|
||||
// EXPAND_NO_DIRECTORY_ABBREVIATIONS (issue #2413).
|
||||
// Don't do fuzzy matches if the literal segment was valid (#3211)
|
||||
bool allow_fuzzy = (this->flags & (EXPAND_FUZZY_MATCH | EXPAND_NO_FUZZY_DIRECTORIES)) ==
|
||||
EXPAND_FUZZY_MATCH;
|
||||
bool allow_fuzzy = this->flags.get(expand_flag::EXPAND_FUZZY_MATCH) &&
|
||||
!this->flags.get(expand_flag::EXPAND_NO_FUZZY_DIRECTORIES);
|
||||
if (allow_fuzzy && this->resolved_completions->size() == before &&
|
||||
waccess(intermediate_dirpath, F_OK) != 0) {
|
||||
assert(this->flags & EXPAND_FOR_COMPLETIONS);
|
||||
assert(this->flags & expand_flag::EXPAND_FOR_COMPLETIONS);
|
||||
DIR *base_dir_fd = open_dir(base_dir);
|
||||
if (base_dir_fd != NULL) {
|
||||
this->expand_literal_intermediate_segment_with_fuzz(
|
||||
@ -905,13 +904,15 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &working_directory
|
||||
expand_flags_t flags, std::vector<completion_t> *output) {
|
||||
assert(output != NULL);
|
||||
// Fuzzy matching only if we're doing completions.
|
||||
assert((flags & (EXPAND_FUZZY_MATCH | EXPAND_FOR_COMPLETIONS)) != EXPAND_FUZZY_MATCH);
|
||||
assert(flags.get(expand_flag::EXPAND_FOR_COMPLETIONS) ||
|
||||
!flags.get(expand_flag::EXPAND_FUZZY_MATCH));
|
||||
|
||||
// EXPAND_SPECIAL_FOR_CD requires DIRECTORIES_ONLY and EXPAND_FOR_COMPLETIONS and
|
||||
// EXPAND_NO_DESCRIPTIONS.
|
||||
assert(!(flags & EXPAND_SPECIAL_FOR_CD) ||
|
||||
((flags & DIRECTORIES_ONLY) && (flags & EXPAND_FOR_COMPLETIONS) &&
|
||||
(flags & EXPAND_NO_DESCRIPTIONS)));
|
||||
// expand_flag::EXPAND_SPECIAL_FOR_CD requires expand_flag::DIRECTORIES_ONLY and
|
||||
// expand_flag::EXPAND_FOR_COMPLETIONS and expand_flag::EXPAND_NO_DESCRIPTIONS.
|
||||
assert(!(flags.get(expand_flag::EXPAND_SPECIAL_FOR_CD)) ||
|
||||
((flags.get(expand_flag::DIRECTORIES_ONLY)) &&
|
||||
(flags.get(expand_flag::EXPAND_FOR_COMPLETIONS)) &&
|
||||
(flags.get(expand_flag::EXPAND_NO_DESCRIPTIONS))));
|
||||
|
||||
// Hackish fix for issue #1631. We are about to call c_str(), which will produce a string
|
||||
// truncated at any embedded nulls. We could fix this by passing around the size, etc. However
|
||||
|
Loading…
x
Reference in New Issue
Block a user