open in new window by serializing->closing->reopening

cameron created

Change summary

crates/sidebar/src/sidebar.rs           | 26 ++++++++++++
crates/workspace/src/multi_workspace.rs | 55 ++++++++++++++++++++++++++
2 files changed, 81 insertions(+)

Detailed changes

crates/sidebar/src/sidebar.rs 🔗

@@ -1730,6 +1730,32 @@ impl Sidebar {
                             },
                         );
 
+                        let menu = if project_group_key.host().is_none() {
+                            menu.entry(
+                                "Open Project in New Window",
+                                None,
+                                {
+                                    let project_group_key = project_group_key.clone();
+                                    let multi_workspace = multi_workspace.clone();
+                                    move |window, cx| {
+                                        multi_workspace
+                                            .update(cx, |multi_workspace, cx| {
+                                                multi_workspace
+                                                    .open_project_group_in_new_window(
+                                                        &project_group_key,
+                                                        window,
+                                                        cx,
+                                                    )
+                                                    .detach_and_log_err(cx);
+                                            })
+                                            .ok();
+                                    }
+                                },
+                            )
+                        } else {
+                            menu
+                        };
+
                         let project_group_key = project_group_key.clone();
                         let multi_workspace = multi_workspace.clone();
                         let weak_menu = menu_cx.weak_entity();

crates/workspace/src/multi_workspace.rs 🔗

@@ -854,6 +854,61 @@ impl MultiWorkspace {
         )
     }
 
+    /// Goes through sqlite: serialize -> close -> open new window
+    /// This avoids issues with pending tasks having the wrong window
+    pub fn open_project_group_in_new_window(
+        &mut self,
+        key: &ProjectGroupKey,
+        window: &mut Window,
+        cx: &mut Context<Self>,
+    ) -> Task<Result<()>> {
+        let paths: Vec<PathBuf> = key.path_list().ordered_paths().cloned().collect();
+        if paths.is_empty() {
+            return Task::ready(Ok(()));
+        }
+
+        let app_state = self.workspace().read(cx).app_state().clone();
+
+        let workspaces: Vec<_> = self
+            .workspaces_for_project_group(key, cx)
+            .cloned()
+            .collect();
+        let mut serialization_tasks = Vec::new();
+        for workspace in &workspaces {
+            serialization_tasks.push(
+                workspace.update(cx, |workspace, inner_cx| {
+                    workspace.flush_serialization(window, inner_cx)
+                }),
+            );
+        }
+
+        let remove_task = self.remove_project_group(key, window, cx);
+
+        cx.spawn(async move |_this, cx| {
+            futures::future::join_all(serialization_tasks).await;
+
+            let removed = remove_task.await?;
+            if !removed {
+                return Ok(());
+            }
+
+            cx.update(|cx| {
+                Workspace::new_local(
+                    paths,
+                    app_state,
+                    None,
+                    None,
+                    None,
+                    OpenMode::NewWindow,
+                    cx,
+                )
+            })
+            .await?;
+
+            Ok(())
+        })
+    }
+
     /// Finds an existing workspace whose root paths and host exactly match.
     pub fn workspace_for_paths(
         &self,