diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 9ea50fdc8f12b68147c1073219625c4fd257afd3..1479f159138040681122bac46ace6e73ad62337b 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -4430,7 +4430,8 @@ impl LspStore { WorktreeStoreEvent::WorktreeReleased(..) | WorktreeStoreEvent::WorktreeOrderChanged | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..) - | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {} + | WorktreeStoreEvent::WorktreeDeletedEntry(..) + | WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir(..) => {} } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b90972b3489c25f8a2bf10d7dbdb6d6cfe0c4c6c..fe4f96af7303de6decaf30701610f5edda0ebf92 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -359,6 +359,7 @@ pub enum Event { WorktreeOrderChanged, WorktreeRemoved(WorktreeId), WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet), + WorktreeUpdatedRootRepoCommonDir(WorktreeId), DiskBasedDiagnosticsStarted { language_server_id: LanguageServerId, }, @@ -3680,6 +3681,9 @@ impl Project { } // Listen to the GitStore instead. WorktreeStoreEvent::WorktreeUpdatedGitRepositories(_, _) => {} + WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir(worktree_id) => { + cx.emit(Event::WorktreeUpdatedRootRepoCommonDir(*worktree_id)); + } } } diff --git a/crates/project/src/worktree_store.rs b/crates/project/src/worktree_store.rs index 7ca721ddb50c3f216ed630665e547b60ce4d52bf..be95a6b0ded02ed3527195433adf6eb1ab1f781b 100644 --- a/crates/project/src/worktree_store.rs +++ b/crates/project/src/worktree_store.rs @@ -91,6 +91,7 @@ pub enum WorktreeStoreEvent { WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet), WorktreeUpdatedGitRepositories(WorktreeId, UpdatedGitRepositoriesSet), WorktreeDeletedEntry(WorktreeId, ProjectEntryId), + WorktreeUpdatedRootRepoCommonDir(WorktreeId), } impl EventEmitter for WorktreeStore {} @@ -712,6 +713,7 @@ impl WorktreeStore { root_name, visible, abs_path: response.canonicalized_path, + root_repo_common_dir: response.root_repo_common_dir, }, client, path_style, @@ -812,7 +814,11 @@ impl WorktreeStore { // The worktree root itself has been deleted (for single-file worktrees) // The worktree will be removed via the observe_release callback } - worktree::Event::UpdatedRootRepoCommonDir => {} + worktree::Event::UpdatedRootRepoCommonDir => { + cx.emit(WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir( + worktree_id, + )); + } } }) .detach(); @@ -1049,6 +1055,9 @@ impl WorktreeStore { root_name: worktree.root_name_str().to_owned(), visible: worktree.is_visible(), abs_path: worktree.abs_path().to_string_lossy().into_owned(), + root_repo_common_dir: worktree + .root_repo_common_dir() + .map(|p| p.to_string_lossy().into_owned()), } }) .collect() diff --git a/crates/proto/proto/worktree.proto b/crates/proto/proto/worktree.proto index 08a5892b444c3bcbfbc0fb3f1d010c5233ea7c91..08a1317f6ac7e2f2a173e3080ec4c691b6fa1c98 100644 --- a/crates/proto/proto/worktree.proto +++ b/crates/proto/proto/worktree.proto @@ -40,6 +40,7 @@ message AddWorktree { message AddWorktreeResponse { uint64 worktree_id = 1; string canonicalized_path = 2; + optional string root_repo_common_dir = 3; } message RemoveWorktree { @@ -62,6 +63,7 @@ message WorktreeMetadata { string root_name = 2; bool visible = 3; string abs_path = 4; + optional string root_repo_common_dir = 5; } message ProjectPath { diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index 7bdbbad796bd2ced34ed7ccab690555457a0842b..63e9b4b787230ea877cdc92e1fdcdd6daa86dc0c 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -523,6 +523,9 @@ impl HeadlessProject { proto::AddWorktreeResponse { worktree_id: worktree.id().to_proto(), canonicalized_path: canonicalized.to_string_lossy().into_owned(), + root_repo_common_dir: worktree + .root_repo_common_dir() + .map(|p| p.to_string_lossy().into_owned()), } }); diff --git a/crates/sidebar/src/sidebar_tests.rs b/crates/sidebar/src/sidebar_tests.rs index 691ec48a78c33452de8665b11fc4fd844d215d87..80b381873ca14d27b9efe88eb5753670b8fa278e 100644 --- a/crates/sidebar/src/sidebar_tests.rs +++ b/crates/sidebar/src/sidebar_tests.rs @@ -5901,22 +5901,6 @@ async fn test_clicking_closed_remote_thread_opens_remote_workspace( mw.add_project_group_key(stale_key); }); - // Also save a thread whose main_worktree_paths uses the stale - // path. This simulates a thread created while the workspace's - // project_group_key was still using the fallback abs_path. - cx.update(|_window, cx| { - let metadata = ThreadMetadata { - session_id: acp::SessionId::new(Arc::from("stale-thread")), - agent_id: agent::ZED_AGENT_ID.clone(), - title: "Stale Thread".into(), - updated_at: chrono::TimeZone::with_ymd_and_hms(&Utc, 2024, 1, 1, 0, 0, 2).unwrap(), - created_at: None, - folder_paths: PathList::new(&[PathBuf::from("/project-wt-1")]), - main_worktree_paths: PathList::new(&[PathBuf::from("/project-wt-1")]), - archived: false, - }; - ThreadMetadataStore::global(cx).update(cx, |store, cx| store.save_manually(metadata, cx)); - }); cx.run_until_parked(); // After adding the linked worktree workspace, the sidebar should diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index a52246d3c40288e08e70ca5da3789d4493df3a44..65cfdca009a678d29d859314c3b06b4f752b530e 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/crates/workspace/src/multi_workspace.rs @@ -582,6 +582,13 @@ impl MultiWorkspace { this.add_project_group_key(workspace.read(cx).project_group_key(cx)); } } + project::Event::WorktreeUpdatedRootRepoCommonDir(_) => { + if let Some(workspace) = workspace.upgrade() { + this.add_project_group_key(workspace.read(cx).project_group_key(cx)); + this.remove_stale_project_group_keys(cx); + cx.notify(); + } + } _ => {} } }) @@ -605,6 +612,16 @@ impl MultiWorkspace { self.project_group_keys.push(project_group_key); } + fn remove_stale_project_group_keys(&mut self, cx: &App) { + let workspace_keys: std::collections::HashSet = self + .workspaces + .iter() + .map(|ws| ws.read(cx).project_group_key(cx)) + .collect(); + self.project_group_keys + .retain(|key| workspace_keys.contains(key)); + } + pub fn restore_project_group_keys(&mut self, keys: Vec) { let mut restored = keys; for existing_key in &self.project_group_keys { diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 864858073db70c984e61dbf43bf98be44f6c1c58..1bf6db55a5f9d34810ca7544b2e93e27028a1b4a 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -510,7 +510,7 @@ impl Worktree { cx: &mut App, ) -> Entity { cx.new(|cx: &mut Context| { - let snapshot = Snapshot::new( + let mut snapshot = Snapshot::new( WorktreeId::from_proto(worktree.id), RelPath::from_proto(&worktree.root_name) .unwrap_or_else(|_| RelPath::empty().into()), @@ -518,6 +518,10 @@ impl Worktree { path_style, ); + snapshot.root_repo_common_dir = worktree + .root_repo_common_dir + .map(|p| SanitizedPath::new_arc(Path::new(&p))); + let background_snapshot = Arc::new(Mutex::new(( snapshot.clone(), Vec::::new(), @@ -676,6 +680,9 @@ impl Worktree { root_name: self.root_name().to_proto(), visible: self.is_visible(), abs_path: self.abs_path().to_string_lossy().into_owned(), + root_repo_common_dir: self + .root_repo_common_dir() + .map(|p| p.to_string_lossy().into_owned()), } }