From 87a08f30eb6ddecac359bc4d710a9549727456ab Mon Sep 17 00:00:00 2001 From: Cole Miller Date: Mon, 20 Jul 2026 12:17:02 -0400 Subject: [PATCH] Use diff summary for action log stats instead of iterating hunks (#61272) The diff already has a constant-time accessor to get the counts of added/removed rows, use that instead of iterating hunks on the foreground. Release Notes: - Improved performance in agent threads with many file changes. --- crates/action_log/src/action_log.rs | 25 ++++++------------- .../src/conversation_view/thread_view.rs | 2 +- crates/buffer_diff/src/buffer_diff.rs | 6 +++++ 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/crates/action_log/src/action_log.rs b/crates/action_log/src/action_log.rs index 60bc58701a..6e2de669de 100644 --- a/crates/action_log/src/action_log.rs +++ b/crates/action_log/src/action_log.rs @@ -1047,23 +1047,12 @@ pub struct DiffStats { } impl DiffStats { - pub fn single_file(buffer: &Buffer, diff: &BufferDiff, cx: &App) -> Self { - let mut stats = DiffStats::default(); - let diff_snapshot = diff.snapshot(cx); - let buffer_snapshot = buffer.snapshot(); - let base_text = diff_snapshot.base_text(); - - for hunk in diff_snapshot.hunks(&buffer_snapshot) { - let added_rows = hunk.range.end.row.saturating_sub(hunk.range.start.row); - stats.lines_added += added_rows; - - let base_start = hunk.diff_base_byte_range.start.to_point(base_text).row; - let base_end = hunk.diff_base_byte_range.end.to_point(base_text).row; - let removed_rows = base_end.saturating_sub(base_start); - stats.lines_removed += removed_rows; + pub fn single_file(diff: &BufferDiff) -> Self { + let (lines_added, lines_removed) = diff.changed_row_counts(); + DiffStats { + lines_added, + lines_removed, } - - stats } pub fn all_files( @@ -1071,8 +1060,8 @@ impl DiffStats { cx: &App, ) -> Self { let mut total = DiffStats::default(); - for (buffer, diff) in changed_buffers { - let stats = DiffStats::single_file(buffer.read(cx), diff.read(cx), cx); + for (_, diff) in changed_buffers { + let stats = DiffStats::single_file(diff.read(cx)); total.lines_added += stats.lines_added; total.lines_removed += stats.lines_removed; } diff --git a/crates/agent_ui/src/conversation_view/thread_view.rs b/crates/agent_ui/src/conversation_view/thread_view.rs index 35b7145a1b..2cface9521 100644 --- a/crates/agent_ui/src/conversation_view/thread_view.rs +++ b/crates/agent_ui/src/conversation_view/thread_view.rs @@ -3215,7 +3215,7 @@ impl ThreadView { .size(IconSize::Small) }); - let file_stats = DiffStats::single_file(buffer.read(cx), diff.read(cx), cx); + let file_stats = DiffStats::single_file(diff.read(cx)); let buttons = self.render_edited_files_buttons( index, diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index dad94c4b01..b73c64ff61 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/crates/buffer_diff/src/buffer_diff.rs @@ -2122,6 +2122,12 @@ impl BufferDiff { .is_some_and(|diff_snapshot| diff_snapshot.base_text_exists) } + pub fn changed_row_counts(&self) -> (u32, u32) { + self.diff_snapshot + .as_ref() + .map_or((0, 0), |diff_snapshot| diff_snapshot.changed_row_counts()) + } + pub fn snapshot(&self, cx: &App) -> BufferDiffSnapshot { let mut snapshot = self.diff_snapshot.clone().unwrap_or_else(|| { let base_text = self.base_text_buffer.read(cx).snapshot();