Remove disk diagnostics that were invalidated by a buffer edit

Antonio Scandurra , Nathan Sobo , and Max Brunsfeld created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
Co-Authored-By: Max Brunsfeld <max@zed.dev>

Change summary

crates/language/src/buffer.rs |  6 +++++-
crates/text/src/rope.rs       | 16 ++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)

Detailed changes

crates/language/src/buffer.rs 🔗

@@ -751,7 +751,9 @@ impl Buffer {
             .peekable();
         let mut last_edit_old_end = PointUtf16::zero();
         let mut last_edit_new_end = PointUtf16::zero();
-        'outer: for entry in &mut diagnostics {
+        let mut ix = 0;
+        'outer: while ix < diagnostics.len() {
+            let entry = &mut diagnostics[ix];
             let mut start = entry.range.start;
             let mut end = entry.range.end;
             if entry
@@ -766,6 +768,7 @@ impl Buffer {
                         last_edit_new_end = edit.new.end;
                         edits_since_save.next();
                     } else if edit.old.start <= end && edit.old.end >= start {
+                        diagnostics.remove(ix);
                         continue 'outer;
                     } else {
                         break;
@@ -786,6 +789,7 @@ impl Buffer {
                     entry.range.start = content.clip_point_utf16(entry.range.start, Bias::Left);
                 }
             }
+            ix += 1;
         }
 
         drop(edits_since_save);

crates/text/src/rope.rs 🔗

@@ -958,6 +958,22 @@ mod tests {
                 }
             }
 
+            let mut point_utf16 = PointUtf16::zero();
+            for unit in expected.encode_utf16() {
+                let left_point = actual.clip_point_utf16(point_utf16, Bias::Left);
+                let right_point = actual.clip_point_utf16(point_utf16, Bias::Right);
+                assert!(right_point >= left_point);
+                // Ensure translating UTF-16 points to offsets doesn't panic.
+                actual.point_utf16_to_offset(left_point);
+                actual.point_utf16_to_offset(right_point);
+
+                if unit == b'\n' as u16 {
+                    point_utf16 += PointUtf16::new(1, 0);
+                } else {
+                    point_utf16 += PointUtf16::new(0, 1);
+                }
+            }
+
             for _ in 0..5 {
                 let end_ix = clip_offset(&expected, rng.gen_range(0..=expected.len()), Right);
                 let start_ix = clip_offset(&expected, rng.gen_range(0..=end_ix), Left);