sweep: Coalesce edits based on line distance rather than time (#43006)

Release Notes:

- N/A

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
This commit is contained in:
Agus Zubiaga
2025-11-19 20:32:14 +00:00
committed by GitHub
co-authored by Ben Kunkle
parent b6c8c3f3d9
commit ec220dcc05
+54 -50
View File
@@ -8,7 +8,9 @@ use feature_flags::FeatureFlag;
use futures::AsyncReadExt as _;
use gpui::{App, AppContext, Context, Entity, EntityId, Global, Task, WeakEntity};
use http_client::{AsyncBody, Method};
use language::{Anchor, Buffer, BufferSnapshot, EditPreview, ToOffset as _, ToPoint, text_diff};
use language::{
Anchor, Buffer, BufferSnapshot, EditPreview, Point, ToOffset as _, ToPoint, text_diff,
};
use project::Project;
use release_channel::{AppCommitSha, AppVersion};
use std::collections::{VecDeque, hash_map};
@@ -28,8 +30,8 @@ use workspace::Workspace;
use crate::api::{AutocompleteRequest, AutocompleteResponse, FileChunk};
const BUFFER_CHANGE_GROUPING_INTERVAL: Duration = Duration::from_secs(1);
const MAX_EVENT_COUNT: usize = 16;
const CHANGE_GROUPING_LINE_SPAN: u32 = 8;
const MAX_EVENT_COUNT: usize = 6;
const SWEEP_API_URL: &str = "https://autocomplete.sweep.dev/backend/next_edit_autocomplete";
@@ -143,40 +145,6 @@ impl SweepAi {
}
}
fn push_event(sweep_ai_project: &mut SweepAiProject, event: Event) {
let events = &mut sweep_ai_project.events;
if let Some(Event::BufferChange {
new_snapshot: last_new_snapshot,
timestamp: last_timestamp,
..
}) = events.back_mut()
{
// Coalesce edits for the same buffer when they happen one after the other.
let Event::BufferChange {
old_snapshot,
new_snapshot,
timestamp,
} = &event;
if timestamp.duration_since(*last_timestamp) <= BUFFER_CHANGE_GROUPING_INTERVAL
&& old_snapshot.remote_id() == last_new_snapshot.remote_id()
&& old_snapshot.version == last_new_snapshot.version
{
*last_new_snapshot = new_snapshot.clone();
*last_timestamp = *timestamp;
return;
}
}
if events.len() >= MAX_EVENT_COUNT {
// These are halved instead of popping to improve prompt caching.
events.drain(..MAX_EVENT_COUNT / 2);
}
events.push_back(event);
}
pub fn register_buffer(
&mut self,
buffer: &Entity<Buffer>,
@@ -314,6 +282,8 @@ impl SweepAi {
})
.collect();
eprintln!("{recent_changes}");
let request_body = AutocompleteRequest {
debug_info,
repo_name,
@@ -420,24 +390,58 @@ impl SweepAi {
buffer: &Entity<Buffer>,
project: &Entity<Project>,
cx: &mut Context<Self>,
) -> BufferSnapshot {
) {
let sweep_ai_project = self.get_or_init_sweep_ai_project(project, cx);
let registered_buffer = Self::register_buffer_impl(sweep_ai_project, buffer, project, cx);
let new_snapshot = buffer.read(cx).snapshot();
if new_snapshot.version != registered_buffer.snapshot.version {
let old_snapshot = mem::replace(&mut registered_buffer.snapshot, new_snapshot.clone());
Self::push_event(
sweep_ai_project,
Event::BufferChange {
old_snapshot,
new_snapshot: new_snapshot.clone(),
timestamp: Instant::now(),
},
);
if new_snapshot.version == registered_buffer.snapshot.version {
return;
}
new_snapshot
let old_snapshot = mem::replace(&mut registered_buffer.snapshot, new_snapshot.clone());
let end_edit_anchor = new_snapshot
.anchored_edits_since::<Point>(&old_snapshot.version)
.last()
.map(|(_, range)| range.end);
let events = &mut sweep_ai_project.events;
if let Some(Event::BufferChange {
new_snapshot: last_new_snapshot,
end_edit_anchor: last_end_edit_anchor,
..
}) = events.back_mut()
{
let is_next_snapshot_of_same_buffer = old_snapshot.remote_id()
== last_new_snapshot.remote_id()
&& old_snapshot.version == last_new_snapshot.version;
let should_coalesce = is_next_snapshot_of_same_buffer
&& end_edit_anchor
.as_ref()
.zip(last_end_edit_anchor.as_ref())
.is_some_and(|(a, b)| {
let a = a.to_point(&new_snapshot);
let b = b.to_point(&new_snapshot);
a.row.abs_diff(b.row) <= CHANGE_GROUPING_LINE_SPAN
});
if should_coalesce {
*last_end_edit_anchor = end_edit_anchor;
*last_new_snapshot = new_snapshot;
return;
}
}
if events.len() >= MAX_EVENT_COUNT {
events.pop_front();
}
events.push_back(Event::BufferChange {
old_snapshot,
new_snapshot,
end_edit_anchor,
});
}
}
@@ -451,7 +455,7 @@ pub enum Event {
BufferChange {
old_snapshot: BufferSnapshot,
new_snapshot: BufferSnapshot,
timestamp: Instant,
end_edit_anchor: Option<Anchor>,
},
}