diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index e8a16a20f722dd69488348fa944df3527c6806ee..26ad334c32b06b673d70e49b6e8e5864377562cb 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -1931,7 +1931,8 @@ impl RecentProjectsDelegate { .workspaces() .find(|ws| ws.read(cx).database_id() == Some(workspace_id)); if let Some(workspace) = workspace { - multi_workspace.remove_group(&workspace, window, cx); + multi_workspace + .remove_group_containing_workspace(&workspace, window, cx); } }) .log_err(); diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index b3cc2f42d9237482fdbbcb9d96e5e82c403f8b80..89e9bce93ee44cb625333a46c769d0bca84234d2 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -793,13 +793,6 @@ impl Sidebar { let should_load_threads = !is_collapsed || !query.is_empty(); let is_active = group.workspaces.contains(&active_workspace); - // Pick a representative workspace for the group: prefer the active - // workspace if it belongs to this group, otherwise use the main - // repo workspace (not a linked worktree). - let representative_workspace = Some(&active_workspace) - .filter(|_| is_active) - .unwrap_or_else(|| group.main_workspace(cx)); - // Collect live thread infos from all workspaces in this group. let live_infos: Vec<_> = group .workspaces @@ -854,23 +847,21 @@ impl Sidebar { // Load threads from linked git worktrees whose // canonical paths belong to this group. - let linked_worktree_queries = group + let linked_worktree_paths = group .workspaces - .iter() - .flat_map(|ws| root_repository_snapshots(ws, cx)) - .filter(|snapshot| !snapshot.is_linked_worktree()) - .flat_map(|snapshot| { - snapshot - .linked_worktrees() - .iter() - .filter(|wt| { - project_groups.group_owns_worktree(group, &path_list, &wt.path) + .first() + .map(|workspace| { + root_repository_snapshots(workspace, cx) + .flat_map(|repo| { + repo.linked_worktrees + .iter() + .map(|worktree| worktree.path.clone()) }) - .map(|wt| PathList::new(std::slice::from_ref(&wt.path))) .collect::>() - }); + }) + .unwrap_or_default(); - for worktree_path_list in linked_worktree_queries { + for worktree_path_list in linked_worktree_paths { for row in thread_store .read(cx) .entries_for_path(&worktree_path_list) @@ -1584,7 +1575,8 @@ impl Sidebar { 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_group(&ws, window, cx); + multi_workspace + .remove_group_containing_workspace(&ws, window, cx); }); } } else { @@ -1657,7 +1649,8 @@ impl Sidebar { if let Some(mw) = multi_workspace_for_remove.upgrade() { let ws = workspace_for_remove.clone(); mw.update(cx, |multi_workspace, cx| { - multi_workspace.remove_group(&ws, window, cx); + multi_workspace + .remove_group_containing_workspace(&ws, window, cx); }); } }) diff --git a/crates/sidebar/src/sidebar_tests.rs b/crates/sidebar/src/sidebar_tests.rs index 86e6029e406343ebfdac7472a426454f25c4cc18..e20a7e9f585781a52f4edbd00cdc4997b87dba99 100644 --- a/crates/sidebar/src/sidebar_tests.rs +++ b/crates/sidebar/src/sidebar_tests.rs @@ -516,7 +516,7 @@ async fn test_workspace_lifecycle(cx: &mut TestAppContext) { // Remove the second workspace multi_workspace.update_in(cx, |mw, window, cx| { let workspace = mw.workspaces().nth(1).unwrap().clone(); - mw.remove_group(&workspace, window, cx); + mw.remove_group_containing_workspace(&workspace, window, cx); }); cx.run_until_parked(); @@ -5061,7 +5061,7 @@ mod property_test { Operation::RemoveWorkspace { index } => { let removed = multi_workspace.update_in(cx, |mw, window, cx| { let workspace = mw.workspaces().nth(index).unwrap().clone(); - mw.remove_group(&workspace, window, cx) + mw.remove_group_containing_workspace(&workspace, window, cx) }); if removed { state.workspace_paths.remove(index); diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index 91b51d255bd3a2f9a07d14eae1c8cad224723f6c..db65f646c7614a1e1eab245cc9d059a939fd3f60 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/crates/workspace/src/multi_workspace.rs @@ -23,6 +23,7 @@ use ui::{ContextMenu, right_click_menu}; const SIDEBAR_RESIZE_HANDLE_SIZE: Pixels = px(6.0); +use crate::SerializedWorkspaceLocation; use crate::{ CloseIntent, CloseWindow, DockPosition, Event as WorkspaceEvent, Item, ModalView, OpenMode, Panel, Workspace, WorkspaceId, client_side_decorations, @@ -255,6 +256,17 @@ impl ProjectGroupKey { host, } } + + pub fn from_location_and_paths(location: SerializedWorkspaceLocation, paths: PathList) -> Self { + let host = match location { + SerializedWorkspaceLocation::Local => None, + SerializedWorkspaceLocation::Remote(options) => Some(options), + }; + Self { + main_worktree_paths: paths, + host, + } + } } pub struct MultiWorkspace { @@ -447,6 +459,10 @@ impl MultiWorkspace { &self.project_groups } + pub fn project_group_keys(&self) -> impl Iterator { + self.project_groups.iter().map(|group| &group.key) + } + pub fn open_sidebar(&mut self, cx: &mut Context) { self.sidebar_open = true; let sidebar_focus_handle = self.sidebar.as_ref().map(|s| s.focus_handle(cx)); @@ -908,7 +924,8 @@ impl MultiWorkspace { } /// Removes the group that contains this workspace. - pub fn remove_group( + #[deprecated = "use remove_group instead"] + pub fn remove_group_containing_workspace( &mut self, workspace: &Entity, window: &mut Window, @@ -921,11 +938,33 @@ impl MultiWorkspace { else { return false; }; + self.remove_group_at_index(group_ix, window, cx); + true + } + pub fn remove_group( + &mut self, + key: ProjectGroupKey, + window: &mut Window, + cx: &mut Context, + ) -> bool { + let Some(group_ix) = self.project_groups.iter_mut().position(|g| g.key == key) else { + return false; + }; + self.remove_group_at_index(group_ix, window, cx); + true + } + + fn remove_group_at_index( + &mut self, + group_ix: usize, + window: &mut Window, + cx: &mut Context, + ) { let removed_group = self.project_groups.remove(group_ix); // If we removed the active workspace, pick a new one. - let app_state = workspace.read(cx).app_state().clone(); + let app_state = self.active_workspace.read(cx).app_state().clone(); if removed_group.workspaces.contains(&self.active_workspace) { let workspace = self.workspaces().next(); if let Some(workspace) = workspace { @@ -958,8 +997,6 @@ impl MultiWorkspace { cx.emit(MultiWorkspaceEvent::WorkspaceRemoved); cx.emit(MultiWorkspaceEvent::ActiveWorkspaceChanged); cx.notify(); - - true } pub fn move_workspace_to_new_window( @@ -969,7 +1006,7 @@ impl MultiWorkspace { cx: &mut Context, ) { let workspace = workspace.clone(); - if !self.remove_group(&workspace, window, cx) { + if !self.remove_group_containing_workspace(&workspace, window, cx) { return; } diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 0ce27990fa7d6efae230d008bbf0dd8260f4ad73..68bab620999d6579c4db065d8bd370dca01bd834 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -2561,7 +2561,7 @@ mod tests { .nth(1) .expect("no workspace at index 1") .clone(); - mw.remove_group(&ws, window, cx); + mw.remove_group_containing_workspace(&ws, window, cx); }); cx.run_until_parked(); @@ -4248,7 +4248,7 @@ mod tests { .nth(1) .expect("no workspace at index 1") .clone(); - mw.remove_group(&ws, window, cx); + mw.remove_group_containing_workspace(&ws, window, cx); }); cx.run_until_parked(); @@ -4363,7 +4363,7 @@ mod tests { .nth(1) .expect("no workspace at index 1") .clone(); - mw.remove_group(&ws, window, cx); + mw.remove_group_containing_workspace(&ws, window, cx); }); cx.run_until_parked(); @@ -4451,7 +4451,7 @@ mod tests { .nth(1) .expect("no workspace at index 1") .clone(); - mw.remove_group(&ws, window, cx); + mw.remove_group_containing_workspace(&ws, window, cx); }); // Simulate the quit handler pattern: collect flush tasks + pending