Use word_diffs

Bennet Bo Fenner created

Change summary

crates/acp_thread/src/diff.rs         |   4 
crates/buffer_diff/src/buffer_diff.rs | 100 +++++++++++++++++-----------
2 files changed, 62 insertions(+), 42 deletions(-)

Detailed changes

crates/acp_thread/src/diff.rs 🔗

@@ -441,10 +441,10 @@ impl PendingDiff {
                     async move {
                         let hunks = compute_hunks(&base_snapshot, &snapshot, operations);
                         BufferDiffUpdate::from_hunks(
-                            base_text.clone(),
+                            base_text,
+                            base_snapshot.as_rope(),
                             snapshot,
                             hunks,
-                            // FIXME options
                             Some(DiffOptions::default()),
                         )
                     }

crates/buffer_diff/src/buffer_diff.rs 🔗

@@ -54,18 +54,23 @@ impl BufferDiffUpdate {
     // FIXME thread through diff options to control word diff
     pub fn from_hunks(
         base_text: Arc<str>,
+        base_snapshot: &Rope,
         buffer_snapshot: text::BufferSnapshot,
         edits: Patch<usize>,
         diff_options: Option<DiffOptions>,
     ) -> Self {
         let hunks = edits.into_iter().map(|edit| {
-            let old_text = &base_text[edit.old.clone()];
-            let new_text = buffer_snapshot
-                .text_for_range(edit.new.clone())
-                .collect::<String>();
+            let buffer_range = buffer_snapshot.anchor_after(edit.new.start)
+                ..buffer_snapshot.anchor_after(edit.new.end);
 
             let (base_word_diffs, buffer_word_diffs) = if let Some(options) = &diff_options {
-                word_diff_ranges(old_text, &new_text, options.clone())
+                word_diffs(
+                    base_snapshot,
+                    edit.old.clone(),
+                    &buffer_snapshot,
+                    buffer_range,
+                    options,
+                )
             } else {
                 (Vec::new(), Vec::new())
             };
@@ -74,13 +79,7 @@ impl BufferDiffUpdate {
                     ..buffer_snapshot.anchor_before(edit.new.end),
                 diff_base_byte_range: edit.old,
                 base_word_diffs,
-                buffer_word_diffs: buffer_word_diffs
-                    .into_iter()
-                    .map(|range| {
-                        buffer_snapshot.anchor_after(range.start)
-                            ..buffer_snapshot.anchor_after(range.end)
-                    })
-                    .collect::<Vec<_>>(),
+                buffer_word_diffs,
             }
         });
 
@@ -1461,35 +1460,16 @@ fn process_patch_hunk(
     let end = Point::new(buffer_row_range.end, 0);
     let buffer_range = buffer.anchor_before(start)..buffer.anchor_before(end);
 
-    let base_line_count = line_item_count.saturating_sub(buffer_row_range.len());
-
-    let (base_word_diffs, buffer_word_diffs) = if let Some(diff_options) = diff_options
-        && !buffer_row_range.is_empty()
-        && base_line_count == buffer_row_range.len()
-        && diff_options.max_word_diff_line_count >= base_line_count
-    {
-        let base_text: String = diff_base
-            .chunks_in_range(diff_base_byte_range.clone())
-            .collect();
-
-        let buffer_text: String = buffer.text_for_range(buffer_range.clone()).collect();
-
-        let (base_word_diffs, buffer_word_diffs_relative) =
-            word_diff_ranges(&base_text, &buffer_text, diff_options.clone());
-
-        let buffer_start_offset = buffer_range.start.to_offset(buffer);
-        let buffer_word_diffs = buffer_word_diffs_relative
-            .into_iter()
-            .map(|range| {
-                let start = buffer.anchor_after(buffer_start_offset + range.start);
-                let end = buffer.anchor_after(buffer_start_offset + range.end);
-                start..end
-            })
-            .collect();
-
-        (base_word_diffs, buffer_word_diffs)
+    let (base_word_diffs, buffer_word_diffs) = if let Some(options) = diff_options {
+        word_diffs(
+            diff_base,
+            diff_base_byte_range.clone(),
+            buffer,
+            buffer_range.clone(),
+            options,
+        )
     } else {
-        (Vec::default(), Vec::default())
+        (Vec::new(), Vec::new())
     };
 
     InternalDiffHunk {
@@ -1500,6 +1480,46 @@ fn process_patch_hunk(
     }
 }
 
+fn word_diffs(
+    diff_base: &Rope,
+    diff_base_byte_range: Range<usize>,
+    buffer: &text::BufferSnapshot,
+    buffer_range: Range<Anchor>,
+    options: &DiffOptions,
+) -> (Vec<Range<usize>>, Vec<Range<Anchor>>) {
+    let buffer_rows = buffer.text_summary_for_range::<Point, _>(buffer_range.clone());
+    let base_text_rows = diff_base
+        .cursor(diff_base_byte_range.start)
+        .summary::<Point>(diff_base_byte_range.end);
+    if buffer_rows == Point::zero()
+        || base_text_rows.row != buffer_rows.row
+        || base_text_rows.row > options.max_word_diff_line_count as u32
+    {
+        return (Vec::default(), Vec::default());
+    }
+
+    let base_text: String = diff_base
+        .chunks_in_range(diff_base_byte_range.clone())
+        .collect();
+
+    let buffer_text: String = buffer.text_for_range(buffer_range.clone()).collect();
+
+    let (base_word_diffs, buffer_word_diffs_relative) =
+        word_diff_ranges(&base_text, &buffer_text, options.clone());
+
+    let buffer_start_offset = buffer_range.start.to_offset(buffer);
+    let buffer_word_diffs = buffer_word_diffs_relative
+        .into_iter()
+        .map(|range| {
+            let start = buffer.anchor_after(buffer_start_offset + range.start);
+            let end = buffer.anchor_after(buffer_start_offset + range.end);
+            start..end
+        })
+        .collect();
+
+    (base_word_diffs, buffer_word_diffs)
+}
+
 impl std::fmt::Debug for BufferDiff {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.debug_struct("BufferChangeSet")