Update more sidebar interactions to use the MultiWorkspace's explicit project groups (#53174)
* Don't require a workspace to be loaded in order to render the group header menu. * When adding or removing root folders, do it to *every* workspace in the group. * When activating a thread, never open a different window, and never open it in a workspace that's part of a different groupw with a superset of the thread's worktrees. Find or create a workspace with the exact right group of root folders. Release Notes: - N/A
This commit is contained in:
1 parent
d7fca945ac
commit
bf28ac168f
5 files changed
+342
-127
No files matched your search
@@ -4763,6 +4763,19 @@ impl Project {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn remove_worktree_for_main_worktree_path(
|
||||
&mut self,
|
||||
path: impl AsRef<Path>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let path = path.as_ref();
|
||||
self.worktree_store.update(cx, |worktree_store, cx| {
|
||||
if let Some(worktree) = worktree_store.worktree_for_main_worktree_path(path, cx) {
|
||||
worktree_store.remove_worktree(worktree.read(cx).id(), cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn add_worktree(&mut self, worktree: &Entity<Worktree>, cx: &mut Context<Self>) {
|
||||
self.worktree_store.update(cx, |worktree_store, cx| {
|
||||
worktree_store.add(worktree, cx);
|
||||
|
||||
@@ -850,6 +850,21 @@ impl WorktreeStore {
|
||||
self.send_project_updates(cx);
|
||||
}
|
||||
|
||||
pub fn worktree_for_main_worktree_path(
|
||||
&self,
|
||||
path: &Path,
|
||||
cx: &App,
|
||||
) -> Option<Entity<Worktree>> {
|
||||
self.visible_worktrees(cx).find(|worktree| {
|
||||
let worktree = worktree.read(cx);
|
||||
if let Some(common_dir) = worktree.root_repo_common_dir() {
|
||||
common_dir.parent() == Some(path)
|
||||
} else {
|
||||
worktree.abs_path().as_ref() == path
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_worktrees_reordered(&mut self, worktrees_reordered: bool) {
|
||||
self.worktrees_reordered = worktrees_reordered;
|
||||
}
|
||||
|
||||
+73
-111
@@ -689,12 +689,9 @@ impl Sidebar {
|
||||
return;
|
||||
};
|
||||
|
||||
let paths: Vec<std::path::PathBuf> =
|
||||
path_list.paths().iter().map(|p| p.to_path_buf()).collect();
|
||||
|
||||
multi_workspace
|
||||
.update(cx, |mw, cx| {
|
||||
mw.open_project(paths, workspace::OpenMode::Activate, window, cx)
|
||||
.update(cx, |this, cx| {
|
||||
this.find_or_create_local_workspace(path_list.clone(), window, cx)
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
@@ -1439,10 +1436,7 @@ impl Sidebar {
|
||||
})
|
||||
}),
|
||||
)
|
||||
.child({
|
||||
let workspace_for_new_thread = workspace.clone();
|
||||
let path_list_for_new_thread = path_list.clone();
|
||||
|
||||
.child(
|
||||
h_flex()
|
||||
.when(self.project_header_menu_ix != Some(ix), |this| {
|
||||
this.visible_on_hover(group_name)
|
||||
@@ -1450,13 +1444,7 @@ impl Sidebar {
|
||||
.on_mouse_down(gpui::MouseButton::Left, |_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.when_some(workspace, |this, workspace| {
|
||||
this.child(
|
||||
self.render_project_header_menu(
|
||||
ix, id_prefix, &workspace, &workspace, cx,
|
||||
),
|
||||
)
|
||||
})
|
||||
.child(self.render_project_header_menu(ix, id_prefix, key, cx))
|
||||
.when(view_more_expanded && !is_collapsed, |this| {
|
||||
this.child(
|
||||
IconButton::new(
|
||||
@@ -1478,12 +1466,10 @@ impl Sidebar {
|
||||
})),
|
||||
)
|
||||
})
|
||||
.when(
|
||||
show_new_thread_button && workspace_for_new_thread.is_some(),
|
||||
|this| {
|
||||
let workspace_for_new_thread =
|
||||
workspace_for_new_thread.clone().unwrap();
|
||||
let path_list_for_new_thread = path_list_for_new_thread.clone();
|
||||
.when_some(
|
||||
workspace.filter(|_| show_new_thread_button),
|
||||
|this, workspace| {
|
||||
let path_list = path_list.clone();
|
||||
this.child(
|
||||
IconButton::new(
|
||||
SharedString::from(format!(
|
||||
@@ -1495,26 +1481,22 @@ impl Sidebar {
|
||||
.tooltip(Tooltip::text("New Thread"))
|
||||
.on_click(cx.listener(
|
||||
move |this, _, window, cx| {
|
||||
this.collapsed_groups.remove(&path_list_for_new_thread);
|
||||
this.collapsed_groups.remove(&path_list);
|
||||
this.selection = None;
|
||||
this.create_new_thread(
|
||||
&workspace_for_new_thread,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
this.create_new_thread(&workspace, window, cx);
|
||||
},
|
||||
)),
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
),
|
||||
)
|
||||
.when(!is_active, |this| {
|
||||
let path_list_for_open = path_list.clone();
|
||||
let path_list = path_list.clone();
|
||||
this.cursor_pointer()
|
||||
.hover(|s| s.bg(hover_color))
|
||||
.tooltip(Tooltip::text("Open Workspace"))
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
if let Some(workspace) = this.workspace_for_group(&path_list_for_open, cx) {
|
||||
if let Some(workspace) = this.workspace_for_group(&path_list, cx) {
|
||||
this.active_entry = Some(ActiveEntry::Draft(workspace.clone()));
|
||||
if let Some(multi_workspace) = this.multi_workspace.upgrade() {
|
||||
multi_workspace.update(cx, |multi_workspace, cx| {
|
||||
@@ -1527,7 +1509,7 @@ impl Sidebar {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.open_workspace_for_group(&path_list_for_open, window, cx);
|
||||
this.open_workspace_for_group(&path_list, window, cx);
|
||||
}
|
||||
}))
|
||||
})
|
||||
@@ -1538,14 +1520,12 @@ impl Sidebar {
|
||||
&self,
|
||||
ix: usize,
|
||||
id_prefix: &str,
|
||||
workspace: &Entity<Workspace>,
|
||||
workspace_for_remove: &Entity<Workspace>,
|
||||
project_group_key: &ProjectGroupKey,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let workspace_for_menu = workspace.clone();
|
||||
let workspace_for_remove = workspace_for_remove.clone();
|
||||
let multi_workspace = self.multi_workspace.clone();
|
||||
let this = cx.weak_entity();
|
||||
let project_group_key = project_group_key.clone();
|
||||
|
||||
PopoverMenu::new(format!("{id_prefix}project-header-menu-{ix}"))
|
||||
.on_open(Rc::new({
|
||||
@@ -1559,116 +1539,102 @@ impl Sidebar {
|
||||
}
|
||||
}))
|
||||
.menu(move |window, cx| {
|
||||
let workspace = workspace_for_menu.clone();
|
||||
let workspace_for_remove = workspace_for_remove.clone();
|
||||
let multi_workspace = multi_workspace.clone();
|
||||
let project_group_key = project_group_key.clone();
|
||||
|
||||
let menu = ContextMenu::build_persistent(window, cx, move |menu, _window, cx| {
|
||||
let worktrees: Vec<_> = workspace
|
||||
.read(cx)
|
||||
.visible_worktrees(cx)
|
||||
.map(|worktree| {
|
||||
let worktree_read = worktree.read(cx);
|
||||
let id = worktree_read.id();
|
||||
let name: SharedString =
|
||||
worktree_read.root_name().as_unix_str().to_string().into();
|
||||
(id, name)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let worktree_count = worktrees.len();
|
||||
|
||||
let mut menu = menu
|
||||
.header("Project Folders")
|
||||
.end_slot_action(Box::new(menu::EndSlot));
|
||||
|
||||
for (worktree_id, name) in &worktrees {
|
||||
let worktree_id = *worktree_id;
|
||||
let workspace_for_worktree = workspace.clone();
|
||||
let workspace_for_remove_worktree = workspace_for_remove.clone();
|
||||
let multi_workspace_for_worktree = multi_workspace.clone();
|
||||
|
||||
let remove_handler = move |window: &mut Window, cx: &mut App| {
|
||||
if worktree_count <= 1 {
|
||||
if let Some(mw) = multi_workspace_for_worktree.upgrade() {
|
||||
let ws = workspace_for_remove_worktree.clone();
|
||||
mw.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.remove(&ws, window, cx);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
workspace_for_worktree.update(cx, |workspace, cx| {
|
||||
workspace.project().update(cx, |project, cx| {
|
||||
project.remove_worktree(worktree_id, cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
for path in project_group_key.path_list().paths() {
|
||||
let Some(name) = path.file_name() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let name: SharedString = name.to_string_lossy().into_owned().into();
|
||||
let path = path.clone();
|
||||
let project_group_key = project_group_key.clone();
|
||||
let multi_workspace = multi_workspace.clone();
|
||||
menu = menu.entry_with_end_slot_on_hover(
|
||||
name.clone(),
|
||||
None,
|
||||
|_, _| {},
|
||||
IconName::Close,
|
||||
"Remove Folder".into(),
|
||||
remove_handler,
|
||||
move |_window, cx| {
|
||||
multi_workspace
|
||||
.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.remove_folder_from_project_group(
|
||||
&project_group_key,
|
||||
&path,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let workspace_for_add = workspace.clone();
|
||||
let multi_workspace_for_add = multi_workspace.clone();
|
||||
let menu = menu.separator().entry(
|
||||
"Add Folder to Project",
|
||||
Some(Box::new(AddFolderToProject)),
|
||||
move |window, cx| {
|
||||
if let Some(mw) = multi_workspace_for_add.upgrade() {
|
||||
mw.update(cx, |mw, cx| {
|
||||
mw.activate(workspace_for_add.clone(), window, cx);
|
||||
});
|
||||
{
|
||||
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.prompt_to_add_folders_to_project_group(
|
||||
&project_group_key,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
workspace_for_add.update(cx, |workspace, cx| {
|
||||
workspace.add_folder_to_project(&AddFolderToProject, window, cx);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let workspace_count = multi_workspace
|
||||
let group_count = multi_workspace
|
||||
.upgrade()
|
||||
.map_or(0, |mw| mw.read(cx).workspaces().len());
|
||||
let menu = if workspace_count > 1 {
|
||||
let workspace_for_move = workspace.clone();
|
||||
let multi_workspace_for_move = multi_workspace.clone();
|
||||
.map_or(0, |mw| mw.read(cx).project_group_keys().count());
|
||||
let menu = if group_count > 1 {
|
||||
let project_group_key = project_group_key.clone();
|
||||
let multi_workspace = multi_workspace.clone();
|
||||
menu.entry(
|
||||
"Move to New Window",
|
||||
Some(Box::new(
|
||||
zed_actions::agents_sidebar::MoveWorkspaceToNewWindow,
|
||||
)),
|
||||
move |window, cx| {
|
||||
if let Some(mw) = multi_workspace_for_move.upgrade() {
|
||||
mw.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.move_workspace_to_new_window(
|
||||
&workspace_for_move,
|
||||
multi_workspace
|
||||
.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.move_project_group_to_new_window(
|
||||
&project_group_key,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
},
|
||||
)
|
||||
} else {
|
||||
menu
|
||||
};
|
||||
|
||||
let workspace_for_remove = workspace_for_remove.clone();
|
||||
let multi_workspace_for_remove = multi_workspace.clone();
|
||||
let project_group_key = project_group_key.clone();
|
||||
let multi_workspace = multi_workspace.clone();
|
||||
menu.separator()
|
||||
.entry("Remove Project", None, move |window, cx| {
|
||||
if let Some(mw) = multi_workspace_for_remove.upgrade() {
|
||||
let ws = workspace_for_remove.clone();
|
||||
mw.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.remove(&ws, window, cx);
|
||||
});
|
||||
}
|
||||
multi_workspace
|
||||
.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.remove_project_group(
|
||||
&project_group_key,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
});
|
||||
|
||||
@@ -2176,16 +2142,12 @@ impl Sidebar {
|
||||
return;
|
||||
};
|
||||
|
||||
let paths: Vec<std::path::PathBuf> =
|
||||
path_list.paths().iter().map(|p| p.to_path_buf()).collect();
|
||||
|
||||
let open_task = multi_workspace.update(cx, |mw, cx| {
|
||||
mw.open_project(paths, workspace::OpenMode::Activate, window, cx)
|
||||
let open_task = multi_workspace.update(cx, |this, cx| {
|
||||
this.find_or_create_local_workspace(path_list, window, cx)
|
||||
});
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let workspace = open_task.await?;
|
||||
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
this.activate_thread(metadata, &workspace, window, cx);
|
||||
})?;
|
||||
|
||||
@@ -65,6 +65,16 @@ impl PathList {
|
||||
self.paths.is_empty()
|
||||
}
|
||||
|
||||
/// Returns a new `PathList` with the given path removed.
|
||||
pub fn without_path(&self, path_to_remove: &Path) -> PathList {
|
||||
let paths: Vec<PathBuf> = self
|
||||
.ordered_paths()
|
||||
.filter(|p| p.as_path() != path_to_remove)
|
||||
.cloned()
|
||||
.collect();
|
||||
PathList::new(&paths)
|
||||
}
|
||||
|
||||
/// Get the paths in lexicographic order.
|
||||
pub fn paths(&self) -> &[PathBuf] {
|
||||
self.paths.as_ref()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt};
|
||||
use gpui::PathPromptOptions;
|
||||
use gpui::{
|
||||
AnyView, App, Context, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, Focusable,
|
||||
ManagedView, MouseButton, Pixels, Render, Subscription, Task, Tiling, Window, WindowId,
|
||||
@@ -7,14 +8,16 @@ use gpui::{
|
||||
};
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use project::Project;
|
||||
use project::{DisableAiSettings, ProjectGroupKey};
|
||||
use project::{DirectoryLister, DisableAiSettings, ProjectGroupKey};
|
||||
use settings::Settings;
|
||||
pub use settings::SidebarSide;
|
||||
use std::future::Future;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use ui::prelude::*;
|
||||
use util::ResultExt;
|
||||
use util::path_list::PathList;
|
||||
use zed_actions::agents_sidebar::{MoveWorkspaceToNewWindow, ToggleThreadSwitcher};
|
||||
|
||||
use agent_settings::AgentSettings;
|
||||
@@ -23,6 +26,7 @@ use ui::{ContextMenu, right_click_menu};
|
||||
|
||||
const SIDEBAR_RESIZE_HANDLE_SIZE: Pixels = px(6.0);
|
||||
|
||||
use crate::AppState;
|
||||
use crate::{
|
||||
CloseIntent, CloseWindow, DockPosition, Event as WorkspaceEvent, Item, ModalView, OpenMode,
|
||||
Panel, Workspace, WorkspaceId, client_side_decorations,
|
||||
@@ -494,6 +498,176 @@ impl MultiWorkspace {
|
||||
groups.into_iter()
|
||||
}
|
||||
|
||||
pub fn workspaces_for_project_group(
|
||||
&self,
|
||||
project_group_key: &ProjectGroupKey,
|
||||
cx: &App,
|
||||
) -> impl Iterator<Item = &Entity<Workspace>> {
|
||||
self.workspaces
|
||||
.iter()
|
||||
.filter(move |ws| ws.read(cx).project_group_key(cx) == *project_group_key)
|
||||
}
|
||||
|
||||
pub fn remove_folder_from_project_group(
|
||||
&mut self,
|
||||
project_group_key: &ProjectGroupKey,
|
||||
path: &Path,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let new_path_list = project_group_key.path_list().without_path(path);
|
||||
if new_path_list.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_key = ProjectGroupKey::new(project_group_key.host(), new_path_list);
|
||||
|
||||
let workspaces: Vec<_> = self
|
||||
.workspaces_for_project_group(project_group_key, cx)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
self.add_project_group_key(new_key);
|
||||
|
||||
for workspace in workspaces {
|
||||
let project = workspace.read(cx).project().clone();
|
||||
project.update(cx, |project, cx| {
|
||||
project.remove_worktree_for_main_worktree_path(path, cx);
|
||||
});
|
||||
}
|
||||
|
||||
self.serialize(cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn prompt_to_add_folders_to_project_group(
|
||||
&mut self,
|
||||
key: &ProjectGroupKey,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let paths = self.workspace().update(cx, |workspace, cx| {
|
||||
workspace.prompt_for_open_path(
|
||||
PathPromptOptions {
|
||||
files: false,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
prompt: None,
|
||||
},
|
||||
DirectoryLister::Project(workspace.project().clone()),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let key = key.clone();
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
if let Some(new_paths) = paths.await.ok().flatten() {
|
||||
if !new_paths.is_empty() {
|
||||
this.update(cx, |multi_workspace, cx| {
|
||||
multi_workspace.add_folders_to_project_group(&key, new_paths, cx);
|
||||
})?;
|
||||
}
|
||||
}
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub fn add_folders_to_project_group(
|
||||
&mut self,
|
||||
project_group_key: &ProjectGroupKey,
|
||||
new_paths: Vec<PathBuf>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let mut all_paths: Vec<PathBuf> = project_group_key.path_list().paths().to_vec();
|
||||
all_paths.extend(new_paths.iter().cloned());
|
||||
let new_path_list = PathList::new(&all_paths);
|
||||
let new_key = ProjectGroupKey::new(project_group_key.host(), new_path_list);
|
||||
|
||||
let workspaces: Vec<_> = self
|
||||
.workspaces_for_project_group(project_group_key, cx)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
self.add_project_group_key(new_key);
|
||||
|
||||
for workspace in workspaces {
|
||||
let project = workspace.read(cx).project().clone();
|
||||
for path in &new_paths {
|
||||
project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_worktree(path, true, cx)
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
}
|
||||
|
||||
self.serialize(cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn remove_project_group(
|
||||
&mut self,
|
||||
key: &ProjectGroupKey,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.project_group_keys.retain(|k| k != key);
|
||||
|
||||
let workspaces: Vec<_> = self
|
||||
.workspaces_for_project_group(key, cx)
|
||||
.cloned()
|
||||
.collect();
|
||||
for workspace in workspaces {
|
||||
self.remove(&workspace, window, cx);
|
||||
}
|
||||
|
||||
self.serialize(cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Finds an existing workspace in this multi-workspace whose paths match,
|
||||
/// or creates a new one (deserializing its saved state from the database).
|
||||
/// Never searches other windows or matches workspaces with a superset of
|
||||
/// the requested paths.
|
||||
pub fn find_or_create_local_workspace(
|
||||
&mut self,
|
||||
path_list: PathList,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<Workspace>>> {
|
||||
if let Some(workspace) = self
|
||||
.workspaces
|
||||
.iter()
|
||||
.find(|ws| ws.read(cx).project_group_key(cx).path_list() == &path_list)
|
||||
.cloned()
|
||||
{
|
||||
self.activate(workspace.clone(), window, cx);
|
||||
return Task::ready(Ok(workspace));
|
||||
}
|
||||
|
||||
let paths = path_list.paths().to_vec();
|
||||
let app_state = self.workspace().read(cx).app_state().clone();
|
||||
let requesting_window = window.window_handle().downcast::<MultiWorkspace>();
|
||||
|
||||
cx.spawn(async move |_this, cx| {
|
||||
let result = cx
|
||||
.update(|cx| {
|
||||
Workspace::new_local(
|
||||
paths,
|
||||
app_state,
|
||||
requesting_window,
|
||||
None,
|
||||
None,
|
||||
OpenMode::Activate,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await?;
|
||||
Ok(result.workspace)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn workspace(&self) -> &Entity<Workspace> {
|
||||
&self.workspaces[self.active_workspace_index]
|
||||
}
|
||||
@@ -892,7 +1066,7 @@ impl MultiWorkspace {
|
||||
return;
|
||||
}
|
||||
|
||||
let app_state: Arc<crate::AppState> = workspace.read(cx).app_state().clone();
|
||||
let app_state: Arc<AppState> = workspace.read(cx).app_state().clone();
|
||||
|
||||
cx.defer(move |cx| {
|
||||
let options = (app_state.build_window_options)(None, cx);
|
||||
@@ -909,7 +1083,58 @@ impl MultiWorkspace {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Move group to a new window?
|
||||
pub fn move_project_group_to_new_window(
|
||||
&mut self,
|
||||
key: &ProjectGroupKey,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let workspaces: Vec<_> = self
|
||||
.workspaces_for_project_group(key, cx)
|
||||
.cloned()
|
||||
.collect();
|
||||
if workspaces.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.project_group_keys.retain(|k| k != key);
|
||||
|
||||
let mut removed = Vec::new();
|
||||
for workspace in &workspaces {
|
||||
if self.remove(workspace, window, cx) {
|
||||
removed.push(workspace.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if removed.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let app_state = removed[0].read(cx).app_state().clone();
|
||||
|
||||
cx.defer(move |cx| {
|
||||
let options = (app_state.build_window_options)(None, cx);
|
||||
|
||||
let first = removed[0].clone();
|
||||
let rest = removed[1..].to_vec();
|
||||
|
||||
let Ok(new_window) = cx.open_window(options, |window, cx| {
|
||||
cx.new(|cx| MultiWorkspace::new(first, window, cx))
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
|
||||
new_window
|
||||
.update(cx, |mw, window, cx| {
|
||||
for workspace in rest {
|
||||
mw.activate(workspace, window, cx);
|
||||
}
|
||||
window.activate_window();
|
||||
})
|
||||
.log_err();
|
||||
});
|
||||
}
|
||||
|
||||
fn move_active_workspace_to_new_window(
|
||||
&mut self,
|
||||
_: &MoveWorkspaceToNewWindow,
|
||||
@@ -927,16 +1152,10 @@ impl MultiWorkspace {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<Workspace>>> {
|
||||
let workspace = self.workspace().clone();
|
||||
|
||||
let needs_close_prompt = !self.multi_workspace_enabled(cx);
|
||||
let open_mode = if self.multi_workspace_enabled(cx) {
|
||||
open_mode
|
||||
if self.multi_workspace_enabled(cx) {
|
||||
self.find_or_create_local_workspace(PathList::new(&paths), window, cx)
|
||||
} else {
|
||||
OpenMode::Activate
|
||||
};
|
||||
|
||||
if needs_close_prompt {
|
||||
let workspace = self.workspace().clone();
|
||||
cx.spawn_in(window, async move |_this, cx| {
|
||||
let should_continue = workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
@@ -953,10 +1172,6 @@ impl MultiWorkspace {
|
||||
Ok(workspace)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.open_workspace_for_paths(open_mode, paths, window, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user