mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Add test for avoiding indent adjustment inside newly-created errors
This commit is contained in:
parent
9f74d6e4ac
commit
56080771e6
4 changed files with 212 additions and 104 deletions
|
@ -1666,6 +1666,16 @@ impl Buffer {
|
|||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl Buffer {
|
||||
pub fn edit_via_marked_text(
|
||||
&mut self,
|
||||
marked_string: &str,
|
||||
autoindent_mode: Option<AutoindentMode>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
let edits = self.edits_for_marked_text(marked_string);
|
||||
self.edit(edits, autoindent_mode, cx);
|
||||
}
|
||||
|
||||
pub fn set_group_interval(&mut self, group_interval: Duration) {
|
||||
self.text.set_group_interval(group_interval);
|
||||
}
|
||||
|
|
|
@ -800,23 +800,29 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
|
|||
cx.set_global(settings);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let text = "
|
||||
let mut buffer = Buffer::new(
|
||||
0,
|
||||
"
|
||||
fn a() {
|
||||
c;
|
||||
d;
|
||||
}
|
||||
"
|
||||
.unindent();
|
||||
|
||||
let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
|
||||
"
|
||||
.unindent(),
|
||||
cx,
|
||||
)
|
||||
.with_language(Arc::new(rust_lang()), cx);
|
||||
|
||||
// Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
|
||||
// their indentation is not adjusted.
|
||||
buffer.edit(
|
||||
[
|
||||
(empty(Point::new(1, 1)), "()"),
|
||||
(empty(Point::new(2, 1)), "()"),
|
||||
],
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a() {
|
||||
c«()»;
|
||||
d«()»;
|
||||
}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
|
@ -833,14 +839,22 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
|
|||
|
||||
// When appending new content after these lines, the indentation is based on the
|
||||
// preceding lines' actual indentation.
|
||||
buffer.edit(
|
||||
[
|
||||
(empty(Point::new(1, 1)), "\n.f\n.g"),
|
||||
(empty(Point::new(2, 1)), "\n.f\n.g"),
|
||||
],
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a() {
|
||||
c«
|
||||
.f
|
||||
.g()»;
|
||||
d«
|
||||
.f
|
||||
.g()»;
|
||||
}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"
|
||||
|
@ -859,20 +873,27 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
|
|||
});
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let text = "
|
||||
let mut buffer = Buffer::new(
|
||||
0,
|
||||
"
|
||||
fn a() {
|
||||
{
|
||||
b()?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
"
|
||||
.unindent();
|
||||
let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
|
||||
b();
|
||||
|
|
||||
"
|
||||
.replace("|", "") // marker to preserve trailing whitespace
|
||||
.unindent(),
|
||||
cx,
|
||||
)
|
||||
.with_language(Arc::new(rust_lang()), cx);
|
||||
|
||||
// Delete a closing curly brace changes the suggested indent for the line.
|
||||
buffer.edit(
|
||||
[(Point::new(3, 4)..Point::new(3, 5), "")],
|
||||
// Insert a closing brace. It is outdented.
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a() {
|
||||
b();
|
||||
«}»
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
|
@ -880,19 +901,20 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
|
|||
buffer.text(),
|
||||
"
|
||||
fn a() {
|
||||
{
|
||||
b()?
|
||||
|
|
||||
Ok(())
|
||||
b();
|
||||
}
|
||||
"
|
||||
.replace('|', "") // included in the string to preserve trailing whites
|
||||
.unindent()
|
||||
);
|
||||
|
||||
// Manually editing the leading whitespace
|
||||
buffer.edit(
|
||||
[(Point::new(3, 0)..Point::new(3, 12), "")],
|
||||
// Manually edit the leading whitespace. The edit is preserved.
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a() {
|
||||
b();
|
||||
« »}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
|
@ -900,11 +922,8 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
|
|||
buffer.text(),
|
||||
"
|
||||
fn a() {
|
||||
{
|
||||
b()?
|
||||
|
||||
Ok(())
|
||||
}
|
||||
b();
|
||||
}
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
|
@ -913,30 +932,108 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
|
||||
cx.set_global(Settings::test(cx));
|
||||
fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut MutableAppContext) {
|
||||
let settings = Settings::test(cx);
|
||||
cx.set_global(settings);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let text = "
|
||||
fn a() {}
|
||||
"
|
||||
.unindent();
|
||||
let mut buffer = Buffer::new(
|
||||
0,
|
||||
"
|
||||
fn a() {
|
||||
i
|
||||
}
|
||||
"
|
||||
.unindent(),
|
||||
cx,
|
||||
)
|
||||
.with_language(Arc::new(rust_lang()), cx);
|
||||
|
||||
let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
|
||||
|
||||
buffer.edit([(5..5, "\nb")], Some(AutoindentMode::EachLine), cx);
|
||||
// Regression test: line does not get outdented due to syntax error
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a() {
|
||||
i«f let Some(x) = y»
|
||||
}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"
|
||||
fn a(
|
||||
b) {}
|
||||
fn a() {
|
||||
if let Some(x) = y
|
||||
}
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a() {
|
||||
if let Some(x) = y« {»
|
||||
}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"
|
||||
fn a() {
|
||||
if let Some(x) = y {
|
||||
}
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
|
||||
cx.set_global(Settings::test(cx));
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(
|
||||
0,
|
||||
"
|
||||
fn a() {}
|
||||
"
|
||||
.unindent(),
|
||||
cx,
|
||||
)
|
||||
.with_language(Arc::new(rust_lang()), cx);
|
||||
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a(«
|
||||
b») {}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"
|
||||
fn a(
|
||||
b) {}
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
|
||||
// The indentation suggestion changed because `@end` node (a close paren)
|
||||
// is now at the beginning of the line.
|
||||
buffer.edit(
|
||||
[(Point::new(1, 4)..Point::new(1, 5), "")],
|
||||
buffer.edit_via_marked_text(
|
||||
&"
|
||||
fn a(
|
||||
ˇ) {}
|
||||
"
|
||||
.unindent(),
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
|
@ -1894,7 +1991,3 @@ fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> Str
|
|||
layers[0].node.to_sexp()
|
||||
})
|
||||
}
|
||||
|
||||
fn empty(point: Point) -> Range<Point> {
|
||||
point..point
|
||||
}
|
||||
|
|
|
@ -2262,7 +2262,7 @@ mod tests {
|
|||
mutated_syntax_map.reparse(language.clone(), &buffer);
|
||||
|
||||
for (i, marked_string) in steps.into_iter().enumerate() {
|
||||
edit_buffer(&mut buffer, &marked_string.unindent());
|
||||
buffer.edit_via_marked_text(&marked_string.unindent());
|
||||
|
||||
// Reparse the syntax map
|
||||
mutated_syntax_map.interpolate(&buffer);
|
||||
|
@ -2452,52 +2452,6 @@ mod tests {
|
|||
assert_eq!(actual_ranges, expected_ranges);
|
||||
}
|
||||
|
||||
fn edit_buffer(buffer: &mut Buffer, marked_string: &str) {
|
||||
let old_text = buffer.text();
|
||||
let (new_text, mut ranges) = marked_text_ranges(marked_string, false);
|
||||
if ranges.is_empty() {
|
||||
ranges.push(0..new_text.len());
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
old_text[..ranges[0].start],
|
||||
new_text[..ranges[0].start],
|
||||
"invalid edit"
|
||||
);
|
||||
|
||||
let mut delta = 0;
|
||||
let mut edits = Vec::new();
|
||||
let mut ranges = ranges.into_iter().peekable();
|
||||
|
||||
while let Some(inserted_range) = ranges.next() {
|
||||
let new_start = inserted_range.start;
|
||||
let old_start = (new_start as isize - delta) as usize;
|
||||
|
||||
let following_text = if let Some(next_range) = ranges.peek() {
|
||||
&new_text[inserted_range.end..next_range.start]
|
||||
} else {
|
||||
&new_text[inserted_range.end..]
|
||||
};
|
||||
|
||||
let inserted_len = inserted_range.len();
|
||||
let deleted_len = old_text[old_start..]
|
||||
.find(following_text)
|
||||
.expect("invalid edit");
|
||||
|
||||
let old_range = old_start..old_start + deleted_len;
|
||||
edits.push((old_range, new_text[inserted_range].to_string()));
|
||||
delta += inserted_len as isize - deleted_len as isize;
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
old_text.len() as isize + delta,
|
||||
new_text.len() as isize,
|
||||
"invalid edit"
|
||||
);
|
||||
|
||||
buffer.edit(edits);
|
||||
}
|
||||
|
||||
pub fn string_contains_sequence(text: &str, parts: &[&str]) -> bool {
|
||||
let mut last_part_end = 0;
|
||||
for part in parts {
|
||||
|
|
|
@ -1372,6 +1372,57 @@ impl Buffer {
|
|||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl Buffer {
|
||||
pub fn edit_via_marked_text(&mut self, marked_string: &str) {
|
||||
let edits = self.edits_for_marked_text(marked_string);
|
||||
self.edit(edits);
|
||||
}
|
||||
|
||||
pub fn edits_for_marked_text(&self, marked_string: &str) -> Vec<(Range<usize>, String)> {
|
||||
let old_text = self.text();
|
||||
let (new_text, mut ranges) = util::test::marked_text_ranges(marked_string, false);
|
||||
if ranges.is_empty() {
|
||||
ranges.push(0..new_text.len());
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
old_text[..ranges[0].start],
|
||||
new_text[..ranges[0].start],
|
||||
"invalid edit"
|
||||
);
|
||||
|
||||
let mut delta = 0;
|
||||
let mut edits = Vec::new();
|
||||
let mut ranges = ranges.into_iter().peekable();
|
||||
|
||||
while let Some(inserted_range) = ranges.next() {
|
||||
let new_start = inserted_range.start;
|
||||
let old_start = (new_start as isize - delta) as usize;
|
||||
|
||||
let following_text = if let Some(next_range) = ranges.peek() {
|
||||
&new_text[inserted_range.end..next_range.start]
|
||||
} else {
|
||||
&new_text[inserted_range.end..]
|
||||
};
|
||||
|
||||
let inserted_len = inserted_range.len();
|
||||
let deleted_len = old_text[old_start..]
|
||||
.find(following_text)
|
||||
.expect("invalid edit");
|
||||
|
||||
let old_range = old_start..old_start + deleted_len;
|
||||
edits.push((old_range, new_text[inserted_range].to_string()));
|
||||
delta += inserted_len as isize - deleted_len as isize;
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
old_text.len() as isize + delta,
|
||||
new_text.len() as isize,
|
||||
"invalid edit"
|
||||
);
|
||||
|
||||
edits
|
||||
}
|
||||
|
||||
pub fn check_invariants(&self) {
|
||||
// Ensure every fragment is ordered by locator in the fragment tree and corresponds
|
||||
// to an insertion fragment in the insertions tree.
|
||||
|
|
Loading…
Reference in a new issue