summaryrefslogtreecommitdiff
path: root/src/app/runtime.rs
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-07-13 17:25:52 +0300
committerGitHub <noreply@github.com>2026-07-13 17:25:52 +0300
commit75ed6abc6258f09af5d4fc995a5004c1abf14fc2 (patch)
tree7dd561becfc189f2dbe6f153d0c870ac913351ae /src/app/runtime.rs
parent6e85ff07f188186edcec8ac0e8263f899c7f1f26 (diff)
fix: reap detached custom command children (#1384)
* fix: reap detached custom command children refs #1360 * test: harden child cleanup and sidebar metrics refs #1360 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Diffstat (limited to 'src/app/runtime.rs')
-rw-r--r--src/app/runtime.rs27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/app/runtime.rs b/src/app/runtime.rs
index 88081743..25275cd7 100644
--- a/src/app/runtime.rs
+++ b/src/app/runtime.rs
@@ -38,7 +38,27 @@ pub(crate) struct WorkspaceGitRefreshOutput {
pub(crate) cache_updates: Vec<(std::path::PathBuf, GitStatusCacheEntry)>,
}
+fn retain_custom_command_after_wait(
+ pid: u32,
+ result: std::io::Result<Option<std::process::ExitStatus>>,
+) -> bool {
+ match result {
+ Ok(None) => true,
+ Ok(Some(_)) => false,
+ Err(err) if err.kind() == std::io::ErrorKind::Interrupted => true,
+ Err(err) => {
+ tracing::warn!(pid, err = %err, "failed to reap detached custom command");
+ false
+ }
+ }
+}
+
impl App {
+ pub(crate) fn reap_finished_custom_commands(&mut self) {
+ self.detached_custom_command_children
+ .retain_mut(|child| retain_custom_command_after_wait(child.id(), child.try_wait()));
+ }
+
pub(crate) fn shutdown_detached_terminal_runtimes(&mut self) {
let terminal_ids = std::mem::take(&mut self.state.terminal_runtime_shutdowns);
for terminal_id in terminal_ids {
@@ -697,6 +717,13 @@ mod tests {
use crate::workspace::Workspace;
use std::path::PathBuf;
+ #[test]
+ fn interrupted_custom_command_wait_keeps_child_for_retry() {
+ let interrupted = std::io::Error::new(std::io::ErrorKind::Interrupted, "test interrupt");
+
+ assert!(retain_custom_command_after_wait(42, Err(interrupted)));
+ }
+
fn test_app_with_pane() -> (super::super::App, crate::layout::PaneId) {
let mut app = super::super::App::new(
&crate::config::Config::default(),