diff options
Diffstat (limited to 'src/app/actions.rs')
| -rw-r--r-- | src/app/actions.rs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/app/actions.rs b/src/app/actions.rs index 0709ed4c..10d28054 100644 --- a/src/app/actions.rs +++ b/src/app/actions.rs @@ -1390,6 +1390,73 @@ impl AppState { true } + pub fn move_workspace_block( + &mut self, + workspace_ids: &[String], + before_workspace_id: Option<&str>, + ) -> bool { + let moved_ids = workspace_ids + .iter() + .map(String::as_str) + .collect::<std::collections::HashSet<_>>(); + if moved_ids.is_empty() + || moved_ids.len() != workspace_ids.len() + || !workspace_ids + .iter() + .all(|id| self.workspaces.iter().any(|workspace| workspace.id == *id)) + || before_workspace_id.is_some_and(|id| { + moved_ids.contains(id) + || !self.workspaces.iter().any(|workspace| workspace.id == id) + }) + { + return false; + } + + let mut desired_ids = self + .workspaces + .iter() + .filter(|workspace| !moved_ids.contains(workspace.id.as_str())) + .map(|workspace| workspace.id.clone()) + .collect::<Vec<_>>(); + let insert_idx = before_workspace_id + .and_then(|id| desired_ids.iter().position(|candidate| candidate == id)) + .unwrap_or(desired_ids.len()); + desired_ids.splice(insert_idx..insert_idx, workspace_ids.iter().cloned()); + if self + .workspaces + .iter() + .map(|workspace| workspace.id.as_str()) + .eq(desired_ids.iter().map(String::as_str)) + { + return false; + } + + let active_id = self.active.map(|idx| self.workspaces[idx].id.clone()); + let selected_id = self + .workspaces + .get(self.selected) + .map(|workspace| workspace.id.clone()); + let desired_positions = desired_ids + .iter() + .enumerate() + .map(|(index, id)| (id.clone(), index)) + .collect::<std::collections::HashMap<_, _>>(); + + self.mark_session_dirty(); + self.workspaces.sort_by_key(|workspace| { + desired_positions + .get(&workspace.id) + .copied() + .unwrap_or(usize::MAX) + }); + self.active = active_id.and_then(|id| self.workspaces.iter().position(|ws| ws.id == id)); + self.selected = selected_id + .and_then(|id| self.workspaces.iter().position(|ws| ws.id == id)) + .unwrap_or(0); + self.ensure_workspace_visible(self.selected); + true + } + pub fn scroll_tabs_left(&mut self) { self.tab_scroll_follow_active = false; self.tab_scroll = self.tab_scroll.saturating_sub(1); @@ -4434,6 +4501,59 @@ mod tests { } #[test] + fn move_workspace_block_collects_non_contiguous_members() { + let mut state = + app_with_workspaces(&["child-one", "normal", "parent", "child-two", "tail"]); + let parent_id = state.workspaces[2].id.clone(); + let child_one_id = state.workspaces[0].id.clone(); + let child_two_id = state.workspaces[3].id.clone(); + let tail_id = state.workspaces[4].id.clone(); + state.active = Some(0); + state.selected = 4; + + assert!(state.move_workspace_block( + &[parent_id, child_one_id.clone(), child_two_id], + Some(&tail_id), + )); + + let names = state + .workspaces + .iter() + .map(|workspace| workspace.display_name()) + .collect::<Vec<_>>(); + assert_eq!( + names, + ["normal", "parent", "child-one", "child-two", "tail"] + ); + assert_eq!(state.workspaces[state.active.unwrap()].id, child_one_id); + assert_eq!(state.workspaces[state.selected].id, tail_id); + } + + #[test] + fn move_workspace_block_rejects_invalid_and_noop_orders() { + let mut state = app_with_workspaces(&["a", "b", "c"]); + let ids = state + .workspaces + .iter() + .map(|workspace| workspace.id.clone()) + .collect::<Vec<_>>(); + + assert!(!state.move_workspace_block(&[], None)); + assert!(!state.move_workspace_block(&[ids[0].clone(), ids[0].clone()], None)); + assert!(!state.move_workspace_block(&["missing".into()], None)); + assert!(!state.move_workspace_block(&[ids[0].clone()], Some(&ids[0]))); + assert!(!state.move_workspace_block(&[ids[0].clone()], Some(&ids[1]))); + assert_eq!( + state + .workspaces + .iter() + .map(|workspace| workspace.display_name()) + .collect::<Vec<_>>(), + ["a", "b", "c"] + ); + } + + #[test] fn close_workspace_adjusts_indices() { let mut state = app_with_workspaces(&["a", "b", "c"]); state.selected = 1; |
