Add a prototype with a multi buffer having all project git changes (#21543)

Part of https://github.com/zed-industries/zed/issues/20925

This prototype is behind a feature flag and being merged to avoid
conflicts with further git-related resturctures.
To be a proper, public feature, this needs at least:
* showing deleted files
* better performance 
* randomized tests
* `TODO`s in the `project_diff.rs` file fixed

The good thing is, >90% of the changes are in the `project_diff.rs` file
only, have a basic test and already work on simple cases.

Release Notes:

- N/A

---------

Co-authored-by: Thorsten Ball <thorsten@zed.dev>
Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Kirill Bulatov 2024-12-04 23:36:36 +02:00 committed by GitHub
parent f0fac41ca4
commit 8d18dfa4c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1269 additions and 27 deletions

2
Cargo.lock generated
View file

@ -3790,6 +3790,7 @@ dependencies = [
"db",
"emojis",
"env_logger 0.11.5",
"feature_flags",
"file_icons",
"fs",
"futures 0.3.31",
@ -3823,6 +3824,7 @@ dependencies = [
"snippet",
"sum_tree",
"task",
"tempfile",
"text",
"theme",
"time",

View file

@ -39,6 +39,7 @@ collections.workspace = true
convert_case.workspace = true
db.workspace = true
emojis.workspace = true
feature_flags.workspace = true
file_icons.workspace = true
futures.workspace = true
fuzzy.workspace = true
@ -97,6 +98,7 @@ project = { workspace = true, features = ["test-support"] }
release_channel.workspace = true
rand.workspace = true
settings = { workspace = true, features = ["test-support"] }
tempfile.workspace = true
text = { workspace = true, features = ["test-support"] }
theme = { workspace = true, features = ["test-support"] }
tree-sitter-html.workspace = true

View file

@ -327,6 +327,7 @@ pub fn init(cx: &mut AppContext) {
.detach();
}
});
git::project_diff::init(cx);
}
pub struct SearchWithinRange;

View file

@ -1 +1,2 @@
pub mod blame;
pub mod project_diff;

View file

@ -154,7 +154,7 @@ impl GitBlame {
this.generate(cx);
}
}
project::Event::WorktreeUpdatedGitRepositories => {
project::Event::WorktreeUpdatedGitRepositories(_) => {
log::debug!("Status of git repositories updated. Regenerating blame data...",);
this.generate(cx);
}

File diff suppressed because it is too large Load diff

View file

@ -648,7 +648,7 @@ impl FileFinderDelegate {
cx.subscribe(project, |file_finder, _, event, cx| {
match event {
project::Event::WorktreeUpdatedEntries(_, _)
| project::Event::WorktreeAdded
| project::Event::WorktreeAdded(_)
| project::Event::WorktreeRemoved(_) => file_finder
.picker
.update(cx, |picker, cx| picker.refresh(cx)),

View file

@ -80,7 +80,6 @@ impl BufferDiff {
self.tree.is_empty()
}
#[cfg(any(test, feature = "test-support"))]
pub fn hunks_in_row_range<'a>(
&'a self,
range: Range<u32>,

View file

@ -3998,7 +3998,6 @@ impl BufferSnapshot {
}
/// Returns all the Git diff hunks intersecting the given row range.
#[cfg(any(test, feature = "test-support"))]
pub fn git_diff_hunks_in_row_range(
&self,
range: Range<BufferRow>,

View file

@ -240,11 +240,11 @@ pub enum Event {
LanguageNotFound(Model<Buffer>),
ActiveEntryChanged(Option<ProjectEntryId>),
ActivateProjectPanel,
WorktreeAdded,
WorktreeAdded(WorktreeId),
WorktreeOrderChanged,
WorktreeRemoved(WorktreeId),
WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet),
WorktreeUpdatedGitRepositories,
WorktreeUpdatedGitRepositories(WorktreeId),
DiskBasedDiagnosticsStarted {
language_server_id: LanguageServerId,
},
@ -259,7 +259,7 @@ pub enum Event {
DisconnectedFromHost,
DisconnectedFromSshRemote,
Closed,
DeletedEntry(ProjectEntryId),
DeletedEntry(WorktreeId, ProjectEntryId),
CollaboratorUpdated {
old_peer_id: proto::PeerId,
new_peer_id: proto::PeerId,
@ -1504,6 +1504,7 @@ impl Project {
cx: &mut ModelContext<Self>,
) -> Option<Task<Result<()>>> {
let worktree = self.worktree_for_entry(entry_id, cx)?;
cx.emit(Event::DeletedEntry(worktree.read(cx).id(), entry_id));
worktree.update(cx, |worktree, cx| {
worktree.delete_entry(entry_id, trash, cx)
})
@ -2204,7 +2205,7 @@ impl Project {
match event {
WorktreeStoreEvent::WorktreeAdded(worktree) => {
self.on_worktree_added(worktree, cx);
cx.emit(Event::WorktreeAdded);
cx.emit(Event::WorktreeAdded(worktree.read(cx).id()));
}
WorktreeStoreEvent::WorktreeRemoved(_, id) => {
cx.emit(Event::WorktreeRemoved(*id));
@ -2225,23 +2226,25 @@ impl Project {
}
}
cx.observe(worktree, |_, _, cx| cx.notify()).detach();
cx.subscribe(worktree, |project, worktree, event, cx| match event {
worktree::Event::UpdatedEntries(changes) => {
cx.emit(Event::WorktreeUpdatedEntries(
worktree.read(cx).id(),
changes.clone(),
));
cx.subscribe(worktree, |project, worktree, event, cx| {
let worktree_id = worktree.update(cx, |worktree, _| worktree.id());
match event {
worktree::Event::UpdatedEntries(changes) => {
cx.emit(Event::WorktreeUpdatedEntries(
worktree.read(cx).id(),
changes.clone(),
));
let worktree_id = worktree.update(cx, |worktree, _| worktree.id());
project
.client()
.telemetry()
.report_discovered_project_events(worktree_id, changes);
project
.client()
.telemetry()
.report_discovered_project_events(worktree_id, changes);
}
worktree::Event::UpdatedGitRepositories(_) => {
cx.emit(Event::WorktreeUpdatedGitRepositories(worktree_id));
}
worktree::Event::DeletedEntry(id) => cx.emit(Event::DeletedEntry(worktree_id, *id)),
}
worktree::Event::UpdatedGitRepositories(_) => {
cx.emit(Event::WorktreeUpdatedGitRepositories);
}
worktree::Event::DeletedEntry(id) => cx.emit(Event::DeletedEntry(*id)),
})
.detach();
cx.notify();

View file

@ -304,7 +304,7 @@ impl ProjectPanel {
cx.notify();
}
project::Event::WorktreeUpdatedEntries(_, _)
| project::Event::WorktreeAdded
| project::Event::WorktreeAdded(_)
| project::Event::WorktreeOrderChanged => {
this.update_visible_entries(None, cx);
cx.notify();

View file

@ -125,7 +125,7 @@ impl ProjectIndex {
cx: &mut ModelContext<Self>,
) {
match event {
project::Event::WorktreeAdded | project::Event::WorktreeRemoved(_) => {
project::Event::WorktreeAdded(_) | project::Event::WorktreeRemoved(_) => {
self.update_worktree_indices(cx);
}
_ => {}

View file

@ -810,7 +810,7 @@ impl Workspace {
this.collaborator_left(*peer_id, cx);
}
project::Event::WorktreeRemoved(_) | project::Event::WorktreeAdded => {
project::Event::WorktreeRemoved(_) | project::Event::WorktreeAdded(_) => {
this.update_window_title(cx);
this.serialize_workspace(cx);
}
@ -832,7 +832,7 @@ impl Workspace {
cx.remove_window();
}
project::Event::DeletedEntry(entry_id) => {
project::Event::DeletedEntry(_, entry_id) => {
for pane in this.panes.iter() {
pane.update(cx, |pane, cx| {
pane.handle_deleted_project_item(*entry_id, cx)