Detailed changes
@@ -1972,6 +1972,10 @@ impl Sidebar {
let multi_workspace = multi_workspace.clone();
let project_group_key = project_group_key.clone();
+ let has_multiple_projects = multi_workspace
+ .read_with(cx, |mw, _| mw.project_group_keys().len() >= 2)
+ .unwrap_or(false);
+
let menu =
ContextMenu::build_persistent(window, cx, move |menu, _window, menu_cx| {
let weak_menu = menu_cx.weak_entity();
@@ -2031,6 +2035,32 @@ impl Sidebar {
},
);
+ let menu = if project_group_key.host().is_none() && has_multiple_projects {
+ menu.entry(
+ "Open Project in New Window",
+ Some(Box::new(workspace::MoveProjectToNewWindow)),
+ {
+ 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();
menu.separator()
@@ -54,6 +54,8 @@ actions!(
ShowFewerThreads,
/// Creates a new thread in the current workspace.
NewThread,
+ /// Moves the active project to a new window.
+ MoveProjectToNewWindow,
]
);
@@ -1017,6 +1019,50 @@ 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)
+ .unwrap_or_default();
+ 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,
@@ -1836,13 +1882,23 @@ impl Render for MultiWorkspace {
sidebar.cycle_thread(true, window, cx);
}
}))
- .on_action(cx.listener(
- |this: &mut Self, _: &PreviousThread, window, cx| {
+ .on_action(
+ cx.listener(|this: &mut Self, _: &PreviousThread, window, cx| {
if let Some(sidebar) = &this.sidebar {
sidebar.cycle_thread(false, window, cx);
}
- },
- ))
+ }),
+ )
+ .when(self.project_group_keys().len() >= 2, |el| {
+ el.on_action(cx.listener(
+ |this: &mut Self, _: &MoveProjectToNewWindow, window, cx| {
+ let key =
+ this.project_group_key_for_workspace(this.workspace(), cx);
+ this.open_project_group_in_new_window(&key, window, cx)
+ .detach_and_log_err(cx);
+ },
+ ))
+ })
})
.when(
self.sidebar_open() && self.multi_workspace_enabled(cx),
@@ -31,11 +31,11 @@ mod workspace_settings;
pub use crate::notifications::NotificationFrame;
pub use dock::Panel;
pub use multi_workspace::{
- CloseWorkspaceSidebar, DraggedSidebar, FocusWorkspaceSidebar, MultiWorkspace,
- MultiWorkspaceEvent, NewThread, NextProject, NextThread, PreviousProject, PreviousThread,
- ProjectGroup, ProjectGroupKey, SerializedProjectGroupState, ShowFewerThreads, ShowMoreThreads,
- Sidebar, SidebarEvent, SidebarHandle, SidebarRenderState, SidebarSide, ToggleWorkspaceSidebar,
- sidebar_side_context_menu,
+ CloseWorkspaceSidebar, DraggedSidebar, FocusWorkspaceSidebar, MoveProjectToNewWindow,
+ MultiWorkspace, MultiWorkspaceEvent, NewThread, NextProject, NextThread, PreviousProject,
+ PreviousThread, ProjectGroup, ProjectGroupKey, SerializedProjectGroupState, ShowFewerThreads,
+ ShowMoreThreads, Sidebar, SidebarEvent, SidebarHandle, SidebarRenderState, SidebarSide,
+ ToggleWorkspaceSidebar, sidebar_side_context_menu,
};
pub use path_list::{PathList, SerializedPathList};
pub use toast_layer::{ToastAction, ToastLayer, ToastView};