diff options
Diffstat (limited to 'src/app/runtime_commands.rs')
| -rw-r--r-- | src/app/runtime_commands.rs | 177 |
1 files changed, 0 insertions, 177 deletions
diff --git a/src/app/runtime_commands.rs b/src/app/runtime_commands.rs deleted file mode 100644 index ad9b85bc..00000000 --- a/src/app/runtime_commands.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Runtime command launching and overlay pane lifecycle helpers for [`App`]. - -use std::process::{Command, Stdio}; - -use ratatui::layout::Direction; - -use super::{App, Mode}; - -#[derive(Debug, Clone, Copy)] -pub(super) struct OverlayPaneState { - ws_idx: usize, - tab_idx: usize, - previous_focus: crate::layout::PaneId, - previous_zoomed: bool, -} - -impl App { - pub(super) fn launch_custom_command(&mut self, binding: crate::config::CustomCommandKeybind) { - let previous_toast = self.state.toast.clone(); - let result = match binding.action { - crate::config::CustomCommandAction::Shell => self.spawn_custom_command(&binding), - crate::config::CustomCommandAction::Pane => self.spawn_pane_command(&binding.command), - }; - match result { - Ok(()) => { - if self.state.active.is_some() { - self.state.mode = Mode::Terminal; - } - } - Err(err) => { - self.state.toast = Some(crate::app::state::ToastNotification { - kind: crate::app::state::ToastKind::NeedsAttention, - title: "custom command failed".to_string(), - context: err.to_string(), - }); - self.sync_toast_deadline(previous_toast); - } - } - } - - fn custom_command_env(&self) -> (Vec<(String, String)>, Option<std::path::PathBuf>) { - let mut env = vec![( - crate::api::SOCKET_PATH_ENV_VAR.to_string(), - crate::api::socket_path().display().to_string(), - )]; - if let Ok(current_exe) = std::env::current_exe() { - env.push(( - "HERDR_BIN_PATH".to_string(), - current_exe.display().to_string(), - )); - } - - let mut cwd = None; - if let Some(ws_idx) = self.state.active { - env.push(( - "HERDR_ACTIVE_WORKSPACE_ID".to_string(), - self.public_workspace_id(ws_idx), - )); - if let Some(workspace) = self.state.workspaces.get(ws_idx) { - let tab_idx = workspace.active_tab_index(); - if let Some(tab_id) = self.public_tab_id(ws_idx, tab_idx) { - env.push(("HERDR_ACTIVE_TAB_ID".to_string(), tab_id)); - } - if let Some(pane_id) = workspace.focused_pane_id() { - if let Some(public_pane_id) = self.public_pane_id(ws_idx, pane_id) { - env.push(("HERDR_ACTIVE_PANE_ID".to_string(), public_pane_id)); - } - if let Some(pane_cwd) = workspace - .active_tab() - .and_then(|tab| tab.cwd_for_pane(pane_id)) - { - env.push(( - "HERDR_ACTIVE_PANE_CWD".to_string(), - pane_cwd.display().to_string(), - )); - if pane_cwd.is_dir() { - cwd = Some(pane_cwd); - } - } - } - } - } - (env, cwd) - } - - fn spawn_custom_command( - &self, - binding: &crate::config::CustomCommandKeybind, - ) -> std::io::Result<()> { - let mut command = Command::new("/bin/sh"); - command - .arg("-lc") - .arg(&binding.command) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()); - let (env, cwd) = self.custom_command_env(); - command.envs(env); - if let Some(cwd) = cwd { - command.current_dir(cwd); - } - command.spawn()?; - Ok(()) - } - - fn spawn_pane_command(&mut self, command: &str) -> std::io::Result<()> { - let Some(ws_idx) = self.state.active else { - return Err(std::io::Error::other("no active workspace")); - }; - let (rows, cols) = self.state.estimate_pane_size(); - let new_rows = rows.max(4); - let new_cols = cols.max(10); - let (env, _) = self.custom_command_env(); - - let ws = self - .state - .workspaces - .get_mut(ws_idx) - .ok_or_else(|| std::io::Error::other("active workspace disappeared"))?; - let tab_idx = ws.active_tab_index(); - let previous_focus = ws - .focused_pane_id() - .ok_or_else(|| std::io::Error::other("no focused pane"))?; - let previous_zoomed = ws.active_tab().map(|tab| tab.zoomed).unwrap_or(false); - let cwd = ws - .active_tab() - .and_then(|tab| tab.cwd_for_pane(previous_focus)); - let new_pane_id = ws.split_focused_command( - Direction::Horizontal, - new_rows, - new_cols, - cwd, - command, - &env, - self.state.pane_scrollback_limit_bytes, - self.state.host_terminal_theme, - )?; - ws.active_tab_mut() - .expect("workspace must have an active tab") - .layout - .focus_pane(new_pane_id); - ws.active_tab_mut() - .expect("workspace must have an active tab") - .zoomed = true; - self.overlay_panes.insert( - new_pane_id, - OverlayPaneState { - ws_idx, - tab_idx, - previous_focus, - previous_zoomed, - }, - ); - self.state.mode = Mode::Terminal; - Ok(()) - } - - pub(super) fn restore_overlay_after_exit(&mut self, overlay: OverlayPaneState) { - let Some(ws) = self.state.workspaces.get_mut(overlay.ws_idx) else { - return; - }; - if overlay.tab_idx >= ws.tabs.len() { - return; - } - - ws.active_tab = overlay.tab_idx; - let tab = &mut ws.tabs[overlay.tab_idx]; - if tab.panes.contains_key(&overlay.previous_focus) { - tab.layout.focus_pane(overlay.previous_focus); - } - tab.zoomed = overlay.previous_zoomed; - - if self.state.active == Some(overlay.ws_idx) { - self.state.mode = Mode::Terminal; - } - } -} |
