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
|
@ -25,7 +25,7 @@ pub mod search_history;
|
|||
mod yarn;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use buffer_store::{BufferStore, BufferStoreEvent};
|
||||
use buffer_store::{BufferChangeSet, BufferStore, BufferStoreEvent};
|
||||
use client::{proto, Client, Collaborator, PendingEntitySubscription, TypedEnvelope, UserStore};
|
||||
use clock::ReplicaId;
|
||||
use collections::{BTreeSet, HashMap, HashSet};
|
||||
|
@ -1821,6 +1821,20 @@ impl Project {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn open_unstaged_changes(
|
||||
&mut self,
|
||||
buffer: Model<Buffer>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Model<BufferChangeSet>>> {
|
||||
if self.is_disconnected(cx) {
|
||||
return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
|
||||
}
|
||||
|
||||
self.buffer_store.update(cx, |buffer_store, cx| {
|
||||
buffer_store.open_unstaged_changes(buffer, cx)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn open_buffer_by_id(
|
||||
&mut self,
|
||||
id: BufferId,
|
||||
|
@ -2269,10 +2283,7 @@ impl Project {
|
|||
event: &BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Option<()> {
|
||||
if matches!(
|
||||
event,
|
||||
BufferEvent::Edited { .. } | BufferEvent::Reloaded | BufferEvent::DiffBaseChanged
|
||||
) {
|
||||
if matches!(event, BufferEvent::Edited { .. } | BufferEvent::Reloaded) {
|
||||
self.request_buffer_diff_recalculation(&buffer, cx);
|
||||
}
|
||||
|
||||
|
@ -2369,34 +2380,32 @@ impl Project {
|
|||
}
|
||||
|
||||
fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext<Self>) -> Task<()> {
|
||||
let buffers = self.buffers_needing_diff.drain().collect::<Vec<_>>();
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
let tasks: Vec<_> = buffers
|
||||
.iter()
|
||||
.filter_map(|buffer| {
|
||||
let buffer = buffer.upgrade()?;
|
||||
buffer
|
||||
.update(&mut cx, |buffer, cx| buffer.recalculate_diff(cx))
|
||||
.ok()
|
||||
.flatten()
|
||||
})
|
||||
.collect();
|
||||
|
||||
futures::future::join_all(tasks).await;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
if this.buffers_needing_diff.is_empty() {
|
||||
// TODO: Would a `ModelContext<Project>.notify()` suffice here?
|
||||
for buffer in buffers {
|
||||
if let Some(buffer) = buffer.upgrade() {
|
||||
buffer.update(cx, |_, cx| cx.notify());
|
||||
loop {
|
||||
let task = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
let buffers = this
|
||||
.buffers_needing_diff
|
||||
.drain()
|
||||
.filter_map(|buffer| buffer.upgrade())
|
||||
.collect::<Vec<_>>();
|
||||
if buffers.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(this.buffer_store.update(cx, |buffer_store, cx| {
|
||||
buffer_store.recalculate_buffer_diffs(buffers, cx)
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
if let Some(task) = task {
|
||||
task.await;
|
||||
} else {
|
||||
this.recalculate_buffer_diffs(cx).detach();
|
||||
break;
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -4149,6 +4158,10 @@ impl Project {
|
|||
.read(cx)
|
||||
.language_servers_for_buffer(buffer, cx)
|
||||
}
|
||||
|
||||
pub fn buffer_store(&self) -> &Model<BufferStore> {
|
||||
&self.buffer_store
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_code_actions(code_actions: &HashMap<String, bool>) -> Vec<lsp::CodeActionKind> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue