From 2174f3d53649585556f82b732cf1b016be65f16a Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 23 Sep 2023 22:19:35 +0800 Subject: [PATCH 1/2] feat: new `orphan` option for opener rules, to keep the process running even when Yazi exited --- config/src/open/opener.rs | 5 ++++- core/src/external/shell.rs | 9 +++++---- core/src/manager/manager.rs | 7 ++++--- core/src/manager/tab.rs | 2 +- core/src/tasks/scheduler.rs | 1 + core/src/tasks/workers/process.rs | 11 ++++++++--- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/config/src/open/opener.rs b/config/src/open/opener.rs index b813c04de..e20a5fe5e 100644 --- a/config/src/open/opener.rs +++ b/config/src/open/opener.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Deserializer}; pub struct Opener { pub exec: String, pub block: bool, + pub orphan: bool, pub display_name: String, pub spread: bool, } @@ -18,6 +19,8 @@ impl<'de> Deserialize<'de> for Opener { pub exec: String, #[serde(default)] pub block: bool, + #[serde(default)] + pub orphan: bool, pub display_name: Option, } @@ -32,6 +35,6 @@ impl<'de> Deserialize<'de> for Opener { .unwrap_or_else(|| shadow.exec.split_whitespace().next().unwrap().to_string()); let spread = shadow.exec.contains("$*") || shadow.exec.contains("$@"); - Ok(Self { exec: shadow.exec, block: shadow.block, display_name, spread }) + Ok(Self { exec: shadow.exec, block: shadow.block, orphan: shadow.orphan, display_name, spread }) } } diff --git a/core/src/external/shell.rs b/core/src/external/shell.rs index c3621ae54..a0eaea75c 100644 --- a/core/src/external/shell.rs +++ b/core/src/external/shell.rs @@ -4,9 +4,10 @@ use anyhow::Result; use tokio::process::{Child, Command}; pub struct ShellOpt { - pub cmd: OsString, - pub args: Vec, - pub piped: bool, + pub cmd: OsString, + pub args: Vec, + pub piped: bool, + pub orphan: bool, } pub fn shell(opt: ShellOpt) -> Result { @@ -21,7 +22,7 @@ pub fn shell(opt: ShellOpt) -> Result { .stdin(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .stdout(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .stderr(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) - .kill_on_drop(true) + .kill_on_drop(!opt.orphan) .spawn()?, ) } diff --git a/core/src/manager/manager.rs b/core/src/manager/manager.rs index e8e8f8819..373c418e5 100644 --- a/core/src/manager/manager.rs +++ b/core/src/manager/manager.rs @@ -259,9 +259,10 @@ impl Manager { emit!(Stop(true)).await; let mut child = external::shell(ShellOpt { - cmd: (*opener.exec).into(), - args: vec![tmp.to_owned().into()], - piped: false, + cmd: (*opener.exec).into(), + args: vec![tmp.to_owned().into()], + piped: false, + orphan: false, })?; child.wait().await?; diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index 4e5971c15..0b124a64e 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -379,7 +379,7 @@ impl Tab { emit!(Open( selected, - Some(Opener { exec, block, display_name: Default::default(), spread: true }) + Some(Opener { exec, block, orphan: false, display_name: Default::default(), spread: true }) )); }); diff --git a/core/src/tasks/scheduler.rs b/core/src/tasks/scheduler.rs index 7e319a2e9..d48f10025 100644 --- a/core/src/tasks/scheduler.rs +++ b/core/src/tasks/scheduler.rs @@ -310,6 +310,7 @@ impl Scheduler { cmd: opener.exec.into(), args, block: opener.block, + orphan: opener.orphan, cancel: cancel_tx, }) .await diff --git a/core/src/tasks/workers/process.rs b/core/src/tasks/workers/process.rs index 3fade197a..b5f04ac67 100644 --- a/core/src/tasks/workers/process.rs +++ b/core/src/tasks/workers/process.rs @@ -16,6 +16,7 @@ pub(crate) struct ProcessOpOpen { pub cmd: OsString, pub args: Vec, pub block: bool, + pub orphan: bool, pub cancel: oneshot::Sender<()>, } @@ -29,11 +30,12 @@ impl Process { fn done(&self, id: usize) -> Result<()> { Ok(self.sch.send(TaskOp::Done(id))?) } pub(crate) async fn open(&self, mut task: ProcessOpOpen) -> Result<()> { + let opt = ShellOpt { cmd: task.cmd, args: task.args, piped: true, orphan: task.orphan }; if task.block { let _guard = BLOCKER.acquire().await.unwrap(); emit!(Stop(true)).await; - match external::shell(ShellOpt { cmd: task.cmd, args: task.args, piped: false }) { + match external::shell(ShellOpt { piped: false, ..opt }) { Ok(mut child) => { child.wait().await.ok(); } @@ -48,13 +50,16 @@ impl Process { } self.sch.send(TaskOp::New(task.id, 0))?; - let mut child = external::shell(ShellOpt { cmd: task.cmd, args: task.args, piped: true })?; + let mut child = external::shell(opt)?; let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines(); let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines(); loop { select! { - _ = task.cancel.closed() => break, + _ = task.cancel.closed() => { + child.start_kill().ok(); + break; + } Ok(Some(line)) = stdout.next_line() => { self.log(task.id, line)?; } From 5443aac767083584a8368301d198d78d16bf2b9a Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 23 Sep 2023 23:15:43 +0800 Subject: [PATCH 2/2] .. --- core/src/external/shell.rs | 7 +++++++ core/src/tasks/workers/process.rs | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/src/external/shell.rs b/core/src/external/shell.rs index a0eaea75c..2ca8f185f 100644 --- a/core/src/external/shell.rs +++ b/core/src/external/shell.rs @@ -10,6 +10,13 @@ pub struct ShellOpt { pub orphan: bool, } +impl ShellOpt { + pub fn with_piped(mut self) -> Self { + self.piped = true; + self + } +} + pub fn shell(opt: ShellOpt) -> Result { #[cfg(not(target_os = "windows"))] { diff --git a/core/src/tasks/workers/process.rs b/core/src/tasks/workers/process.rs index b5f04ac67..6bed7b44e 100644 --- a/core/src/tasks/workers/process.rs +++ b/core/src/tasks/workers/process.rs @@ -1,4 +1,4 @@ -use std::ffi::OsString; +use std::{ffi::OsString, mem}; use anyhow::Result; use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::{mpsc, oneshot}}; @@ -20,6 +20,17 @@ pub(crate) struct ProcessOpOpen { pub cancel: oneshot::Sender<()>, } +impl From<&mut ProcessOpOpen> for ShellOpt { + fn from(value: &mut ProcessOpOpen) -> Self { + Self { + cmd: mem::take(&mut value.cmd), + args: mem::take(&mut value.args), + piped: false, + orphan: value.orphan, + } + } +} + impl Process { pub(crate) fn new(sch: mpsc::UnboundedSender) -> Self { Self { sch } } @@ -30,12 +41,11 @@ impl Process { fn done(&self, id: usize) -> Result<()> { Ok(self.sch.send(TaskOp::Done(id))?) } pub(crate) async fn open(&self, mut task: ProcessOpOpen) -> Result<()> { - let opt = ShellOpt { cmd: task.cmd, args: task.args, piped: true, orphan: task.orphan }; if task.block { let _guard = BLOCKER.acquire().await.unwrap(); emit!(Stop(true)).await; - match external::shell(ShellOpt { piped: false, ..opt }) { + match external::shell(ShellOpt::from(&mut task)) { Ok(mut child) => { child.wait().await.ok(); } @@ -50,7 +60,7 @@ impl Process { } self.sch.send(TaskOp::New(task.id, 0))?; - let mut child = external::shell(opt)?; + let mut child = external::shell(ShellOpt::from(&mut task).with_piped())?; let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines(); let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines();