From df3d956e63380b90382aba494f9bb01faaa1d328 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Wed, 2 Jul 2025 21:16:26 -0300 Subject: [PATCH] Only show hunk ranges --- crates/acp/src/acp.rs | 83 +++++++++++++++++++++-------------- crates/acp/src/thread_view.rs | 18 ++++---- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/crates/acp/src/acp.rs b/crates/acp/src/acp.rs index 175ab7b1ee892803ddf295d9d192844f5f04177d..683329aa019113841fabe7c138ea1ae298ef7b23 100644 --- a/crates/acp/src/acp.rs +++ b/crates/acp/src/acp.rs @@ -5,10 +5,10 @@ use agentic_coding_protocol::{self as acp, Role}; use anyhow::{Context as _, Result}; use buffer_diff::BufferDiff; use chrono::{DateTime, Utc}; -use editor::MultiBuffer; +use editor::{MultiBuffer, PathKey}; use futures::channel::oneshot; use gpui::{AppContext, Context, Entity, EventEmitter, SharedString, Task}; -use language::{Buffer, LanguageRegistry}; +use language::{Anchor, Buffer, Capability, LanguageRegistry, OffsetRangeExt as _}; use markdown::Markdown; use project::Project; use std::{mem, ops::Range, path::PathBuf, sync::Arc}; @@ -231,7 +231,7 @@ pub enum ToolCallContent { #[derive(Debug)] pub struct Diff { // todo! show path somewhere - buffer: Entity, + multibuffer: Entity, _path: PathBuf, _task: Task>, } @@ -248,46 +248,65 @@ impl Diff { new_text, } = diff; - let buffer = cx.new(|cx| Buffer::local(new_text, cx)); - let text_snapshot = buffer.read(cx).text_snapshot(); - let buffer_diff = cx.new(|cx| BufferDiff::new(&text_snapshot, cx)); - - let multibuffer = cx.new(|cx| { - let mut multibuffer = MultiBuffer::singleton(buffer.clone(), cx); - multibuffer.add_diff(buffer_diff.clone(), cx); - multibuffer + let multibuffer = cx.new(|_cx| MultiBuffer::without_headers(Capability::ReadOnly)); + + let new_buffer = cx.new(|cx| Buffer::local(new_text, cx)); + let old_buffer = cx.new(|cx| Buffer::local(old_text.unwrap_or("".into()), cx)); + let new_buffer_snapshot = new_buffer.read(cx).text_snapshot(); + let old_buffer_snapshot = old_buffer.read(cx).snapshot(); + let buffer_diff = cx.new(|cx| BufferDiff::new(&new_buffer_snapshot, cx)); + let diff_task = buffer_diff.update(cx, |diff, cx| { + diff.set_base_text( + old_buffer_snapshot, + Some(language_registry.clone()), + new_buffer_snapshot, + cx, + ) }); - Self { - buffer: multibuffer, - _path: path.clone(), - _task: cx.spawn(async move |cx| { - let diff_snapshot = BufferDiff::update_diff( - buffer_diff.clone(), - text_snapshot.clone(), - old_text.map(|o| o.into()), - true, - true, - None, - Some(language_registry.clone()), - cx, - ) - .await?; - - buffer_diff.update(cx, |diff, cx| { - diff.set_snapshot(diff_snapshot, &text_snapshot, cx) - })?; + let task = cx.spawn({ + let multibuffer = multibuffer.clone(); + let path = path.clone(); + async move |cx| { + diff_task.await?; + + multibuffer + .update(cx, |multibuffer, cx| { + let hunk_ranges = { + let buffer = new_buffer.read(cx); + let diff = buffer_diff.read(cx); + diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer, cx) + .map(|diff_hunk| diff_hunk.buffer_range.to_point(&buffer)) + .collect::>() + }; + + multibuffer.set_excerpts_for_path( + PathKey::for_buffer(&new_buffer, cx), + new_buffer.clone(), + hunk_ranges, + editor::DEFAULT_MULTIBUFFER_CONTEXT, + cx, + ); + multibuffer.add_diff(buffer_diff.clone(), cx); + }) + .log_err(); if let Some(language) = language_registry .language_for_file_path(&path) .await .log_err() { - buffer.update(cx, |buffer, cx| buffer.set_language(Some(language), cx))?; + new_buffer.update(cx, |buffer, cx| buffer.set_language(Some(language), cx))?; } anyhow::Ok(()) - }), + } + }); + + Self { + multibuffer, + _path: path, + _task: task, } } } diff --git a/crates/acp/src/thread_view.rs b/crates/acp/src/thread_view.rs index 2349dccc3d8cca8b71cfc7f31e27d17110207e3e..8d3e40da3cd7987e3547c9c8c86be55fd9e135aa 100644 --- a/crates/acp/src/thread_view.rs +++ b/crates/acp/src/thread_view.rs @@ -266,19 +266,19 @@ impl AcpThreadView { window: &mut Window, cx: &mut Context, ) { - let buffer = match ( - self.entry_diff_buffer(entry_ix, cx), + let multibuffer = match ( + self.entry_diff_multibuffer(entry_ix, cx), self.thread_entry_views.get(entry_ix), ) { - (Some(buffer), Some(Some(ThreadEntryView::Diff { editor }))) => { - if editor.read(cx).buffer() == &buffer { + (Some(multibuffer), Some(Some(ThreadEntryView::Diff { editor }))) => { + if editor.read(cx).buffer() == &multibuffer { // same buffer, all synced up return; } // new buffer, replace editor - buffer + multibuffer } - (Some(buffer), _) => buffer, + (Some(multibuffer), _) => multibuffer, (None, Some(Some(ThreadEntryView::Diff { .. }))) => { // no longer displaying a diff, drop editor self.thread_entry_views[entry_ix] = None; @@ -294,7 +294,7 @@ impl AcpThreadView { show_active_line_background: false, sized_by_content: true, }, - buffer.clone(), + multibuffer.clone(), None, window, cx, @@ -334,7 +334,7 @@ impl AcpThreadView { }); } - fn entry_diff_buffer(&self, entry_ix: usize, cx: &App) -> Option> { + fn entry_diff_multibuffer(&self, entry_ix: usize, cx: &App) -> Option> { let entry = self.thread()?.read(cx).entries().get(entry_ix)?; if let AgentThreadEntryContent::ToolCall(ToolCall { status, .. }) = &entry.content { @@ -347,7 +347,7 @@ impl AcpThreadView { .. } = status { - Some(diff.buffer.clone()) + Some(diff.multibuffer.clone()) } else { None }