From bf63e061c9abecf8b44c2b1b00b1b4badeb7ba48 Mon Sep 17 00:00:00 2001 From: Matthew Brock Date: Mon, 8 Jan 2018 16:36:20 -0500 Subject: [PATCH] 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 --- src/complete.cpp | 3 +++ src/expand.h | 5 ++++- src/fish_tests.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/wildcard.cpp | 4 +++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/complete.cpp b/src/complete.cpp index 8a0504c89..8e7fa63d7 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1031,6 +1031,9 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file, if (!do_file) flags |= EXPAND_SKIP_WILDCARDS; 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; } diff --git a/src/expand.h b/src/expand.h index 251f02b04..2d8605457 100644 --- a/src/expand.h +++ b/src/expand.h @@ -46,9 +46,12 @@ enum { /// Do expansions specifically to support cd. This means using CDPATH as a list of potential /// working directories. 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 /// a list of potential working directories. - EXPAND_SPECIAL_FOR_COMMAND = 1 << 12 + EXPAND_SPECIAL_FOR_COMMAND = 1 << 13 }; typedef int expand_flags_t; diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 63ca2fdc2..b965f6f27 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -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 comps; + complete(command, &comps, COMPLETION_REQUEST_DEFAULT); + + bool expects_error = (expected == L""); + + 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 // backslashes. 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"); 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_completion_cd_test(L"cd ~haha", L"ha/", __LINE__); + perform_one_completion_cd_test(L"cd ~hahaha/", L"path1/", __LINE__); popd(); system("rmdir ~/test_autosuggest_suggest_special/"); diff --git a/src/wildcard.cpp b/src/wildcard.cpp index a51c8762f..93027fc24 100644 --- a/src/wildcard.cpp +++ b/src/wildcard.cpp @@ -586,7 +586,9 @@ class wildcard_expander_t { // Hack. Implement EXPAND_SPECIAL_FOR_CD by descending the deepest unique hierarchy we // 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); if (!unique_hierarchy.empty()) { for (size_t i = before; i < after; i++) {