Move diff logic back into `BufferDiff::update`

Julia created

Change summary

crates/language/src/buffer.rs |   3 
crates/language/src/git.rs    | 351 +++++++++---------------------------
2 files changed, 88 insertions(+), 266 deletions(-)

Detailed changes

crates/language/src/buffer.rs 🔗

@@ -48,7 +48,7 @@ pub use lsp::DiagnosticSeverity;
 
 pub struct Buffer {
     text: TextBuffer,
-    head_text: Option<Rope>,
+    head_text: Option<String>,
     git_diff: BufferDiff,
     file: Option<Arc<dyn File>>,
     saved_version: clock::Global,
@@ -422,7 +422,6 @@ impl Buffer {
         };
 
         let git_diff = BufferDiff::new(&head_text, &buffer);
-        let head_text = head_text.map(|h| Rope::from(h.as_str()));
 
         Self {
             saved_mtime,

crates/language/src/git.rs 🔗

@@ -83,64 +83,6 @@ impl<'a> sum_tree::Dimension<'a, DiffHunkSummary> for HunkBufferEnd {
     }
 }
 
-// struct HunkIter<'a> {
-//     index: usize,
-//     patch: GitPatch<'a>,
-// }
-
-// impl<'a> HunkIter<'a> {
-//     fn diff(head: &'a [u8], current: &'a [u8]) -> Option<Self> {
-//         let mut options = GitOptions::default();
-//         options.context_lines(0);
-//         let patch = match GitPatch::from_buffers(head, None, current, None, Some(&mut options)) {
-//             Ok(patch) => patch,
-//             Err(_) => return None,
-//         };
-
-//         Some(HunkIter { index: 0, patch })
-//     }
-
-//     fn next(&mut self, buffer: &BufferSnapshot) -> Option<DiffHunk<Anchor>> {
-//         if self.index >= self.patch.num_hunks() {
-//             return None;
-//         }
-
-//         let (hunk, _) = match self.patch.hunk(self.index) {
-//             Ok(it) => it,
-//             Err(_) => return None,
-//         };
-//         let hunk_line_count = self.patch.num_lines_in_hunk(self.index).unwrap();
-
-//         println!("{hunk:#?}");
-//         for index in 0..hunk_line_count {
-//             println!("{:?}", self.patch.line_in_hunk(self.index, index));
-//         }
-
-//         let new_start = hunk.new_start() - 1;
-//         let new_end = new_start + hunk.new_lines();
-//         let start_anchor = buffer.anchor_at(Point::new(new_start, 0), Bias::Left);
-//         let end_anchor = buffer.anchor_at(Point::new(new_end, 0), Bias::Left);
-//         let buffer_range = start_anchor..end_anchor;
-
-//         //This is probably wrong? When does this trigger? Should buffer range also do this?
-//         let head_range = if hunk.old_start() == 0 {
-//             0..0
-//         } else {
-//             let old_start = hunk.old_start() - 1;
-//             let old_end = old_start + hunk.old_lines();
-//             old_start..old_end
-//         };
-
-//         // let head_start_index = self.patch.line_in_hunk(self.index, 0)
-
-//         self.index += 1;
-//         Some(DiffHunk {
-//             buffer_range,
-//             head_range,
-//         })
-//     }
-// }
-
 #[derive(Clone)]
 pub struct BufferDiffSnapshot {
     tree: SumTree<DiffHunk<Anchor>>,
@@ -187,221 +129,102 @@ pub struct BufferDiff {
 
 impl BufferDiff {
     pub fn new(head_text: &Option<String>, buffer: &text::BufferSnapshot) -> BufferDiff {
-        let hunks = if let Some(head_text) = head_text {
-            let buffer_string = buffer.as_rope().to_string();
-            let buffer_bytes = buffer_string.as_bytes();
-
-            let mut options = GitOptions::default();
-            options.context_lines(0);
-            let patch = match GitPatch::from_buffers(
-                head_text.as_bytes(),
-                None,
-                buffer_bytes,
-                None,
-                Some(&mut options),
-            ) {
-                Ok(patch) => patch,
-                Err(_) => todo!("This needs to be handled"),
-            };
-
-            let mut hunks = SumTree::<DiffHunk<Anchor>>::new();
-            let mut delta = 0i64;
-            for i in 0..patch.num_hunks() {
-                let diff_line_item_count = patch.num_lines_in_hunk(i).unwrap();
-
-                // if diff_line_item_count == 0 {
-                //     continue;
-                // }
-
-                // let calc_line_diff_hunk = || {
-
-                // };
-
-                // let first_line = patch.line_in_hunk(0).unwrap();
-                // let mut hunk =
-
-                for j in 0..diff_line_item_count {
-                    let line = patch.line_in_hunk(i, j).unwrap();
-
-                    let hunk = match line.origin_value() {
-                        libgit::DiffLineType::Addition => {
-                            let buffer_start = line.content_offset();
-                            let buffer_end = buffer_start as usize + line.content().len();
-                            let head_offset = (buffer_start - delta) as usize;
-                            delta += line.content().len() as i64;
-                            DiffHunk {
-                                buffer_range: buffer.anchor_before(buffer_start as usize)
-                                    ..buffer.anchor_after(buffer_end),
-                                head_range: head_offset..head_offset,
-                            }
-                        }
-                        libgit::DiffLineType::Deletion => {
-                            let head_start = line.content_offset();
-                            let head_end = head_start as usize + line.content().len();
-                            let buffer_offset = (head_start + delta) as usize;
-                            delta -= line.content().len() as i64;
-                            DiffHunk {
-                                buffer_range: buffer.anchor_before(buffer_offset)
-                                    ..buffer.anchor_after(buffer_offset),
-                                head_range: (head_start as usize)..head_end,
-                            }
-                        }
-
-                        libgit::DiffLineType::AddEOFNL => todo!(),
-                        libgit::DiffLineType::ContextEOFNL => todo!(),
-                        libgit::DiffLineType::DeleteEOFNL => todo!(),
-                        libgit::DiffLineType::Context => unreachable!(),
-                        libgit::DiffLineType::FileHeader => continue,
-                        libgit::DiffLineType::HunkHeader => continue,
-                        libgit::DiffLineType::Binary => continue,
-                    };
-
-                    let mut combined = false;
-                    hunks.update_last(
-                        |last_hunk| {
-                            if last_hunk.head_range.end == hunk.head_range.start {
-                                last_hunk.head_range.end = hunk.head_range.end;
-                                last_hunk.buffer_range.end = hunk.buffer_range.end;
-                                combined = true;
-                            }
-                        },
-                        buffer,
-                    );
-                    if !combined {
-                        hunks.push(hunk, buffer);
-                    }
-                }
-            }
-
-            // let iter = HunkIter::diff(head_text.as_bytes(), buffer_bytes);
-            // if let Some(mut iter) = iter {
-            //     let mut hunks = SumTree::new();
-            //     while let Some(hunk) = iter.next(buffer) {
-            //         hunks.push(hunk, buffer);
-            //     }
-            //     println!("========");
-            //     hunks
-            // } else {
-            //     SumTree::new()
-            // }
-            hunks
-        } else {
-            SumTree::new()
+        let mut instance = BufferDiff {
+            last_update_version: buffer.version().clone(),
+            snapshot: BufferDiffSnapshot {
+                tree: SumTree::new(),
+            },
         };
 
-        BufferDiff {
-            last_update_version: buffer.version().clone(),
-            snapshot: BufferDiffSnapshot { tree: hunks },
+        if let Some(head_text) = head_text {
+            instance.update(head_text, buffer);
         }
+
+        instance
     }
 
     pub fn snapshot(&self) -> BufferDiffSnapshot {
         self.snapshot.clone()
     }
 
-    pub fn update(&mut self, head: &Rope, buffer: &text::BufferSnapshot) {
-        //     let expand_by = 20;
-        //     let combine_distance = 5;
-
-        //     struct EditRange {
-        //         head_start: u32,
-        //         head_end: u32,
-        //         buffer_start: u32,
-        //         buffer_end: u32,
-        //     }
-
-        //     let mut ranges = Vec::<EditRange>::new();
-
-        //     for edit in buffer.edits_since::<Point>(&self.last_update_version) {
-        //         //This bit is extremely wrong, this is not where these row lines should come from
-        //         let head_start = edit.old.start.row.saturating_sub(expand_by);
-        //         let head_end = (edit.old.end.row + expand_by).min(head.summary().lines.row + 1);
-
-        //         let buffer_start = edit.new.start.row.saturating_sub(expand_by);
-        //         let buffer_end = (edit.new.end.row + expand_by).min(buffer.row_count());
-
-        //         if let Some(last_range) = ranges.last_mut() {
-        //             let head_distance = last_range.head_end.abs_diff(head_end);
-        //             let buffer_distance = last_range.buffer_end.abs_diff(buffer_end);
-
-        //             if head_distance <= combine_distance || buffer_distance <= combine_distance {
-        //                 last_range.head_start = last_range.head_start.min(head_start);
-        //                 last_range.head_end = last_range.head_end.max(head_end);
-
-        //                 last_range.buffer_start = last_range.buffer_start.min(buffer_start);
-        //                 last_range.buffer_end = last_range.buffer_end.max(buffer_end);
-        //             } else {
-        //                 ranges.push(EditRange {
-        //                     head_start,
-        //                     head_end,
-        //                     buffer_start,
-        //                     buffer_end,
-        //                 });
-        //             }
-        //         } else {
-        //             ranges.push(EditRange {
-        //                 head_start,
-        //                 head_end,
-        //                 buffer_start,
-        //                 buffer_end,
-        //             });
-        //         }
-        //     }
-
-        //     self.last_update_version = buffer.version().clone();
-
-        //     let mut new_hunks = SumTree::new();
-        //     let mut cursor = self.snapshot.tree.cursor::<HunkHeadEnd>();
-
-        //     for range in ranges {
-        //         let head_range = range.head_start..range.head_end;
-        //         let head_slice = head.slice_rows(head_range.clone());
-        //         let head_str = head_slice.to_string();
-
-        //         let buffer_range = range.buffer_start..range.buffer_end;
-        //         let buffer_slice = buffer.as_rope().slice_rows(buffer_range.clone());
-        //         let buffer_str = buffer_slice.to_string();
-
-        //         println!("diffing head {:?}, buffer {:?}", head_range, buffer_range);
-
-        //         let mut iter = match HunkIter::diff(head_str.as_bytes(), buffer_str.as_bytes()) {
-        //             Some(iter) => iter,
-        //             None => continue,
-        //         };
-
-        //         while let Some(hunk) = iter.next(buffer) {
-        //             println!("hunk");
-        //             let prefix = cursor.slice(&HunkHeadEnd(hunk.head_range.end), Bias::Right, buffer);
-        //             println!("prefix len: {}", prefix.iter().count());
-        //             new_hunks.extend(prefix.iter().cloned(), buffer);
-
-        //             new_hunks.push(hunk.clone(), buffer);
-
-        //             cursor.seek(&HunkHeadEnd(hunk.head_range.end), Bias::Right, buffer);
-        //             println!("item: {:?}", cursor.item());
-        //             if let Some(item) = cursor.item() {
-        //                 if item.head_range.end <= hunk.head_range.end {
-        //                     println!("skipping");
-        //                     cursor.next(buffer);
-        //                 }
-        //             }
-        //         }
-        //     }
-
-        //     new_hunks.extend(
-        //         cursor
-        //             .suffix(buffer)
-        //             .iter()
-        //             .map(|i| {
-        //                 println!("extending with {i:?}");
-        //                 i
-        //             })
-        //             .cloned(),
-        //         buffer,
-        //     );
-        //     drop(cursor);
-
-        //     self.snapshot.tree = new_hunks;
+    pub fn update(&mut self, head_text: &str, buffer: &text::BufferSnapshot) {
+        let buffer_string = buffer.as_rope().to_string();
+        let buffer_bytes = buffer_string.as_bytes();
+
+        let mut options = GitOptions::default();
+        options.context_lines(0);
+        let patch = match GitPatch::from_buffers(
+            head_text.as_bytes(),
+            None,
+            buffer_bytes,
+            None,
+            Some(&mut options),
+        ) {
+            Ok(patch) => patch,
+            Err(_) => todo!("This needs to be handled"),
+        };
+
+        let mut hunks = SumTree::<DiffHunk<Anchor>>::new();
+        let mut delta = 0i64;
+        for hunk_index in 0..patch.num_hunks() {
+            for line_index in 0..patch.num_lines_in_hunk(hunk_index).unwrap() {
+                let line = patch.line_in_hunk(hunk_index, line_index).unwrap();
+
+                let hunk = match line.origin_value() {
+                    libgit::DiffLineType::Addition => {
+                        let buffer_start = line.content_offset();
+                        let buffer_end = buffer_start as usize + line.content().len();
+                        let head_offset = (buffer_start - delta) as usize;
+                        delta += line.content().len() as i64;
+                        DiffHunk {
+                            buffer_range: buffer.anchor_before(buffer_start as usize)
+                                ..buffer.anchor_after(buffer_end),
+                            head_range: head_offset..head_offset,
+                        }
+                    }
+
+                    libgit::DiffLineType::Deletion => {
+                        let head_start = line.content_offset();
+                        let head_end = head_start as usize + line.content().len();
+                        let buffer_offset = (head_start + delta) as usize;
+                        delta -= line.content().len() as i64;
+                        DiffHunk {
+                            buffer_range: buffer.anchor_before(buffer_offset)
+                                ..buffer.anchor_after(buffer_offset),
+                            head_range: (head_start as usize)..head_end,
+                        }
+                    }
+
+                    libgit::DiffLineType::AddEOFNL => todo!(),
+                    libgit::DiffLineType::ContextEOFNL => todo!(),
+                    libgit::DiffLineType::DeleteEOFNL => todo!(),
+
+                    libgit::DiffLineType::FileHeader => continue,
+                    libgit::DiffLineType::HunkHeader => continue,
+                    libgit::DiffLineType::Binary => continue,
+
+                    //We specifically tell git to not give us context lines
+                    libgit::DiffLineType::Context => unreachable!(),
+                };
+
+                let mut combined = false;
+                hunks.update_last(
+                    |last_hunk| {
+                        if last_hunk.head_range.end == hunk.head_range.start {
+                            last_hunk.head_range.end = hunk.head_range.end;
+                            last_hunk.buffer_range.end = hunk.buffer_range.end;
+                            combined = true;
+                        }
+                    },
+                    buffer,
+                );
+                if !combined {
+                    hunks.push(hunk, buffer);
+                }
+            }
+        }
+
+        self.snapshot.tree = hunks;
     }
 }