Restructure git diff state management to allow viewing buffers with different diff bases (#21258)
This is a pure refactor of our Git diff state management. Buffers are no longer are associated with one single diff (the unstaged changes). Instead, there is an explicit project API for retrieving a buffer's unstaged changes, and the `Editor` view layer is responsible for choosing what diff to associate with a buffer. The reason for this change is that we'll soon want to add multiple "git diff views" to Zed, one of which will show the *uncommitted* changes for a buffer. But that view will need to co-exist with other views of the same buffer, which may want to show the unstaged changes. ### Todo * [x] Get git gutter and git hunks working with new structure * [x] Update editor tests to use new APIs * [x] Update buffer tests * [x] Restructure remoting/collab protocol * [x] Update assertions about staged text in `random_project_collaboration_tests` * [x] Move buffer tests for git diff management to a new spot, using the new APIs Release Notes: - N/A --------- Co-authored-by: Richard <richard@zed.dev> Co-authored-by: Cole <cole@zed.dev> Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
parent
31796171de
commit
a2115e7242
29 changed files with 1832 additions and 1651 deletions
|
@ -4,7 +4,7 @@ use futures::{channel::mpsc, future::join_all};
|
|||
use gpui::{AppContext, EventEmitter, FocusableView, Model, Render, Subscription, Task, View};
|
||||
use language::{Buffer, BufferEvent, Capability};
|
||||
use multi_buffer::{ExcerptRange, MultiBuffer};
|
||||
use project::Project;
|
||||
use project::{buffer_store::BufferChangeSet, Project};
|
||||
use smol::stream::StreamExt;
|
||||
use std::{any::TypeId, ops::Range, rc::Rc, time::Duration};
|
||||
use text::ToOffset;
|
||||
|
@ -75,7 +75,7 @@ impl ProposedChangesEditor {
|
|||
title: title.into(),
|
||||
buffer_entries: Vec::new(),
|
||||
recalculate_diffs_tx,
|
||||
_recalculate_diffs_task: cx.spawn(|_, mut cx| async move {
|
||||
_recalculate_diffs_task: cx.spawn(|this, mut cx| async move {
|
||||
let mut buffers_to_diff = HashSet::default();
|
||||
while let Some(mut recalculate_diff) = recalculate_diffs_rx.next().await {
|
||||
buffers_to_diff.insert(recalculate_diff.buffer);
|
||||
|
@ -96,12 +96,37 @@ impl ProposedChangesEditor {
|
|||
}
|
||||
}
|
||||
|
||||
join_all(buffers_to_diff.drain().filter_map(|buffer| {
|
||||
buffer
|
||||
.update(&mut cx, |buffer, cx| buffer.recalculate_diff(cx))
|
||||
.ok()?
|
||||
}))
|
||||
.await;
|
||||
let recalculate_diff_futures = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
buffers_to_diff
|
||||
.drain()
|
||||
.filter_map(|buffer| {
|
||||
let buffer = buffer.read(cx);
|
||||
let base_buffer = buffer.base_buffer()?;
|
||||
let buffer = buffer.text_snapshot();
|
||||
let change_set = this.editor.update(cx, |editor, _| {
|
||||
Some(
|
||||
editor
|
||||
.diff_map
|
||||
.diff_bases
|
||||
.get(&buffer.remote_id())?
|
||||
.change_set
|
||||
.clone(),
|
||||
)
|
||||
})?;
|
||||
Some(change_set.update(cx, |change_set, cx| {
|
||||
change_set.set_base_text(
|
||||
base_buffer.read(cx).text(),
|
||||
buffer,
|
||||
cx,
|
||||
)
|
||||
}))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
join_all(recalculate_diff_futures).await;
|
||||
}
|
||||
None
|
||||
}),
|
||||
|
@ -154,6 +179,7 @@ impl ProposedChangesEditor {
|
|||
});
|
||||
|
||||
let mut buffer_entries = Vec::new();
|
||||
let mut new_change_sets = Vec::new();
|
||||
for location in locations {
|
||||
let branch_buffer;
|
||||
if let Some(ix) = self
|
||||
|
@ -166,6 +192,15 @@ impl ProposedChangesEditor {
|
|||
buffer_entries.push(entry);
|
||||
} else {
|
||||
branch_buffer = location.buffer.update(cx, |buffer, cx| buffer.branch(cx));
|
||||
new_change_sets.push(cx.new_model(|cx| {
|
||||
let mut change_set = BufferChangeSet::new(branch_buffer.read(cx));
|
||||
let _ = change_set.set_base_text(
|
||||
location.buffer.read(cx).text(),
|
||||
branch_buffer.read(cx).text_snapshot(),
|
||||
cx,
|
||||
);
|
||||
change_set
|
||||
}));
|
||||
buffer_entries.push(BufferEntry {
|
||||
branch: branch_buffer.clone(),
|
||||
base: location.buffer.clone(),
|
||||
|
@ -187,7 +222,10 @@ impl ProposedChangesEditor {
|
|||
|
||||
self.buffer_entries = buffer_entries;
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.change_selections(None, cx, |selections| selections.refresh())
|
||||
editor.change_selections(None, cx, |selections| selections.refresh());
|
||||
for change_set in new_change_sets {
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -217,14 +255,14 @@ impl ProposedChangesEditor {
|
|||
})
|
||||
.ok();
|
||||
}
|
||||
BufferEvent::DiffBaseChanged => {
|
||||
self.recalculate_diffs_tx
|
||||
.unbounded_send(RecalculateDiff {
|
||||
buffer,
|
||||
debounce: false,
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
// BufferEvent::DiffBaseChanged => {
|
||||
// self.recalculate_diffs_tx
|
||||
// .unbounded_send(RecalculateDiff {
|
||||
// buffer,
|
||||
// debounce: false,
|
||||
// })
|
||||
// .ok();
|
||||
// }
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +411,7 @@ impl BranchBufferSemanticsProvider {
|
|||
positions: &[text::Anchor],
|
||||
cx: &AppContext,
|
||||
) -> Option<Model<Buffer>> {
|
||||
let base_buffer = buffer.read(cx).diff_base_buffer()?;
|
||||
let base_buffer = buffer.read(cx).base_buffer()?;
|
||||
let version = base_buffer.read(cx).version();
|
||||
if positions
|
||||
.iter()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue