@@ -216,7 +216,20 @@ impl ActionLog {
loop {
futures::select_biased! {
buffer_update = buffer_updates.next() => {
- if let Some((author, buffer_snapshot)) = buffer_update {
+ if let Some((mut author, mut buffer_snapshot)) = buffer_update {
+ // TODO kb `buffer.edit(` made by agent input below fires off this code path again
+ // as we react on buffer edits and send them under "user" edits here again and again.
+ // Below is a stub to deduplicate things, but this should be done on the editor level
+
+ // Drain any pending updates and keep only the latest snapshot.
+ // This coalesces rapid edits to avoid repeatedly recalculating diffs.
+ // while let Ok(Some((next_author, next_snapshot))) = buffer_updates.try_next() {
+ // // If any update was from Agent, treat the coalesced update as Agent
+ // if matches!(next_author, ChangeAuthor::Agent) {
+ // author = ChangeAuthor::Agent;
+ // }
+ // buffer_snapshot = next_snapshot;
+ // }
Self::track_edits(&this, &buffer, author, buffer_snapshot, cx).await?;
} else {
break;
@@ -246,39 +259,50 @@ impl ActionLog {
.get_mut(buffer)
.context("buffer not tracked")?;
- let rebase = cx.background_spawn({
- let mut base_text = tracked_buffer.diff_base.clone();
- let old_snapshot = tracked_buffer.snapshot.clone();
- let new_snapshot = buffer_snapshot.clone();
- let unreviewed_edits = tracked_buffer.unreviewed_edits.clone();
- let edits = diff_snapshots(&old_snapshot, &new_snapshot);
- async move {
- if let ChangeAuthor::User = author {
- apply_non_conflicting_edits(
- &unreviewed_edits,
- edits,
- &mut base_text,
- new_snapshot.as_rope(),
- );
- }
+ let old_snapshot = tracked_buffer.snapshot.clone();
+ let new_snapshot = buffer_snapshot.clone();
- (Arc::new(base_text.to_string()), base_text)
- }
- });
+ if !new_snapshot.version().changed_since(old_snapshot.version()) {
+ Ok(None)
+ } else {
+ let rebase = cx.background_spawn({
+ let mut base_text = tracked_buffer.diff_base.clone();
+
+ let unreviewed_edits = tracked_buffer.unreviewed_edits.clone();
+ let edits = diff_snapshots(&old_snapshot, &new_snapshot);
+ async move {
+ if let ChangeAuthor::User = author {
+ apply_non_conflicting_edits(
+ &unreviewed_edits,
+ edits,
+ &mut base_text,
+ new_snapshot.as_rope(),
+ );
+ }
+
+ (Arc::new(base_text.to_string()), base_text)
+ }
+ });
- anyhow::Ok(rebase)
+ anyhow::Ok(Some(rebase))
+ }
})??;
- let (new_base_text, new_diff_base) = rebase.await;
- Self::update_diff(
- this,
- buffer,
- buffer_snapshot,
- new_base_text,
- new_diff_base,
- cx,
- )
- .await
+ if let Some(rebase) = rebase {
+ let (new_base_text, new_diff_base) = rebase.await;
+
+ Self::update_diff(
+ this,
+ buffer,
+ buffer_snapshot,
+ new_base_text,
+ new_diff_base,
+ cx,
+ )
+ .await?;
+ }
+
+ Ok(())
}
async fn keep_committed_edits(
@@ -1483,8 +1483,18 @@ impl AgentDiff {
};
let multibuffer = editor.read(cx).buffer().clone();
+ let new_diff = diff_handle.update(cx, |original_diff, cx| {
+ cx.new(|cx| buffer_diff::BufferDiff::new(original_diff.base_text(), cx))
+ });
multibuffer.update(cx, |multibuffer, cx| {
- multibuffer.add_diff(diff_handle.clone(), cx);
+ // TODO kb is there a better way?
+ // This will force real buffer and agent panel's one to calculate diffs independently.
+ // Buffer's calculation will be non-instant (debounced by rapid edits) and theoretically may be different
+ // (as the agent one could be optimized for streaming)
+
+ multibuffer.add_diff(new_diff, cx);
+ // If we keep the diff handle shared, real buffer will flicker if the line wrap is enabled and the agent edits multiple lines.
+ // multibuffer.add_diff(diff_handle.clone(), cx);
});
let reviewing_state = EditorState::Reviewing;