Use workspace::open_paths in restore flow instead of searching workspaces

Richard Feldman created

Instead of passing a slice of workspaces and manually searching for
the main repo entity, use workspace::open_paths to find or open the
workspace containing the main repo. This handles both 'already open'
and 'needs to be opened' cases, and eliminates the disk-based fallback
that was duplicating workspace opening logic.

Change summary

crates/sidebar/src/sidebar.rs | 136 ++++++++++++++++++++----------------
1 file changed, 77 insertions(+), 59 deletions(-)

Detailed changes

crates/sidebar/src/sidebar.rs 🔗

@@ -46,9 +46,9 @@ use ui::{
 use util::ResultExt as _;
 use util::path_list::{PathList, SerializedPathList};
 use workspace::{
-    AddFolderToProject, CloseWindow, FocusWorkspaceSidebar, MultiWorkspace, MultiWorkspaceEvent,
-    Open, Sidebar as WorkspaceSidebar, SidebarSide, ToggleWorkspaceSidebar, Workspace, WorkspaceId,
-    sidebar_side_context_menu,
+    AddFolderToProject, AppState, CloseWindow, FocusWorkspaceSidebar, MultiWorkspace,
+    MultiWorkspaceEvent, Open, OpenOptions, Sidebar as WorkspaceSidebar, SidebarSide,
+    ToggleWorkspaceSidebar, Workspace, WorkspaceId, sidebar_side_context_menu,
 };
 
 use zed_actions::OpenRecent;
@@ -2302,7 +2302,7 @@ impl Sidebar {
                     }
                     Some(row) => {
                         let fs = cx.update(|_window, cx| <dyn fs::Fs>::global(cx))?;
-                        match Self::restore_archived_worktree(row, &workspaces, fs, cx).await {
+                        match Self::restore_archived_worktree(row, fs, cx).await {
                             Ok(restored_path) => {
                                 final_paths.push(restored_path);
                                 Self::maybe_cleanup_archived_worktree(row, &store, &workspaces, cx)
@@ -2334,19 +2334,58 @@ impl Sidebar {
 
     async fn restore_archived_worktree(
         row: &ArchivedGitWorktree,
-        workspaces: &[Entity<Workspace>],
         fs: Arc<dyn fs::Fs>,
         cx: &mut AsyncWindowContext,
     ) -> anyhow::Result<PathBuf> {
         let commit_hash = row.commit_hash.clone();
+        let main_repo_path = row.main_repo_path.clone();
+
+        // Ensure the main repo's workspace is open (finds existing or opens new).
+        let open_task = cx.update(|_window, cx| {
+            let app_state = AppState::global(cx);
+            workspace::open_paths(
+                std::slice::from_ref(&main_repo_path),
+                app_state,
+                OpenOptions::default(),
+                cx,
+            )
+        })?;
+        let open_result = open_task.await?;
+        let project = open_result
+            .workspace
+            .update(cx, |workspace, _cx| workspace.project().clone());
+
+        // Wait for worktree scans to complete so the Repository entities are available.
+        let scan_futures = cx.update(|_window, cx| {
+            project
+                .read(cx)
+                .worktrees(cx)
+                .filter_map(|worktree| {
+                    worktree
+                        .read(cx)
+                        .as_local()
+                        .map(|local| local.scan_complete())
+                })
+                .collect::<Vec<_>>()
+        })?;
+        for scan_future in scan_futures {
+            scan_future.await;
+        }
 
-        // Find the main repo entity.
+        // Find the main repo entity in the project.
         let main_repo = cx.update(|_window, cx| {
-            find_main_repo_in_workspaces(workspaces, &row.main_repo_path, cx)
+            project
+                .read(cx)
+                .repositories(cx)
+                .values()
+                .find_map(|repo_entity| {
+                    let repo = repo_entity.read(cx);
+                    (repo.is_main_worktree() && *repo.work_directory_abs_path == *main_repo_path)
+                        .then(|| repo_entity.clone())
+                })
         })?;
 
         let Some(main_repo) = main_repo else {
-            // Main repo not found — fall back to fresh worktree.
             return Self::create_fresh_worktree(row, &fs, cx).await;
         };
 
@@ -2357,17 +2396,13 @@ impl Sidebar {
         let is_restored_and_valid = already_exists
             && row.restored
             && cx.update(|_window, cx| {
-                workspaces.iter().any(|workspace| {
-                    let project = workspace.read(cx).project().clone();
-                    project
-                        .read(cx)
-                        .repositories(cx)
-                        .values()
-                        .any(|repo_entity| {
-                            *repo_entity.read(cx).snapshot().work_directory_abs_path
-                                == *worktree_path
-                        })
-                })
+                project
+                    .read(cx)
+                    .repositories(cx)
+                    .values()
+                    .any(|repo_entity| {
+                        *repo_entity.read(cx).snapshot().work_directory_abs_path == *worktree_path
+                    })
             })?;
 
         let final_worktree_path = if !already_exists {
@@ -2431,52 +2466,35 @@ impl Sidebar {
 
             // Tell the project about the new worktree and wait for it
             // to finish scanning so the GitStore creates a Repository.
-            let project = cx.update(|_window, cx| {
-                workspaces.iter().find_map(|workspace| {
-                    let project = workspace.read(cx).project().clone();
-                    let has_main_repo = project.read(cx).repositories(cx).values().any(|repo| {
-                        let repo = repo.read(cx);
-                        repo.is_main_worktree()
-                            && *repo.work_directory_abs_path == *row.main_repo_path
-                    });
-                    has_main_repo.then_some(project)
+            let path_for_register = final_worktree_path.clone();
+            let worktree_result = project
+                .update(cx, |project, cx| {
+                    project.find_or_create_worktree(path_for_register, true, cx)
                 })
-            })?;
-
-            if let Some(project) = project {
-                let path_for_register = final_worktree_path.clone();
-                let worktree_result = project
-                    .update(cx, |project, cx| {
-                        project.find_or_create_worktree(path_for_register, true, cx)
-                    })
-                    .await;
-                if let Ok((worktree, _)) = worktree_result {
-                    let scan_complete = cx.update(|_window, cx| {
-                        worktree
-                            .read(cx)
-                            .as_local()
-                            .map(project::LocalWorktree::scan_complete)
-                    })?;
-                    if let Some(future) = scan_complete {
-                        future.await;
-                    }
+                .await;
+            if let Ok((worktree, _)) = worktree_result {
+                let scan_complete = cx.update(|_window, cx| {
+                    worktree
+                        .read(cx)
+                        .as_local()
+                        .map(project::LocalWorktree::scan_complete)
+                })?;
+                if let Some(future) = scan_complete {
+                    future.await;
                 }
             }
 
             // Find the new worktree's repo entity.
             let worktree_repo = cx.update(|_window, cx| {
-                workspaces.iter().find_map(|workspace| {
-                    let project = workspace.read(cx).project().clone();
-                    project
-                        .read(cx)
-                        .repositories(cx)
-                        .values()
-                        .find_map(|repo_entity| {
-                            let snapshot = repo_entity.read(cx).snapshot();
-                            (*snapshot.work_directory_abs_path == *final_worktree_path)
-                                .then(|| repo_entity.clone())
-                        })
-                })
+                project
+                    .read(cx)
+                    .repositories(cx)
+                    .values()
+                    .find_map(|repo_entity| {
+                        let snapshot = repo_entity.read(cx).snapshot();
+                        (*snapshot.work_directory_abs_path == *final_worktree_path)
+                            .then(|| repo_entity.clone())
+                    })
             })?;
 
             if let Some(worktree_repo) = worktree_repo {