mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Correct handling of unescapable entities in quotes
Prior to this fix, if you attempt to complete from inside a quote and the completion contained an entity that cannot be represented inside quotes (i.e. \n \r \t \b), the result would be a broken mess of quotes. Rewrite the implementation so that it exits the quotes, emits the correct unquoted escape, and then re-enters the quotes.
This commit is contained in:
parent
01d87455e1
commit
81b3baaa9c
2 changed files with 26 additions and 17 deletions
|
@ -371,18 +371,23 @@ static void test_escape_quotes() {
|
|||
do_test(parse_util_escape_string_with_quote(L"~abc|def", L'\0') == L"\\~abc\\|def");
|
||||
do_test(parse_util_escape_string_with_quote(L"|abc~def", L'\0') == L"\\|abc\\~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"|abc~def", L'\0', true) == L"\\|abc~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\nbar", L'\0') == L"foo\\nbar");
|
||||
|
||||
// Note tildes are not expanded inside quotes, so no_tilde is ignored with a quote.
|
||||
do_test(parse_util_escape_string_with_quote(L"abc", L'\'') == L"abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\def", L'\'') == L"abc\\def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\def", L'\'') == L"abc\\\\def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc'def", L'\'') == L"abc\\'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'\'') == L"~abc\\'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'\'', true) == L"~abc\\'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\nba'r", L'\'') == L"foo'\\n'ba\\'r");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\\\\bar", L'\'') == L"foo\\\\\\\\bar");
|
||||
|
||||
do_test(parse_util_escape_string_with_quote(L"abc", L'"') == L"abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\def", L'"') == L"abc\\def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\def", L'"') == L"abc\\\\def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'"') == L"~abc'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'"', true) == L"~abc'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\nba'r", L'"') == L"foo\"\\n\"ba'r");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\\\\bar", L'"') == L"foo\\\\\\\\bar");
|
||||
}
|
||||
|
||||
static void test_format(void) {
|
||||
|
|
|
@ -517,29 +517,33 @@ wcstring parse_util_escape_string_with_quote(const wcstring &cmd, wchar_t quote,
|
|||
escape_flags_t flags = ESCAPE_ALL | ESCAPE_NO_QUOTED | (no_tilde ? ESCAPE_NO_TILDE : 0);
|
||||
result = escape_string(cmd, flags);
|
||||
} else {
|
||||
bool unescapable = false;
|
||||
for (size_t i = 0; i < cmd.size(); i++) {
|
||||
wchar_t c = cmd.at(i);
|
||||
// Here we are going to escape a string with quotes.
|
||||
// A few characters cannot be represented inside quotes, e.g. newlines. In that case,
|
||||
// terminate the quote and then re-enter it.
|
||||
result.reserve(cmd.size());
|
||||
for (wchar_t c : cmd) {
|
||||
switch (c) {
|
||||
case L'\n':
|
||||
case L'\t':
|
||||
case L'\b':
|
||||
case L'\r': {
|
||||
unescapable = true;
|
||||
result.append({quote, L'\\', L'n', quote});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
case L'\t':
|
||||
result.append({quote, L'\\', L't', quote});
|
||||
break;
|
||||
case L'\b':
|
||||
result.append({quote, L'\\', L'b', quote});
|
||||
break;
|
||||
case L'\r':
|
||||
result.append({quote, L'\\', L'r', quote});
|
||||
break;
|
||||
case L'\\':
|
||||
result.append({L'\\', L'\\'});
|
||||
break;
|
||||
default:
|
||||
if (c == quote) result.push_back(L'\\');
|
||||
result.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unescapable) {
|
||||
result = escape_string(cmd, ESCAPE_ALL | ESCAPE_NO_QUOTED);
|
||||
result.insert(0, "e, 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue