Allow auto-indenting with syntax errors when using regex-based indent matches to improve bash auto-indent behavior (#24160)

- Fixes auto-indent issues around `elif` caused by auto-indent being prevented due to syntax errors generated before `elif` clause completed

Release Notes:

- Fixed an issue where inserting an elif before an else in bash would
not properly auto-indent

---------

Co-authored-by: Conrad Irwin <conrad@zed.dev>
This commit is contained in:
Ben Kunkle 2025-02-03 21:34:37 -06:00 committed by GitHub
parent 66d0cdfd91
commit 8742c18107
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 53 additions and 8 deletions

1
Cargo.lock generated
View file

@ -7050,6 +7050,7 @@ dependencies = [
"pet-fs", "pet-fs",
"pet-poetry", "pet-poetry",
"pet-reporter", "pet-reporter",
"pretty_assertions",
"project", "project",
"regex", "regex",
"rope", "rope",

View file

@ -2897,12 +2897,19 @@ impl BufferSnapshot {
let mut indent_from_prev_row = false; let mut indent_from_prev_row = false;
let mut outdent_from_prev_row = false; let mut outdent_from_prev_row = false;
let mut outdent_to_row = u32::MAX; let mut outdent_to_row = u32::MAX;
let mut from_regex = false;
while let Some((indent_row, delta)) = indent_changes.peek() { while let Some((indent_row, delta)) = indent_changes.peek() {
match indent_row.cmp(&row) { match indent_row.cmp(&row) {
Ordering::Equal => match delta { Ordering::Equal => match delta {
Ordering::Less => outdent_from_prev_row = true, Ordering::Less => {
Ordering::Greater => indent_from_prev_row = true, from_regex = true;
outdent_from_prev_row = true
}
Ordering::Greater => {
indent_from_prev_row = true;
from_regex = true
}
_ => {} _ => {}
}, },
@ -2935,32 +2942,32 @@ impl BufferSnapshot {
Some(IndentSuggestion { Some(IndentSuggestion {
basis_row: prev_row, basis_row: prev_row,
delta: Ordering::Equal, delta: Ordering::Equal,
within_error, within_error: within_error && !from_regex,
}) })
} else if indent_from_prev_row { } else if indent_from_prev_row {
Some(IndentSuggestion { Some(IndentSuggestion {
basis_row: prev_row, basis_row: prev_row,
delta: Ordering::Greater, delta: Ordering::Greater,
within_error, within_error: within_error && !from_regex,
}) })
} else if outdent_to_row < prev_row { } else if outdent_to_row < prev_row {
Some(IndentSuggestion { Some(IndentSuggestion {
basis_row: outdent_to_row, basis_row: outdent_to_row,
delta: Ordering::Equal, delta: Ordering::Equal,
within_error, within_error: within_error && !from_regex,
}) })
} else if outdent_from_prev_row { } else if outdent_from_prev_row {
Some(IndentSuggestion { Some(IndentSuggestion {
basis_row: prev_row, basis_row: prev_row,
delta: Ordering::Less, delta: Ordering::Less,
within_error, within_error: within_error && !from_regex,
}) })
} else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row) } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
{ {
Some(IndentSuggestion { Some(IndentSuggestion {
basis_row: prev_row, basis_row: prev_row,
delta: Ordering::Equal, delta: Ordering::Equal,
within_error, within_error: within_error && !from_regex,
}) })
} else { } else {
None None

View file

@ -94,3 +94,4 @@ tree-sitter-go.workspace = true
tree-sitter-c.workspace = true tree-sitter-c.workspace = true
tree-sitter-css.workspace = true tree-sitter-css.workspace = true
tree-sitter-bash.workspace = true tree-sitter-bash.workspace = true
pretty_assertions.workspace = true

View file

@ -22,6 +22,8 @@ mod tests {
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer}; use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
use settings::SettingsStore; use settings::SettingsStore;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use unindent::Unindent;
use util::test::marked_text_offsets;
#[gpui::test] #[gpui::test]
async fn test_bash_autoindent(cx: &mut TestAppContext) { async fn test_bash_autoindent(cx: &mut TestAppContext) {
@ -111,6 +113,40 @@ mod tests {
"foo() {\n echo \"Hello, World!\"\n}", "foo() {\n echo \"Hello, World!\"\n}",
); );
let (input, offsets) = marked_text_offsets(
&r#"
if foo; then
1ˇ
else
3
fi
"#
.unindent(),
);
buffer.edit([(0..buffer.len(), input)], None, cx);
buffer.edit(
[(offsets[0]..offsets[0], "\n")],
Some(AutoindentMode::EachLine),
cx,
);
buffer.edit(
[(offsets[0] + 3..offsets[0] + 3, "elif")],
Some(AutoindentMode::EachLine),
cx,
);
let expected = r#"
if foo; then
1
elif
else
3
fi
"#
.unindent();
pretty_assertions::assert_eq!(buffer.text(), expected);
buffer buffer
}); });
} }

View file

@ -24,5 +24,5 @@ brackets = [
### fi ### fi
### ``` ### ```
increase_indent_pattern = "(\\s*|;)(do|then|in|else|elif)\\b.*$" increase_indent_pattern = "(\\s*|;)(do|then|in|else|elif)\\b.*$"
decrease_indent_pattern = "(\\s*|;)(fi|done|esac|else|elif)\\b.*$" decrease_indent_pattern = "(\\s*|;)\\b(fi|done|esac|else|elif)\\b.*$"
# make sure to test each line mode & block mode # make sure to test each line mode & block mode