Move git status out of Entry (#22224)
- [x] Rewrite worktree git handling - [x] Fix tests - [x] Fix `test_propagate_statuses_for_repos_under_project` - [x] Replace `WorkDirectoryEntry` with `WorkDirectory` in `RepositoryEntry` - [x] Add a worktree event for capturing git status changes - [x] Confirm that the local repositories are correctly updating the new WorkDirectory field - [x] Implement the git statuses query as a join when pulling entries out of worktree - [x] Use this new join to implement the project panel and outline panel. - [x] Synchronize git statuses over the wire for collab and remote dev (use the existing `worktree_repository_statuses` table, adjust as needed) - [x] Only send changed statuses to collab Release Notes: - N/A --------- Co-authored-by: Cole Miller <cole@zed.dev> Co-authored-by: Mikayla <mikayla@zed.com> Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
parent
72057e5716
commit
9613084f59
57 changed files with 2824 additions and 1254 deletions
|
@ -569,9 +569,9 @@ impl LocalBufferStore {
|
|||
buffer_change_sets
|
||||
.into_iter()
|
||||
.filter_map(|(change_set, buffer_snapshot, path)| {
|
||||
let (repo_entry, local_repo_entry) = snapshot.repo_for_path(&path)?;
|
||||
let relative_path = repo_entry.relativize(&snapshot, &path).ok()?;
|
||||
let base_text = local_repo_entry.repo().load_index_text(&relative_path);
|
||||
let local_repo = snapshot.local_repo_for_path(&path)?;
|
||||
let relative_path = local_repo.relativize(&path).ok()?;
|
||||
let base_text = local_repo.repo().load_index_text(&relative_path);
|
||||
Some((change_set, buffer_snapshot, base_text))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -1161,16 +1161,16 @@ impl BufferStore {
|
|||
Worktree::Local(worktree) => {
|
||||
let worktree = worktree.snapshot();
|
||||
let blame_params = maybe!({
|
||||
let (repo_entry, local_repo_entry) = match worktree.repo_for_path(&file.path) {
|
||||
let local_repo = match worktree.local_repo_for_path(&file.path) {
|
||||
Some(repo_for_path) => repo_for_path,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let relative_path = repo_entry
|
||||
.relativize(&worktree, &file.path)
|
||||
let relative_path = local_repo
|
||||
.relativize(&file.path)
|
||||
.context("failed to relativize buffer path")?;
|
||||
|
||||
let repo = local_repo_entry.repo().clone();
|
||||
let repo = local_repo.repo().clone();
|
||||
|
||||
let content = match version {
|
||||
Some(version) => buffer.rope_for_version(&version).clone(),
|
||||
|
@ -1247,7 +1247,7 @@ impl BufferStore {
|
|||
});
|
||||
};
|
||||
|
||||
let path = match repo_entry.relativize(worktree, file.path()) {
|
||||
let path = match repo_entry.relativize(file.path()) {
|
||||
Ok(RepoPath(path)) => path,
|
||||
Err(e) => return Task::ready(Err(e)),
|
||||
};
|
||||
|
|
|
@ -87,9 +87,8 @@ pub use language::Location;
|
|||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
|
||||
pub use worktree::{
|
||||
Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, RepositoryEntry,
|
||||
UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
|
||||
FS_WATCH_LATENCY,
|
||||
Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, UpdatedEntriesSet,
|
||||
UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings, FS_WATCH_LATENCY,
|
||||
};
|
||||
|
||||
const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
@ -3109,6 +3108,7 @@ impl LspStore {
|
|||
WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
|
||||
worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
|
||||
}
|
||||
WorktreeStoreEvent::GitRepositoryUpdated => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,10 @@ use futures::{
|
|||
pub use image_store::{ImageItem, ImageStore};
|
||||
use image_store::{ImageItemEvent, ImageStoreEvent};
|
||||
|
||||
use git::{blame::Blame, repository::GitRepository};
|
||||
use git::{
|
||||
blame::Blame,
|
||||
repository::{GitFileStatus, GitRepository},
|
||||
};
|
||||
use gpui::{
|
||||
AnyModel, AppContext, AsyncAppContext, BorrowAppContext, Context as _, EventEmitter, Hsla,
|
||||
Model, ModelContext, SharedString, Task, WeakModel, WindowContext,
|
||||
|
@ -95,9 +98,8 @@ pub use task_inventory::{
|
|||
BasicContextProvider, ContextProviderWithTasks, Inventory, TaskSourceKind,
|
||||
};
|
||||
pub use worktree::{
|
||||
Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, RepositoryEntry,
|
||||
UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
|
||||
FS_WATCH_LATENCY,
|
||||
Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, UpdatedEntriesSet,
|
||||
UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings, FS_WATCH_LATENCY,
|
||||
};
|
||||
|
||||
pub use buffer_store::ProjectTransaction;
|
||||
|
@ -242,6 +244,7 @@ pub enum Event {
|
|||
ActivateProjectPanel,
|
||||
WorktreeAdded(WorktreeId),
|
||||
WorktreeOrderChanged,
|
||||
GitRepositoryUpdated,
|
||||
WorktreeRemoved(WorktreeId),
|
||||
WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet),
|
||||
WorktreeUpdatedGitRepositories(WorktreeId),
|
||||
|
@ -1433,6 +1436,15 @@ impl Project {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn project_path_git_status(
|
||||
&self,
|
||||
project_path: &ProjectPath,
|
||||
cx: &AppContext,
|
||||
) -> Option<GitFileStatus> {
|
||||
self.worktree_for_id(project_path.worktree_id, cx)
|
||||
.and_then(|worktree| worktree.read(cx).status_for_file(&project_path.path))
|
||||
}
|
||||
|
||||
pub fn visibility_for_paths(&self, paths: &[PathBuf], cx: &AppContext) -> Option<bool> {
|
||||
paths
|
||||
.iter()
|
||||
|
@ -2295,6 +2307,7 @@ impl Project {
|
|||
}
|
||||
WorktreeStoreEvent::WorktreeOrderChanged => cx.emit(Event::WorktreeOrderChanged),
|
||||
WorktreeStoreEvent::WorktreeUpdateSent(_) => {}
|
||||
WorktreeStoreEvent::GitRepositoryUpdated => cx.emit(Event::GitRepositoryUpdated),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3516,17 +3529,6 @@ impl Project {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn get_repo(
|
||||
&self,
|
||||
project_path: &ProjectPath,
|
||||
cx: &AppContext,
|
||||
) -> Option<Arc<dyn GitRepository>> {
|
||||
self.worktree_for_id(project_path.worktree_id, cx)?
|
||||
.read(cx)
|
||||
.as_local()?
|
||||
.local_git_repo(&project_path.path)
|
||||
}
|
||||
|
||||
pub fn get_first_worktree_root_repo(&self, cx: &AppContext) -> Option<Arc<dyn GitRepository>> {
|
||||
let worktree = self.visible_worktrees(cx).next()?.read(cx).as_local()?;
|
||||
let root_entry = worktree.root_git_entry()?;
|
||||
|
@ -4426,8 +4428,10 @@ impl Completion {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn sort_worktree_entries(entries: &mut [Entry]) {
|
||||
pub fn sort_worktree_entries(entries: &mut [impl AsRef<Entry>]) {
|
||||
entries.sort_by(|entry_a, entry_b| {
|
||||
let entry_a = entry_a.as_ref();
|
||||
let entry_b = entry_b.as_ref();
|
||||
compare_paths(
|
||||
(&entry_a.path, entry_a.is_file()),
|
||||
(&entry_b.path, entry_b.is_file()),
|
||||
|
|
|
@ -109,7 +109,7 @@ impl Inventory {
|
|||
/// Pulls its task sources relevant to the worktree and the language given and resolves them with the [`TaskContext`] given.
|
||||
/// Joins the new resolutions with the resolved tasks that were used (spawned) before,
|
||||
/// orders them so that the most recently used come first, all equally used ones are ordered so that the most specific tasks come first.
|
||||
/// Deduplicates the tasks by their labels and contenxt and splits the ordered list into two: used tasks and the rest, newly resolved tasks.
|
||||
/// Deduplicates the tasks by their labels and context and splits the ordered list into two: used tasks and the rest, newly resolved tasks.
|
||||
pub fn used_and_current_resolved_tasks(
|
||||
&self,
|
||||
worktree: Option<WorktreeId>,
|
||||
|
|
|
@ -62,6 +62,7 @@ pub enum WorktreeStoreEvent {
|
|||
WorktreeReleased(EntityId, WorktreeId),
|
||||
WorktreeOrderChanged,
|
||||
WorktreeUpdateSent(Model<Worktree>),
|
||||
GitRepositoryUpdated,
|
||||
}
|
||||
|
||||
impl EventEmitter<WorktreeStoreEvent> for WorktreeStore {}
|
||||
|
@ -322,6 +323,7 @@ impl WorktreeStore {
|
|||
let worktree = Worktree::local(path.clone(), visible, fs, next_entry_id, &mut cx).await;
|
||||
|
||||
let worktree = worktree?;
|
||||
|
||||
this.update(&mut cx, |this, cx| this.add(&worktree, cx))?;
|
||||
|
||||
if visible {
|
||||
|
@ -374,6 +376,17 @@ impl WorktreeStore {
|
|||
this.send_project_updates(cx);
|
||||
})
|
||||
.detach();
|
||||
|
||||
cx.subscribe(
|
||||
worktree,
|
||||
|_this, _, event: &worktree::Event, cx| match event {
|
||||
worktree::Event::UpdatedGitRepositories(_) => {
|
||||
cx.emit(WorktreeStoreEvent::GitRepositoryUpdated);
|
||||
}
|
||||
worktree::Event::DeletedEntry(_) | worktree::Event::UpdatedEntries(_) => {}
|
||||
},
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
|
||||
|
@ -583,11 +596,11 @@ impl WorktreeStore {
|
|||
pub fn shared(
|
||||
&mut self,
|
||||
remote_id: u64,
|
||||
downsteam_client: AnyProtoClient,
|
||||
downstream_client: AnyProtoClient,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
self.retain_worktrees = true;
|
||||
self.downstream_client = Some((downsteam_client, remote_id));
|
||||
self.downstream_client = Some((downstream_client, remote_id));
|
||||
|
||||
// When shared, retain all worktrees
|
||||
for worktree_handle in self.worktrees.iter_mut() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue