Don't color a whole string invalid because of an unclosed quote

When syntax highlighting a quoted string, if the string is not closed,
only show the opening quote as an error, not the whole string.
This commit is contained in:
ridiculousfish 2019-07-24 12:28:05 -07:00
parent c0053ceef5
commit 822b53c67a
3 changed files with 24 additions and 2 deletions

View File

@ -64,6 +64,7 @@
- If fish_mode_prompt exists, vi-mode will only execute it on mode-switch instead of the entire prompt. This should make it much more responsive with slow prompts (#5783).
- The path-component bindings (like ctrl-w) now also stop at ":" and "@" because those are used to denote user and host in ssh-likes (#5841).
- `read` no longer keeps a history, making it suitable for operations that shouldn't end up there, like password entry (#5904).
- When syntax highlighting a string with an unclosed quote, only the quote itself will be shown as an error, instead of the whole argument.
### For distributors and developers
- The autotools-based build system and legacy Xcode build systems have been removed, leaving only the CMake build system. All distributors and developers must migrate to the CMake build.

View File

@ -4474,7 +4474,16 @@ static void test_highlighting() {
highlight_tests.push_back({
{L"echo", highlight_role_t::command},
{L"'single_quote", highlight_role_t::error},
{L"'", highlight_role_t::error},
{L"single_quote", highlight_role_t::quote},
{L"$stuff", highlight_role_t::quote},
});
highlight_tests.push_back({
{L"echo", highlight_role_t::command},
{L"\"", highlight_role_t::error},
{L"double_quote", highlight_role_t::quote},
{L"$stuff", highlight_role_t::operat},
});
highlight_tests.push_back({

View File

@ -537,6 +537,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
}
enum { e_unquoted, e_single_quoted, e_double_quoted } mode = e_unquoted;
maybe_t<size_t> unclosed_quote_offset;
int bracket_count = 0;
for (size_t in_pos = 0; in_pos < buff_len; in_pos++) {
const wchar_t c = buffstr.at(in_pos);
@ -671,11 +672,13 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
}
case L'\'': {
colors[in_pos] = highlight_role_t::quote;
unclosed_quote_offset = in_pos;
mode = e_single_quoted;
break;
}
case L'\"': {
colors[in_pos] = highlight_role_t::quote;
unclosed_quote_offset = in_pos;
mode = e_double_quoted;
break;
}
@ -700,6 +703,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
}
}
} else if (c == L'\'') {
unclosed_quote_offset = none();
mode = e_unquoted;
}
break;
@ -713,6 +717,7 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
}
switch (c) {
case L'"': {
unclosed_quote_offset = none();
mode = e_unquoted;
break;
}
@ -743,6 +748,11 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
}
}
}
// Error on unclosed quotes.
if (unclosed_quote_offset) {
colors[*unclosed_quote_offset] = highlight_role_t::error;
}
}
/// Syntax highlighter helper.
@ -793,7 +803,9 @@ class highlighter_t {
working_directory(std::move(wd)),
color_array(str.size()) {
// Parse the tree.
parse_tree_from_string(buff, parse_flag_continue_after_error | parse_flag_include_comments,
parse_tree_from_string(buff,
parse_flag_continue_after_error | parse_flag_include_comments |
parse_flag_accept_incomplete_tokens,
&this->parse_tree, NULL);
}