diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index 4d3030c1e37206831ea71beb7466e66d528ee3cd..d12badb48c00e965b97e4d0af82c624c7f549069 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/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(); diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index f4e8b47399e1420a4b01d380ad4a6532a0934a2d..3d60b08449cd032cfdae8f98e028837a247d8491 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/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, + ) -> Task> { + let paths: Vec = 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,