WIP

Antonio Scandurra and Max Brunsfeld created

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

Change summary

crates/buffer/src/lib.rs | 126 ++++++++++++++++++++++++++----------------
1 file changed, 78 insertions(+), 48 deletions(-)

Detailed changes

crates/buffer/src/lib.rs 🔗

@@ -151,6 +151,7 @@ impl Drop for QueryCursorHandle {
         QUERY_CURSORS.lock().push(cursor)
     }
 }
+
 pub struct Buffer {
     fragments: SumTree<Fragment>,
     visible_text: Rope,
@@ -192,6 +193,30 @@ struct SyntaxTree {
     version: clock::Global,
 }
 
+impl SyntaxTree {
+    fn interpolate(&mut self, buffer: &Buffer) {
+        let mut delta = 0_isize;
+        for edit in buffer.edits_since(self.version.clone()) {
+            let start_offset = (edit.old_bytes.start as isize + delta) as usize;
+            let start_point = buffer.visible_text.to_point(start_offset);
+            self.tree.edit(&InputEdit {
+                start_byte: start_offset,
+                old_end_byte: start_offset + edit.deleted_bytes(),
+                new_end_byte: start_offset + edit.inserted_bytes(),
+                start_position: start_point.into(),
+                old_end_position: (start_point + edit.deleted_lines()).into(),
+                new_end_position: buffer
+                    .visible_text
+                    .to_point(start_offset + edit.inserted_bytes())
+                    .into(),
+            });
+            delta += edit.inserted_bytes() as isize - edit.deleted_bytes() as isize;
+            self.dirty = true;
+        }
+        self.version = buffer.version();
+    }
+}
+
 #[derive(Clone, Debug)]
 struct AutoindentRequest {
     position: Anchor,
@@ -850,27 +875,9 @@ impl Buffer {
         self.parse_count
     }
 
-    pub fn syntax_tree(&self) -> Option<Tree> {
+    fn syntax_tree(&self) -> Option<Tree> {
         if let Some(syntax_tree) = self.syntax_tree.lock().as_mut() {
-            let mut delta = 0_isize;
-            for edit in self.edits_since(syntax_tree.version.clone()) {
-                let start_offset = (edit.old_bytes.start as isize + delta) as usize;
-                let start_point = self.visible_text.to_point(start_offset);
-                syntax_tree.tree.edit(&InputEdit {
-                    start_byte: start_offset,
-                    old_end_byte: start_offset + edit.deleted_bytes(),
-                    new_end_byte: start_offset + edit.inserted_bytes(),
-                    start_position: start_point.into(),
-                    old_end_position: (start_point + edit.deleted_lines()).into(),
-                    new_end_position: self
-                        .visible_text
-                        .to_point(start_offset + edit.inserted_bytes())
-                        .into(),
-                });
-                delta += edit.inserted_bytes() as isize - edit.deleted_bytes() as isize;
-                syntax_tree.dirty = true;
-            }
-            syntax_tree.version = self.version();
+            syntax_tree.interpolate(self);
             Some(syntax_tree.tree.clone())
         } else {
             None
@@ -893,13 +900,16 @@ impl Buffer {
         }
 
         if let Some(language) = self.language.clone() {
-            let old_snapshot = self.snapshot();
+            let old_tree = self.syntax_tree.lock().as_mut().map(|tree| {
+                tree.interpolate(self);
+                tree.clone()
+            });
+            let text = self.visible_text.clone();
             let parsed_version = self.version();
             let parse_task = cx.background().spawn({
                 let language = language.clone();
-                let text = old_snapshot.visible_text.clone();
-                let tree = old_snapshot.tree.clone();
-                async move { Self::parse_text(&text, tree, &language) }
+                let old_tree = old_tree.as_ref().map(|t| t.tree.clone());
+                async move { Self::parse_text(&text, old_tree, &language) }
             });
 
             match cx
@@ -907,13 +917,13 @@ impl Buffer {
                 .block_with_timeout(self.sync_parse_timeout, parse_task)
             {
                 Ok(new_tree) => {
-                    *self.syntax_tree.lock() = Some(SyntaxTree {
-                        tree: new_tree.clone(),
-                        dirty: false,
-                        version: parsed_version,
-                    });
-                    self.parse_count += 1;
-                    self.did_finish_parsing(new_tree, old_snapshot, language, cx);
+                    self.did_finish_parsing(
+                        old_tree.map(|t| t.tree),
+                        new_tree,
+                        parsed_version,
+                        language,
+                        cx,
+                    );
                     return true;
                 }
                 Err(parse_task) => {
@@ -926,19 +936,22 @@ impl Buffer {
                                     !Arc::ptr_eq(curr_language, &language)
                                 });
                             let parse_again = this.version > parsed_version || language_changed;
-                            *this.syntax_tree.lock() = Some(SyntaxTree {
-                                tree: new_tree.clone(),
-                                dirty: false,
-                                version: parsed_version,
+                            let old_tree = old_tree.map(|mut old_tree| {
+                                old_tree.interpolate(this);
+                                old_tree.tree
                             });
-                            this.parse_count += 1;
                             this.parsing_in_background = false;
+                            this.did_finish_parsing(
+                                old_tree,
+                                new_tree,
+                                parsed_version,
+                                language,
+                                cx,
+                            );
 
                             if parse_again && this.reparse(cx) {
                                 return;
                             }
-
-                            this.did_finish_parsing(new_tree, old_snapshot, language, cx);
                         });
                     })
                     .detach();
@@ -970,8 +983,28 @@ impl Buffer {
 
     fn did_finish_parsing(
         &mut self,
+        old_tree: Option<Tree>,
         new_tree: Tree,
-        old_snapshot: Snapshot,
+        new_version: clock::Global,
+        language: Arc<Language>,
+        cx: &mut ModelContext<Self>,
+    ) {
+        self.perform_autoindent(old_tree, &new_tree, language, cx);
+
+        self.parse_count += 1;
+        *self.syntax_tree.lock() = Some(SyntaxTree {
+            tree: new_tree,
+            dirty: false,
+            version: new_version,
+        });
+        cx.emit(Event::Reparsed);
+        cx.notify();
+    }
+
+    fn perform_autoindent(
+        &mut self,
+        old_tree: Option<Tree>,
+        new_tree: &Tree,
         language: Arc<Language>,
         cx: &mut ModelContext<Self>,
     ) {
@@ -999,10 +1032,10 @@ impl Buffer {
                     if range.end == row {
                         range.end += 1;
                     } else {
-                        self.perform_autoindent(
+                        self.perform_autoindent_for_rows(
                             range.clone(),
+                            old_tree.as_ref(),
                             &new_tree,
-                            &old_snapshot,
                             &autoindent_requests_by_row,
                             language.as_ref(),
                             &mut cursor,
@@ -1014,10 +1047,10 @@ impl Buffer {
             }
         }
         if let Some(range) = row_range {
-            self.perform_autoindent(
+            self.perform_autoindent_for_rows(
                 range,
+                old_tree.as_ref(),
                 &new_tree,
-                &old_snapshot,
                 &autoindent_requests_by_row,
                 language.as_ref(),
                 &mut cursor,
@@ -1025,16 +1058,13 @@ impl Buffer {
             );
         }
         self.end_transaction(None, cx).unwrap();
-
-        cx.emit(Event::Reparsed);
-        cx.notify();
     }
 
-    fn perform_autoindent(
+    fn perform_autoindent_for_rows(
         &mut self,
         row_range: Range<u32>,
+        old_tree: Option<&Tree>,
         new_tree: &Tree,
-        old_snapshot: &Snapshot,
         autoindent_requests: &BTreeMap<u32, AutoindentRequest>,
         language: &Language,
         cursor: &mut QueryCursor,