diff options
Diffstat (limited to 'src/app/actions.rs')
| -rw-r--r-- | src/app/actions.rs | 75 |
1 files changed, 70 insertions, 5 deletions
diff --git a/src/app/actions.rs b/src/app/actions.rs index 23b886d9..a7d99f35 100644 --- a/src/app/actions.rs +++ b/src/app/actions.rs @@ -1349,6 +1349,15 @@ impl AppState { .collect() } + pub(crate) fn pane_ids_for_workspace(&self, ws_idx: usize) -> Vec<PaneId> { + self.workspaces + .get(ws_idx) + .into_iter() + .flat_map(|ws| &ws.tabs) + .flat_map(|tab| tab.layout.pane_ids()) + .collect() + } + pub(crate) fn terminal_ids_for_tab( &self, ws_idx: usize, @@ -1363,6 +1372,14 @@ impl AppState { .collect() } + pub(crate) fn pane_ids_for_tab(&self, ws_idx: usize, tab_idx: usize) -> Vec<PaneId> { + self.workspaces + .get(ws_idx) + .and_then(|ws| ws.tabs.get(tab_idx)) + .map(|tab| tab.layout.pane_ids()) + .unwrap_or_default() + } + pub(crate) fn terminal_id_for_pane( &self, ws_idx: usize, @@ -1395,6 +1412,15 @@ impl AppState { } } + pub(crate) fn remove_plugin_pane_records( + &mut self, + pane_ids: impl IntoIterator<Item = PaneId>, + ) { + for pane_id in pane_ids { + self.plugin_panes.remove(&pane_id); + } + } + pub fn close_selected_workspace(&mut self) { if self.workspaces.is_empty() { return; @@ -1422,12 +1448,15 @@ impl AppState { .unwrap_or_else(|| vec![self.selected]); let mut terminal_ids = Vec::new(); + let mut pane_ids = Vec::new(); for idx in &close_indices { terminal_ids.extend(self.terminal_ids_for_workspace(*idx)); + pane_ids.extend(self.pane_ids_for_workspace(*idx)); if let Some(workspace_id) = self.workspaces.get(*idx).map(|ws| ws.id.clone()) { crate::logging::workspace_closed(&workspace_id); } } + self.remove_plugin_pane_records(pane_ids); for idx in close_indices.iter().rev() { self.workspaces.remove(*idx); } @@ -1761,9 +1790,14 @@ impl AppState { .and_then(|(i, pane_id)| self.terminal_id_for_pane(i, pane_id)) .into_iter() .collect::<Vec<_>>(); + let pane_ids = active + .and_then(|i| self.workspaces.get(i).and_then(|ws| ws.focused_pane_id())) + .into_iter() + .collect::<Vec<_>>(); let should_close_workspace = active .and_then(|i| self.workspaces.get_mut(i)) .is_some_and(|ws| ws.close_focused()); + self.remove_plugin_pane_records(pane_ids); if should_close_workspace { if let Some(active) = active { self.selected = active; @@ -1810,12 +1844,18 @@ impl AppState { .get(ws_idx) .map(|ws| self.terminal_ids_for_tab(ws_idx, ws.active_tab)) .unwrap_or_default(); + let pane_ids = self + .workspaces + .get(ws_idx) + .map(|ws| self.pane_ids_for_tab(ws_idx, ws.active_tab)) + .unwrap_or_default(); let Some(ws) = self.workspaces.get_mut(ws_idx) else { return false; }; let workspace_id = ws.id.clone(); let closing_tab_id = format!("{}:{}", workspace_id, ws.active_tab + 1); ws.close_active_tab(); + self.remove_plugin_pane_records(pane_ids); self.remove_unattached_terminal_ids(terminal_ids); crate::logging::tab_closed(&workspace_id, &closing_tab_id); self.tab_scroll_follow_active = true; @@ -2502,6 +2542,7 @@ impl AppState { } AppEvent::WorktreeAddFinished(_) => Vec::new(), AppEvent::WorktreeRemoveFinished(_) => Vec::new(), + AppEvent::PluginCommandFinished { .. } => Vec::new(), } } @@ -2791,6 +2832,7 @@ impl AppState { fn handle_pane_died(&mut self, pane_id: PaneId) { self.pending_agent_notifications.remove(&pane_id); + self.plugin_panes.remove(&pane_id); let ws_idx = self .workspaces .iter() @@ -3161,10 +3203,10 @@ mod tests { 0, crate::terminal_theme::TerminalTheme::default(), crate::pane::PaneShellConfig::new("/bin/sh", crate::config::ShellModeConfig::NonLogin), + &crate::pane::PaneLaunchEnv::default(), events, std::sync::Arc::new(tokio::sync::Notify::new()), std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), - None, ) .unwrap(); @@ -4875,11 +4917,19 @@ mod tests { #[test] fn close_pane_removes_from_workspace() { let mut state = app_with_workspaces(&["test"]); - state.workspaces[0].test_split(Direction::Horizontal); + let closed = state.workspaces[0].test_split(Direction::Horizontal); assert_eq!(state.workspaces[0].panes.len(), 2); + state.plugin_panes.insert( + closed, + crate::app::state::PluginPaneRecord { + plugin_id: "example.pane".into(), + entrypoint: "board".into(), + }, + ); state.close_pane(); assert_eq!(state.workspaces[0].panes.len(), 1); + assert!(!state.plugin_panes.contains_key(&closed)); } #[test] @@ -4935,22 +4985,37 @@ mod tests { state.workspaces[0].switch_tab(tab_idx); let pane_id = state.workspaces[0].tabs[tab_idx].root_pane; let terminal_id = state.terminal_id_for_pane(0, pane_id).unwrap(); + state.plugin_panes.insert( + pane_id, + crate::app::state::PluginPaneRecord { + plugin_id: "example.pane".into(), + entrypoint: "board".into(), + }, + ); state.close_tab(); assert!(!state.terminals.contains_key(&terminal_id)); + assert!(!state.plugin_panes.contains_key(&pane_id)); } #[test] fn close_workspace_removes_unattached_terminal_states() { let mut state = app_with_workspaces(&["one", "two"]); - let terminal_id = state - .terminal_id_for_pane(0, state.workspaces[0].tabs[0].root_pane) - .unwrap(); + let pane_id = state.workspaces[0].tabs[0].root_pane; + let terminal_id = state.terminal_id_for_pane(0, pane_id).unwrap(); + state.plugin_panes.insert( + pane_id, + crate::app::state::PluginPaneRecord { + plugin_id: "example.pane".into(), + entrypoint: "board".into(), + }, + ); state.close_selected_workspace(); assert!(!state.terminals.contains_key(&terminal_id)); + assert!(!state.plugin_panes.contains_key(&pane_id)); } #[test] |
