aboutsummaryrefslogtreecommitdiff
path: root/src/app/actions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/actions.rs')
-rw-r--r--src/app/actions.rs75
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]