Escape separators (colon and equals) to improve completion

Fish completes parts of words split by the separators, so things like
`dd if=/dev/sd<TAB>` work.
This commit improves interactive completion if completion strings legitimately
contain '=' or ':'.  Consider this example where completion will suggest
a:a:1 and other files in the cwd in addition to a:1

touch a:1; complete -C'ls a:'

This behavior remains unchanged, but this commit allows to quote or escape
separators, so that e.g. `ls "a:<TAB>` and `ls a\:<TAB>` successfully complete
the filename.

This also makes the completion insert those escapes automatically unless
already quoted.
So `ls a<TAB>` will give `ls a\:1`.

Both changes match bash's behavior.
This commit is contained in:
Johannes Altmanninger
2019-08-23 20:58:42 +02:00
committed by ridiculousfish
parent 54ed2ad440
commit f7dac82ed6
6 changed files with 24 additions and 13 deletions

View File

@@ -1098,6 +1098,7 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file,
// Squelch file descriptions per issue #254.
if (this->type() == COMPLETE_AUTOSUGGEST || do_file) flags |= expand_flag::no_descriptions;
// Expand words separated by '=' separately, unless '=' is escaped or quoted.
// We have the following cases:
//
// --foo=bar => expand just bar
@@ -1105,14 +1106,16 @@ void completer_t::complete_param_expand(const wcstring &str, bool do_file,
// foo=bar => expand the whole thing, and also just bar
//
// We also support colon separator (#2178). If there's more than one, prefer the last one.
size_t sep_index = str.find_last_of(L"=:");
bool complete_from_separator = (sep_index != wcstring::npos);
size_t sep_index = str.size();
do {
sep_index = sep_index == 0 ? wcstring::npos : str.find_last_of(L"=:", sep_index - 1);
} while (sep_index != wcstring::npos && is_backslashed(str, sep_index));
wchar_t quote = L'\0';
parse_util_get_parameter_info(str, str.size(), &quote, NULL, NULL);
bool complete_from_separator = (quote == L'\0') && (sep_index != wcstring::npos);
bool complete_from_start = !complete_from_separator || !string_prefixes_string(L"-", str);
if (complete_from_separator) {
// FIXME: This just cuts the token,
// so any quoting or braces gets lost.
// See #4954.
const wcstring sep_string = wcstring(str, sep_index + 1);
std::vector<completion_t> local_completions;
if (expand_string(sep_string, &local_completions, flags, vars, parser, NULL) ==