Fix overzealous cd tab completion

Changed cd completion to differentiate between cd autosuggest and cd tab
completion. cd autosuggest will find deepest unique hierarchy and cd tab
completion will not.

Issue #4402
This commit is contained in:
Matthew Brock 2018-01-08 16:36:20 -05:00 committed by ridiculousfish
parent faa17ec849
commit bf63e061c9
4 changed files with 48 additions and 2 deletions

View File

@ -1031,6 +1031,9 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file,
if (!do_file) flags |= EXPAND_SKIP_WILDCARDS; if (!do_file) flags |= EXPAND_SKIP_WILDCARDS;
if (handle_as_special_cd && do_file) { if (handle_as_special_cd && do_file) {
if (this->type() == COMPLETE_AUTOSUGGEST) {
flags |= EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST;
}
flags |= DIRECTORIES_ONLY | EXPAND_SPECIAL_FOR_CD | EXPAND_NO_DESCRIPTIONS; flags |= DIRECTORIES_ONLY | EXPAND_SPECIAL_FOR_CD | EXPAND_NO_DESCRIPTIONS;
} }

View File

@ -46,9 +46,12 @@ enum {
/// Do expansions specifically to support cd. This means using CDPATH as a list of potential /// Do expansions specifically to support cd. This means using CDPATH as a list of potential
/// working directories. /// working directories.
EXPAND_SPECIAL_FOR_CD = 1 << 11, EXPAND_SPECIAL_FOR_CD = 1 << 11,
/// Do expansions specifically for cd autosuggestion. This is to differentiate between cd
/// completions and cd autosuggestions.
EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST = 1 << 12,
/// Do expansions specifically to support external command completions. This means using PATH as /// Do expansions specifically to support external command completions. This means using PATH as
/// a list of potential working directories. /// a list of potential working directories.
EXPAND_SPECIAL_FOR_COMMAND = 1 << 12 EXPAND_SPECIAL_FOR_COMMAND = 1 << 13
}; };
typedef int expand_flags_t; typedef int expand_flags_t;

View File

@ -2350,6 +2350,42 @@ static void perform_one_autosuggestion_cd_test(const wcstring &command,
} }
} }
static void perform_one_completion_cd_test(const wcstring &command,
const wcstring &expected, long line) {
std::vector<completion_t> comps;
complete(command, &comps, COMPLETION_REQUEST_DEFAULT);
bool expects_error = (expected == L"<error>");
if (comps.empty() && !expects_error) {
fwprintf(stderr, L"line %ld: autosuggest_suggest_special() failed for command %ls\n", line,
command.c_str());
do_test_from(!comps.empty(), line);
return;
} else if (!comps.empty() && expects_error) {
fwprintf(stderr,
L"line %ld: autosuggest_suggest_special() was expected to fail but did not, "
L"for command %ls\n",
line, command.c_str());
do_test_from(comps.empty(), line);
}
if (!comps.empty()) {
completions_sort_and_prioritize(&comps);
const completion_t &suggestion = comps.at(0);
if (suggestion.completion != expected) {
fwprintf(
stderr,
L"line %ld: complete() for cd tab completion returned the wrong expected string for command %ls\n",
line, command.c_str());
fwprintf(stderr, L" actual: %ls\n", suggestion.completion.c_str());
fwprintf(stderr, L"expected: %ls\n", expected.c_str());
do_test_from(suggestion.completion == expected, line);
}
}
}
// Testing test_autosuggest_suggest_special, in particular for properly handling quotes and // Testing test_autosuggest_suggest_special, in particular for properly handling quotes and
// backslashes. // backslashes.
static void test_autosuggest_suggest_special() { static void test_autosuggest_suggest_special() {
@ -2438,6 +2474,8 @@ static void test_autosuggest_suggest_special() {
if (system("mkdir -p '~hahaha/path1/path2/'")) err(L"mkdir failed"); if (system("mkdir -p '~hahaha/path1/path2/'")) err(L"mkdir failed");
perform_one_autosuggestion_cd_test(L"cd ~haha", L"ha/path1/path2/", __LINE__); perform_one_autosuggestion_cd_test(L"cd ~haha", L"ha/path1/path2/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~hahaha/", L"path1/path2/", __LINE__); perform_one_autosuggestion_cd_test(L"cd ~hahaha/", L"path1/path2/", __LINE__);
perform_one_completion_cd_test(L"cd ~haha", L"ha/", __LINE__);
perform_one_completion_cd_test(L"cd ~hahaha/", L"path1/", __LINE__);
popd(); popd();
system("rmdir ~/test_autosuggest_suggest_special/"); system("rmdir ~/test_autosuggest_suggest_special/");

View File

@ -586,7 +586,9 @@ class wildcard_expander_t {
// Hack. Implement EXPAND_SPECIAL_FOR_CD by descending the deepest unique hierarchy we // Hack. Implement EXPAND_SPECIAL_FOR_CD by descending the deepest unique hierarchy we
// can, and then appending any components to each new result. // can, and then appending any components to each new result.
if (flags & EXPAND_SPECIAL_FOR_CD) { // Only descend deepest unique for cd autosuggest and not for cd tab completion
// (issue #4402).
if (flags & EXPAND_SPECIAL_FOR_CD && flags & EXPAND_SPECIAL_FOR_CD_AUTOSUGGEST) {
wcstring unique_hierarchy = this->descend_unique_hierarchy(abs_path); wcstring unique_hierarchy = this->descend_unique_hierarchy(abs_path);
if (!unique_hierarchy.empty()) { if (!unique_hierarchy.empty()) {
for (size_t i = before; i < after; i++) { for (size_t i = before; i < after; i++) {