diff --git a/crates/project/src/worktree_store.rs b/crates/project/src/worktree_store.rs index ab5c46752c6cd92e35a2eb283a50b38e76b649d7..768ab9afb91b4ec9c72962eb4f60f2d90519e791 100644 --- a/crates/project/src/worktree_store.rs +++ b/crates/project/src/worktree_store.rs @@ -1383,12 +1383,6 @@ impl WorktreeStore { pub fn paths(&self, cx: &App) -> WorktreePaths { let (mains, folders): (Vec, Vec) = self .visible_worktrees(cx) - .filter(|worktree| { - let worktree = worktree.read(cx); - // Remote worktrees that haven't received their first update - // don't have enough data to contribute yet. - !worktree.is_remote() || worktree.root_entry().is_some() - }) .map(|worktree| { let snapshot = worktree.read(cx).snapshot(); let folder_path = snapshot.abs_path().to_path_buf(); diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index 508d8928ed52b4fc2582b95c2ed98af84e7dd620..840e683e153d5df4dec4f25fdc0fd15d875ceece 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/crates/workspace/src/multi_workspace.rs @@ -714,6 +714,26 @@ impl MultiWorkspace { cx.emit(MultiWorkspaceEvent::WorkspaceAdded(workspace)); } + pub(crate) fn activate_provisional_workspace( + &mut self, + workspace: Entity, + provisional_key: ProjectGroupKey, + window: &mut Window, + cx: &mut Context, + ) { + if workspace != self.active_workspace { + self.register_workspace(&workspace, window, cx); + } + + self.ensure_project_group_state(provisional_key); + if !self.is_workspace_retained(&workspace) { + self.retained_workspaces.push(workspace.clone()); + } + + self.activate(workspace.clone(), window, cx); + cx.emit(MultiWorkspaceEvent::WorkspaceAdded(workspace)); + } + fn register_workspace( &mut self, workspace: &Entity, diff --git a/crates/workspace/src/multi_workspace_tests.rs b/crates/workspace/src/multi_workspace_tests.rs index 89822383e6307eb23e370bbe9e0810af53584ba8..e5ee718a52876546768f1ee6482e224b4134cf52 100644 --- a/crates/workspace/src/multi_workspace_tests.rs +++ b/crates/workspace/src/multi_workspace_tests.rs @@ -667,44 +667,52 @@ async fn test_switching_projects_with_sidebar_closed_detaches_old_active_workspa } #[gpui::test] -async fn test_remote_worktree_without_git_updates_project_group(cx: &mut TestAppContext) { +async fn test_remote_project_root_dir_changes_update_groups(cx: &mut TestAppContext) { init_test(cx); let fs = FakeFs::new(cx.executor()); - fs.insert_tree("/local", json!({ "file.txt": "" })).await; - let project = Project::test(fs.clone(), ["/local".as_ref()], cx).await; + fs.insert_tree("/root_a", json!({ "file.txt": "" })).await; + fs.insert_tree("/local_b", json!({ "file.txt": "" })).await; + let project_a = Project::test(fs.clone(), ["/root_a".as_ref()], cx).await; + let project_b = Project::test(fs.clone(), ["/local_b".as_ref()], cx).await; let (multi_workspace, cx) = - cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + cx.add_window_view(|window, cx| MultiWorkspace::test_new(project_a, window, cx)); multi_workspace.update(cx, |mw, cx| { mw.open_sidebar(cx); }); cx.run_until_parked(); - let initial_key = project.read_with(cx, |p, cx| p.project_group_key(cx)); + let workspace_b = multi_workspace.update_in(cx, |mw, window, cx| { + let workspace = cx.new(|cx| Workspace::test_new(project_b.clone(), window, cx)); + let key = workspace.read(cx).project_group_key(cx); + mw.activate_provisional_workspace(workspace.clone(), key, window, cx); + workspace + }); + cx.run_until_parked(); + + multi_workspace.read_with(cx, |mw, _cx| { + assert_eq!( + mw.workspace().entity_id(), + workspace_b.entity_id(), + "registered workspace should become active" + ); + }); + + let initial_key = project_b.read_with(cx, |p, cx| p.project_group_key(cx)); multi_workspace.read_with(cx, |mw, _cx| { let keys = mw.project_group_keys(); - assert_eq!(keys.len(), 1); - assert_eq!(keys[0], initial_key); + assert!( + keys.contains(&initial_key), + "project groups should contain the initial key for the registered workspace" + ); }); - // Add a remote worktree without git repo info. - let remote_worktree = project.update(cx, |project, cx| { + let remote_worktree = project_b.update(cx, |project, cx| { project.add_test_remote_worktree("/remote/project", cx) }); cx.run_until_parked(); - // The remote worktree has no entries yet, so project_group_key should - // still exclude it. - let key_after_add = project.read_with(cx, |p, cx| p.project_group_key(cx)); - assert_eq!( - key_after_add, initial_key, - "remote worktree without entries should not affect the group key" - ); - - // Send an UpdateWorktree to the remote worktree with entries but no repo. - // This triggers UpdatedRootRepoCommonDir on the first update (the fix), - // which propagates through WorktreeStore → Project → MultiWorkspace. let worktree_id = remote_worktree.read_with(cx, |wt, _| wt.id().to_proto()); remote_worktree.update(cx, |worktree, _cx| { worktree @@ -741,17 +749,21 @@ async fn test_remote_worktree_without_git_updates_project_group(cx: &mut TestApp }); cx.run_until_parked(); - let updated_key = project.read_with(cx, |p, cx| p.project_group_key(cx)); + let updated_key = project_b.read_with(cx, |p, cx| p.project_group_key(cx)); assert_ne!( initial_key, updated_key, - "adding a remote worktree should change the project group key" + "remote worktree update should change the project group key" ); multi_workspace.read_with(cx, |mw, _cx| { let keys = mw.project_group_keys(); assert!( keys.contains(&updated_key), - "should contain the updated key; got {keys:?}" + "project groups should contain the updated key after remote change; got {keys:?}" + ); + assert!( + !keys.contains(&initial_key), + "project groups should no longer contain the stale initial key; got {keys:?}" ); }); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 79c7734c379b4c433062b0bb351a6b6c17d8f9ae..3ad9de443bf82c92c30d6df39cfbeb83e0b1727c 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9959,9 +9959,15 @@ async fn open_remote_project_inner( }); if let Some(project_group_key) = provisional_project_group_key.clone() { - multi_workspace.retain_workspace(new_workspace.clone(), project_group_key, cx); + multi_workspace.activate_provisional_workspace( + new_workspace.clone(), + project_group_key, + window, + cx, + ); + } else { + multi_workspace.activate(new_workspace.clone(), window, cx); } - multi_workspace.activate(new_workspace.clone(), window, cx); new_workspace })?;