diff --git a/crates/acp_thread/src/diff.rs b/crates/acp_thread/src/diff.rs index e205dfa4df6423d8635c2f55563b0ad093505a2e..7e412a71c2c6838cc844cac2a37266517e1cf4a0 100644 --- a/crates/acp_thread/src/diff.rs +++ b/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()), ) } diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index ee7a259e6980c2f96182ff833e2a889b44b7b80e..2d5a9fbe7c60c371310ff28cbafb94c26d42847a 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/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, + base_snapshot: &Rope, buffer_snapshot: text::BufferSnapshot, edits: Patch, diff_options: Option, ) -> 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::(); + 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::>(), + 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, + buffer: &text::BufferSnapshot, + buffer_range: Range, + options: &DiffOptions, +) -> (Vec>, Vec>) { + let buffer_rows = buffer.text_summary_for_range::(buffer_range.clone()); + let base_text_rows = diff_base + .cursor(diff_base_byte_range.start) + .summary::(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")