mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-27 20:25:12 +00:00
Fix crash indenting quoted suffix after command substitution
Commit b00899179
(Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) made parse_util_compute_indents() crash on `echo "$()"'x`.
After recursively indenting the command substitution, we indent the "'x
suffix. We skip the quoted part by setting "done=2". Later we wrongly
index "self.indents[done..range.start+offset+1]" (= "self.indents[2..1]").
Fix this by making sure that "start >= done", thus not setting any indents
for the quoted suffix. There is no need to do so; only the first character
in each line needs an indent.
This commit is contained in:
parent
50314e309b
commit
4c43819d32
2 changed files with 31 additions and 31 deletions
|
@ -941,42 +941,38 @@ impl<'a> IndentVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn indent_string_part(&mut self, range: Range<usize>, is_double_quoted: bool) {
|
fn indent_string_part(&mut self, range: Range<usize>, is_double_quoted: bool) {
|
||||||
let mut done = range.start;
|
let mut start = range.start;
|
||||||
let mut quoted = false;
|
let mut quoted = false;
|
||||||
{
|
|
||||||
if is_double_quoted {
|
if is_double_quoted {
|
||||||
match quote_end(self.src, range.start, '"') {
|
match quote_end(self.src, range.start, '"') {
|
||||||
Some(q_end) => {
|
Some(q_end) => {
|
||||||
// We may be (in) a multi-line string, so don't indent.
|
// We may be (in) a multi-line string, so don't indent.
|
||||||
done = q_end + 1;
|
start = q_end + 1;
|
||||||
}
|
}
|
||||||
None => quoted = true,
|
None => quoted = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let part = &self.src[done..range.end];
|
let mut done = start;
|
||||||
if !quoted {
|
if !quoted {
|
||||||
|
let part = &self.src[done..range.end];
|
||||||
let mut callback = |offset| {
|
let mut callback = |offset| {
|
||||||
if !quoted {
|
if !quoted {
|
||||||
// Quote open event. Indent unquoted part, including the opening quote.
|
// Quote open event. Indent unquoted part, including the opening quote.
|
||||||
self.indents[done..range.start + offset + 1].fill(self.indent);
|
self.indents[done..start + offset + 1].fill(self.indent);
|
||||||
done = range.start + offset + 1;
|
done = start + offset + 1;
|
||||||
} else {
|
} else {
|
||||||
// Quote close. Don't indent, in case it's a multiline string.
|
// Quote close. Don't indent, in case it's a multiline string.
|
||||||
// Mark the first line as indented but only to make tests look prettier.
|
// Mark the first line as indented but only to make tests look prettier.
|
||||||
let first_line_length = self.src[range.start..range.start + offset]
|
let first_line_length = self.src[start..start + offset]
|
||||||
.chars()
|
.chars()
|
||||||
.take_while(|&c| c != '\n')
|
.take_while(|&c| c != '\n')
|
||||||
.count();
|
.count();
|
||||||
self.indents[range.start..range.start + first_line_length]
|
self.indents[start..start + first_line_length].fill(self.indent);
|
||||||
.fill(self.indent);
|
done = start + offset;
|
||||||
done = range.start + offset;
|
|
||||||
}
|
}
|
||||||
quoted = !quoted;
|
quoted = !quoted;
|
||||||
};
|
};
|
||||||
for _token in
|
for _token in Tokenizer::with_quote_events(part, TOK_ACCEPT_UNFINISHED, &mut callback) {
|
||||||
Tokenizer::with_quote_events(part, TOK_ACCEPT_UNFINISHED, &mut callback)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !quoted {
|
if !quoted {
|
||||||
|
|
|
@ -435,5 +435,9 @@ fn test_indents() {
|
||||||
0, "\n) line4",
|
0, "\n) line4",
|
||||||
0, "\nline5\"",
|
0, "\nline5\"",
|
||||||
);
|
);
|
||||||
|
validate!(
|
||||||
|
0, r#"echo "$()"'"#,
|
||||||
|
0, "\n"
|
||||||
|
);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue