Simplify handle_workspace_key_change: move workspace to matching group

Nathan Sobo created

Individual workspace changes move the workspace to a new or existing
group matching its new key. No sibling cascading — that's only for
group-level operations (add_folders_to_project_group, etc.).

Old group is cleaned up if left empty. If the new key matches an
existing group, the workspace joins it (natural merge).

Change summary

crates/sidebar/src/sidebar_tests.proptest-regressions |  1 
crates/workspace/src/multi_workspace.rs               | 79 +-----------
2 files changed, 13 insertions(+), 67 deletions(-)

Detailed changes

crates/sidebar/src/sidebar_tests.proptest-regressions 🔗

@@ -7,3 +7,4 @@
 cc e5848f13ac6e2dd83819558a65f5836e5196ff6a2dc5289032e28b4cabf2bf83 # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 8911164217610394189, raw_operations: [81, 208] }
 cc 83c95196677f617710761c1163124d3eec7db0e99c0c85fb1fd6d26ce5a6fb2a # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 17358113519749946733, raw_operations: [225, 16] }
 cc 8c6876d3e226c22e3eb57fa40f9b8d8f0cb6b4d21ea15a9af643b028d44693c8 # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 8906097005873738186, raw_operations: [153, 112] }
+cc 562a84b1c8fad8b9109ade8380a54910fbf558b7d86b5d3785b66b933762fee6 # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 7154971574717061752, raw_operations: [201, 208] }

crates/workspace/src/multi_workspace.rs 🔗

@@ -555,77 +555,22 @@ impl MultiWorkspace {
             return;
         }
 
-        // Find which group this workspace is in
-        let group_idx = self
-            .project_groups
-            .iter()
-            .position(|g| g.workspaces.contains(workspace));
-
-        if let Some(idx) = group_idx {
-            let old_key = self.project_groups[idx].key.clone();
-            if old_key == new_key {
+        // Check if the workspace's key already matches its group
+        if let Some(group) = self.group_for_workspace(workspace) {
+            if group.key == new_key {
                 return;
             }
+        }
 
-            let old_paths = old_key.path_list().paths().to_vec();
-            let new_paths = new_key.path_list().paths().to_vec();
-            let changed_root_paths = workspace.read(cx).root_paths(cx);
-            let workspace_id = workspace.entity_id();
-
-            // Remove true duplicates from the same group
-            let duplicates: Vec<Entity<Workspace>> = self.project_groups[idx]
-                .workspaces
-                .iter()
-                .filter(|ws| {
-                    ws.entity_id() != workspace_id
-                        && ws.read(cx).root_paths(cx) == changed_root_paths
-                })
-                .cloned()
-                .collect();
-
-            let active = self.active_workspace.clone();
-            if duplicates.contains(&active) {
-                // Active is a duplicate — remove the incoming workspace instead
-                self.project_groups[idx]
-                    .workspaces
-                    .retain(|w| w != workspace);
-                self.detach_workspace(workspace, cx);
-            } else {
-                for ws in &duplicates {
-                    self.project_groups[idx].workspaces.retain(|w| w != ws);
-                    self.detach_workspace(ws, cx);
-                }
-            }
-
-            // Propagate folder adds/removes to sibling workspaces in the same group
-            let siblings: Vec<Entity<Workspace>> = self.project_groups[idx]
-                .workspaces
-                .iter()
-                .filter(|ws| ws.entity_id() != workspace_id)
-                .cloned()
-                .collect();
-
-            for sibling in &siblings {
-                let project = sibling.read(cx).project().clone();
-
-                for added_path in new_paths.iter().filter(|p| !old_paths.contains(p)) {
-                    project
-                        .update(cx, |project, cx| {
-                            project.find_or_create_worktree(added_path, true, cx)
-                        })
-                        .detach_and_log_err(cx);
-                }
-
-                for removed_path in old_paths.iter().filter(|p| !new_paths.contains(p)) {
-                    project.update(cx, |project, cx| {
-                        project.remove_worktree_for_main_worktree_path(removed_path, cx);
-                    });
-                }
-            }
-
-            // Update the group's key in-place — the ID stays the same
-            self.project_groups[idx].key = new_key;
+        // Remove the workspace from its current group
+        for group in &mut self.project_groups {
+            group.workspaces.retain(|w| w != workspace);
         }
+        // Clean up empty groups
+        self.project_groups.retain(|g| !g.workspaces.is_empty());
+
+        // Add the workspace to the group matching its new key (or create one)
+        self.ensure_workspace_in_group(workspace.clone(), new_key, cx);
 
         self.serialize(cx);
         cx.notify();