feat: allow the spawned child processes to suspend (#556)

This commit is contained in:
三咲雅 · Misaki Masa 2024-01-22 08:43:51 +08:00 committed by GitHub
parent 2b1b66e5e0
commit 701c08ce1e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 107 additions and 103 deletions

84
Cargo.lock generated
View file

@ -72,9 +72,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.7"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba"
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [
"anstyle",
"anstyle-parse",
@ -199,9 +199,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "block-buffer"
@ -281,9 +281,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.17"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80932e03c33999b9235edb8655bc9df3204adc9887c2f95b50cb1deb9fd54253"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
dependencies = [
"clap_builder",
"clap_derive",
@ -291,9 +291,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.17"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c0db58c659eef1c73e444d298c27322a1b52f6927d2ad470c0c0f96fa7b8fa"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
dependencies = [
"anstream",
"anstyle",
@ -303,9 +303,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.4.7"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb0d4825b75ff281318c393e8e1b80c4da9fb75a6b1d98547d389d6fe1f48d2"
checksum = "eaf7dcb7c21d8ca1a2482ee0f1d341f437c9a7af6ca6da359dc5e1b164e98215"
dependencies = [
"clap",
]
@ -447,7 +447,7 @@ version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"crossterm_winapi",
"futures-core",
"libc",
@ -599,9 +599,9 @@ dependencies = [
[[package]]
name = "fdeflate"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "209098dd6dfc4445aa6111f0e98653ac323eaa4dfd212c9ca3931bf9955c31bd"
checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
dependencies = [
"simd-adler32",
]
@ -830,9 +830,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
[[package]]
name = "home"
@ -1047,7 +1047,7 @@ version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"libc",
"redox_syscall",
]
@ -1063,9 +1063,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "lock_api"
@ -1232,7 +1232,7 @@ version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"filetime",
"fsevent-sys",
"inotify",
@ -1404,9 +1404,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.28"
version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
[[package]]
name = "plist"
@ -1467,9 +1467,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.76"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
@ -1507,7 +1507,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"cassowary",
"crossterm",
"indoc",
@ -1522,9 +1522,9 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.8.0"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
dependencies = [
"either",
"rayon-core",
@ -1532,9 +1532,9 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.12.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
@ -1562,9 +1562,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.10.2"
version = "1.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
dependencies = [
"aho-corasick",
"memchr",
@ -1574,9 +1574,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a"
dependencies = [
"aho-corasick",
"memchr",
@ -1613,7 +1613,7 @@ version = "0.38.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"errno",
"libc",
"linux-raw-sys",
@ -1777,9 +1777,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.12.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]]
name = "socket2"
@ -2155,9 +2155,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-bidi"
version = "0.3.14"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-ident"
@ -2263,11 +2263,12 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vergen"
version = "8.2.10"
version = "8.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a78365c3f8ca9dc5428a9f5c6349558c3f9f3eeb65e3fc00b6a981379462947"
checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525"
dependencies = [
"anyhow",
"cfg-if",
"rustversion",
"time",
]
@ -2663,7 +2664,7 @@ version = "0.2.2"
dependencies = [
"anyhow",
"base64",
"bitflags 2.4.1",
"bitflags 2.4.2",
"clipboard-win",
"crossterm",
"futures",
@ -2701,6 +2702,7 @@ dependencies = [
"signal-hook-tokio",
"syntect",
"tokio",
"tokio-util",
"tracing",
"tracing-appender",
"tracing-subscriber",
@ -2772,7 +2774,7 @@ name = "yazi-shared"
version = "0.2.2"
dependencies = [
"anyhow",
"bitflags 2.4.1",
"bitflags 2.4.2",
"crossterm",
"futures",
"libc",

View file

@ -4,7 +4,7 @@ mod key;
mod keymap;
pub use control::*;
pub use exec::*;
#[allow(unused_imports)]
pub use exec::*;
pub use key::*;
pub use keymap::*;

View file

@ -2,6 +2,7 @@ mod exec;
mod plugin;
mod props;
#[allow(unused_imports)]
pub use exec::*;
pub use plugin::*;
pub use props::*;

View file

@ -24,9 +24,10 @@ fdlimit = "^0"
futures = "^0"
mlua = { version = "^0", features = [ "lua54", "vendored" ] }
ratatui = "^0"
tokio = { version = "^1", features = [ "parking_lot" ] }
unicode-width = "^0"
syntect = { version = "^5", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
tokio = { version = "^1", features = [ "parking_lot" ] }
tokio-util = "^0"
unicode-width = "^0"
# Logging
tracing = { version = "^0", features = [ "max_level_debug", "release_max_level_warn" ] }

View file

@ -2,5 +2,6 @@ mod plugin;
mod quit;
mod render;
mod resize;
mod resume;
mod stop;
mod update_progress;

View file

@ -0,0 +1,16 @@
use yazi_shared::{event::Exec, term::Term};
use crate::app::App;
impl App {
pub(crate) fn resume(&mut self, _: &Exec) {
self.cx.manager.active_mut().preview.reset_image();
self.term = Some(Term::start().unwrap());
// While the app resumes, it's possible that the terminal size has changed.
// We need to trigger a resize, and render the UI based on the resized area.
self.resize().unwrap();
self.signals.resume();
}
}

View file

@ -1,38 +1,24 @@
use tokio::sync::oneshot;
use yazi_shared::{event::Exec, term::Term};
use yazi_shared::event::Exec;
use crate::app::App;
pub struct Opt {
state: bool,
tx: Option<oneshot::Sender<()>>,
tx: Option<oneshot::Sender<()>>,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { state: e.args.first().map_or(false, |s| s == "true"), tx: e.take_data() }
}
fn from(e: &Exec) -> Self { Self { tx: e.take_data() } }
}
impl App {
pub(crate) fn stop(&mut self, opt: impl TryInto<Opt>) {
let Ok(opt) = opt.try_into() else {
return;
};
pub(crate) fn stop(&mut self, opt: impl Into<Opt>) {
self.cx.manager.active_mut().preview.reset_image();
if opt.state {
self.signals.stop_term(true);
self.term = None;
} else {
self.term = Some(Term::start().unwrap());
self.signals.stop_term(false);
// While the app resumes, it's possible that the terminal size has changed.
// We need to trigger a resize, and render the UI based on the resized area.
self.resize().unwrap();
}
if let Some(tx) = opt.tx {
self.signals.stop();
self.term = None;
if let Some(tx) = opt.into().tx {
tx.send(()).ok();
}
}

View file

@ -86,6 +86,7 @@ impl<'a> Executor<'a> {
on!(plugin_do);
on!(update_progress);
on!(stop);
on!(resume);
}
fn manager(&mut self, exec: &Exec) {

View file

@ -1,42 +1,38 @@
use anyhow::Result;
use crossterm::event::{Event as CrosstermEvent, EventStream, KeyEvent, KeyEventKind};
use futures::StreamExt;
use tokio::{select, sync::{mpsc::{self, UnboundedReceiver, UnboundedSender}, oneshot}, task::JoinHandle};
use tokio::{select, sync::mpsc, task::JoinHandle};
use tokio_util::sync::CancellationToken;
use yazi_shared::event::Event;
pub(super) struct Signals {
tx: UnboundedSender<Event>,
pub(super) rx: UnboundedReceiver<Event>,
term_stop_tx: Option<oneshot::Sender<()>>,
term_stop_rx: Option<oneshot::Receiver<()>>,
tx: mpsc::UnboundedSender<Event>,
pub rx: mpsc::UnboundedReceiver<Event>,
ct: CancellationToken,
}
impl Signals {
pub(super) fn start() -> Result<Self> {
let (tx, rx) = mpsc::unbounded_channel();
let (term_tx, term_rx) = oneshot::channel();
let mut signals =
Self { tx: tx.clone(), rx, term_stop_tx: Some(term_tx), term_stop_rx: Some(term_rx) };
let ct = CancellationToken::new();
let mut signals = Self { tx: tx.clone(), rx, ct };
Event::init(tx);
signals.spawn_system_task()?;
signals.spawn_crossterm_task();
Event::init(tx);
Ok(signals)
}
pub(super) fn stop_term(&mut self, state: bool) {
if state == self.term_stop_tx.is_none() {
return;
pub(super) fn stop(&mut self) {
if !self.ct.is_cancelled() {
self.ct.cancel();
}
}
if let Some(tx) = self.term_stop_tx.take() {
tx.send(()).ok();
} else {
let (tx, rx) = oneshot::channel();
(self.term_stop_tx, self.term_stop_rx) = (Some(tx), Some(rx));
pub(super) fn resume(&mut self) {
if self.ct.is_cancelled() {
self.ct = CancellationToken::new();
self.spawn_crossterm_task();
}
}
@ -47,9 +43,8 @@ impl Signals {
#[cfg(unix)]
fn spawn_system_task(&self) -> Result<JoinHandle<()>> {
use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGTERM};
use yazi_scheduler::Scheduler;
use yazi_scheduler::{Scheduler, BLOCKER};
let tx = self.tx.clone();
let mut signals = signal_hook_tokio::Signals::new([
// Terminating signals
SIGHUP, SIGTERM, SIGQUIT, SIGINT, //
@ -57,8 +52,13 @@ impl Signals {
SIGCONT,
])?;
let tx = self.tx.clone();
Ok(tokio::spawn(async move {
while let Some(signal) = signals.next().await {
if BLOCKER.try_acquire().is_err() {
continue;
}
match signal {
SIGHUP | SIGTERM | SIGQUIT | SIGINT => {
if tx.send(Event::Quit(Default::default())).is_err() {
@ -73,15 +73,13 @@ impl Signals {
}
fn spawn_crossterm_task(&mut self) -> JoinHandle<()> {
let tx = self.tx.clone();
let mut stop_rx = self.term_stop_rx.take().unwrap();
let mut reader = EventStream::new();
let (tx, ct) = (self.tx.clone(), self.ct.clone());
tokio::spawn(async move {
let mut reader = EventStream::new();
loop {
select! {
_ = &mut stop_rx => break,
_ = ct.cancelled() => break,
Some(Ok(event)) = reader.next() => {
let event = match event {
// We need to check key event kind;

View file

@ -7,7 +7,7 @@ use super::Status;
pub struct Child {
inner: tokio::process::Child,
stdin: Option<ChildStdin>,
_stdin: Option<ChildStdin>,
stdout: Option<BufReader<ChildStdout>>,
stderr: Option<BufReader<ChildStderr>>,
}
@ -17,7 +17,7 @@ impl Child {
let stdin = inner.stdin.take();
let stdout = inner.stdout.take().map(BufReader::new);
let stderr = inner.stderr.take().map(BufReader::new);
Self { inner, stdin, stdout, stderr }
Self { inner, _stdin: stdin, stdout, stderr }
}
}

View file

@ -7,7 +7,7 @@ impl Utils {
ya.set(
"plugin_retrieve",
lua.create_async_function(
|_, (name, calls, args): (String, usize, Variadic<Value>)| async move { Ok(()) },
|_, (_name, _calls, _args): (String, usize, Variadic<Value>)| async move { Ok(()) },
)?,
)?;

View file

@ -164,15 +164,12 @@ impl Scheduler {
pub async fn app_stop() {
let (tx, rx) = oneshot::channel::<()>();
emit!(Call(Exec::call("stop", vec!["true".to_string()]).with_data(Some(tx)).vec(), Layer::App));
emit!(Call(Exec::call("stop", vec![]).with_data(tx).vec(), Layer::App));
rx.await.ok();
}
pub fn app_resume() {
emit!(Call(
Exec::call("stop", vec!["false".to_string()]).with_data(None::<oneshot::Sender<()>>).vec(),
Layer::App
));
emit!(Call(Exec::call("resume", vec![]).vec(), Layer::App));
}
pub fn file_cut(&self, from: Url, mut to: Url, force: bool) {

View file

@ -1,12 +1,12 @@
use std::ffi::OsString;
use crossterm::event::KeyEvent;
use tokio::sync::{mpsc::UnboundedSender, oneshot};
use tokio::sync::{mpsc, oneshot};
use super::Exec;
use crate::{term::Term, Layer, RoCell};
static TX: RoCell<UnboundedSender<Event>> = RoCell::new();
static TX: RoCell<mpsc::UnboundedSender<Event>> = RoCell::new();
#[derive(Debug)]
pub enum Event {
@ -26,11 +26,12 @@ pub struct EventQuit {
impl Event {
#[inline]
pub fn init(tx: UnboundedSender<Event>) { TX.init(tx); }
pub fn init(tx: mpsc::UnboundedSender<Event>) { TX.init(tx); }
#[inline]
pub fn emit(self) { TX.send(self).ok(); }
#[inline]
pub async fn wait<T>(self, rx: oneshot::Receiver<T>) -> T {
TX.send(self).ok();
rx.await.unwrap_or_else(|_| Term::goodbye(|| false))