diff --git a/CHANGELOG.md b/CHANGELOG.md index a206b782..bffe11a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * fix: better command detection when serializing layouts for resurrection (https://github.com/zellij-org/zellij/pull/4287) * fix: slow startup on very large caches (https://github.com/zellij-org/zellij/pull/4292) * fix: don't show popups in the welcome screen (https://github.com/zellij-org/zellij/pull/4294) +* fix: reap processes when using an external clipboard tool (https://github.com/zellij-org/zellij/pull/4298) ## [0.42.2] - 2025-04-15 * refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082) diff --git a/zellij-server/src/tab/copy_command.rs b/zellij-server/src/tab/copy_command.rs index f0a592ef..eead0bd7 100644 --- a/zellij-server/src/tab/copy_command.rs +++ b/zellij-server/src/tab/copy_command.rs @@ -18,17 +18,44 @@ impl CopyCommand { } } pub fn set(&self, value: String) -> Result<()> { - let process = Command::new(self.command.clone()) + let mut process = Command::new(self.command.clone()) .args(self.args.clone()) .stdin(Stdio::piped()) .spawn() .with_context(|| format!("couldn't spawn {}", self.command))?; process .stdin + .take() .context("could not get stdin")? .write_all(value.as_bytes()) .with_context(|| format!("couldn't write to {} stdin", self.command))?; + // reap process with a 1 second timeout + std::thread::spawn(move || { + let timeout = std::time::Duration::from_secs(1); + let start = std::time::Instant::now(); + + loop { + match process.try_wait() { + Ok(Some(_)) => { + return; // Process finished normally + }, + Ok(None) => { + if start.elapsed() > timeout { + let _ = process.kill(); + log::error!("Copy operation times out after 1 second"); + return; + } + std::thread::sleep(std::time::Duration::from_millis(50)); + }, + Err(e) => { + log::error!("Clipboard failure: {}", e); + return; + }, + } + } + }); + Ok(()) } }