diff --git a/Cargo.lock b/Cargo.lock index 6e341b84..f6b4eef7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4747,6 +4747,7 @@ name = "yazi-binding" version = "25.9.15" dependencies = [ "ansi-to-tui", + "futures", "hashbrown 0.16.1", "mlua", "paste", @@ -5087,6 +5088,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", + "yazi-binding", "yazi-config", "yazi-dds", "yazi-fs", diff --git a/yazi-actor/src/mgr/bulk_rename.rs b/yazi-actor/src/mgr/bulk_rename.rs index c8308417..9c853bd9 100644 --- a/yazi-actor/src/mgr/bulk_rename.rs +++ b/yazi-actor/src/mgr/bulk_rename.rs @@ -5,6 +5,7 @@ use crossterm::{execute, style::Print}; use hashbrown::HashMap; use scopeguard::defer; use tokio::io::AsyncWriteExt; +use yazi_binding::Permit; use yazi_config::{YAZI, opener::OpenerRule}; use yazi_dds::Pubsub; use yazi_fs::{File, FilesOp, Splatter, max_common_root, path::skip_url, provider::{FileBuilder, Provider, local::{Gate, Local}}}; @@ -65,8 +66,7 @@ impl Actor for BulkRename { ) .await; - let _permit = HIDER.acquire().await.unwrap(); - defer!(AppProxy::resume()); + let _permit = Permit::new(HIDER.acquire().await.unwrap(), AppProxy::resume()); AppProxy::stop().await; let new: Vec<_> = Local::regular(&tmp) diff --git a/yazi-actor/src/tasks/inspect.rs b/yazi-actor/src/tasks/inspect.rs index f3bd889d..dc78acd5 100644 --- a/yazi-actor/src/tasks/inspect.rs +++ b/yazi-actor/src/tasks/inspect.rs @@ -4,6 +4,7 @@ use anyhow::Result; use crossterm::{execute, terminal::{disable_raw_mode, enable_raw_mode}}; use scopeguard::defer; use tokio::{io::{AsyncReadExt, stdin}, select, sync::mpsc, time}; +use yazi_binding::Permit; use yazi_macro::succ; use yazi_parser::VoidOpt; use yazi_proxy::{AppProxy, HIDER}; @@ -26,7 +27,7 @@ impl Actor for Inspect { }; tokio::spawn(async move { - let _permit = HIDER.acquire().await.unwrap(); + let _permit = Permit::new(HIDER.acquire().await.unwrap(), AppProxy::resume()); let (tx, mut rx) = mpsc::unbounded_channel(); let buffered = { @@ -37,9 +38,7 @@ impl Actor for Inspect { task.logs.clone() }; - defer!(AppProxy::resume()); AppProxy::stop().await; - terminal_clear(TTY.writer()).ok(); TTY.writer().write_all(buffered.as_bytes()).ok(); TTY.writer().flush().ok(); diff --git a/yazi-binding/Cargo.toml b/yazi-binding/Cargo.toml index cd8077cd..622720c2 100644 --- a/yazi-binding/Cargo.toml +++ b/yazi-binding/Cargo.toml @@ -24,6 +24,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.9.15" } # External dependencies ansi-to-tui = { workspace = true } +futures = { workspace = true } hashbrown = { workspace = true } mlua = { workspace = true } paste = { workspace = true } diff --git a/yazi-binding/src/permit.rs b/yazi-binding/src/permit.rs index 2d16037f..19acf379 100644 --- a/yazi-binding/src/permit.rs +++ b/yazi-binding/src/permit.rs @@ -1,42 +1,51 @@ use std::{mem, ops::Deref}; +use futures::{FutureExt, future::BoxFuture}; use mlua::{UserData, prelude::LuaUserDataMethods}; use tokio::sync::SemaphorePermit; -pub type PermitRef = mlua::UserDataRef>; +pub type PermitRef = mlua::UserDataRef; -pub struct Permit { +pub struct Permit { inner: Option>, - destruct: Option, + destruct: Option>, } -impl Deref for Permit { +impl Deref for Permit { type Target = Option>; fn deref(&self) -> &Self::Target { &self.inner } } -impl Permit { - pub fn new(inner: SemaphorePermit<'static>, f: F) -> Self { - Self { inner: Some(inner), destruct: Some(f) } +impl Permit { + pub fn new(inner: SemaphorePermit<'static>, f: F) -> Self + where + F: Future + 'static + Send, + { + Self { inner: Some(inner), destruct: Some(f.boxed()) } } - fn dropping(&mut self) { - if let Some(f) = self.destruct.take() { - f(); - } - if let Some(p) = self.inner.take() { - mem::drop(p); + fn dropping(&mut self) -> impl Future + 'static { + let inner = self.inner.take(); + let destruct = self.destruct.take(); + + async move { + if let Some(f) = destruct { + f.await; + } + if let Some(p) = inner { + mem::drop(p); + } } } } -impl Drop for Permit { - fn drop(&mut self) { self.dropping(); } +impl Drop for Permit { + fn drop(&mut self) { tokio::spawn(self.dropping()); } } -impl UserData for Permit { +impl UserData for Permit { fn add_methods>(methods: &mut M) { - methods.add_method_mut("drop", |_, me, ()| Ok(me.dropping())); + methods.add_async_method_mut("drop", |_, mut me, ()| async move { Ok(me.dropping().await) }); } } diff --git a/yazi-fm/src/signals.rs b/yazi-fm/src/signals.rs index 350a0c66..78a0f505 100644 --- a/yazi-fm/src/signals.rs +++ b/yazi-fm/src/signals.rs @@ -44,7 +44,7 @@ impl Signals { } }); } - SIGCONT if HIDER.try_acquire().is_ok() => AppProxy::resume(), + SIGCONT if HIDER.try_acquire().is_ok() => _ = tokio::spawn(AppProxy::resume()), _ => {} } true diff --git a/yazi-plugin/src/elements/elements.rs b/yazi-plugin/src/elements/elements.rs index 4fd14a1e..08466c5a 100644 --- a/yazi-plugin/src/elements/elements.rs +++ b/yazi-plugin/src/elements/elements.rs @@ -48,14 +48,14 @@ pub(super) fn hide(lua: &Lua) -> mlua::Result { return Err("Cannot call `ui.hide()` during app initialization".into_lua_err()); } - if lua.named_registry_value::>("HIDE_PERMIT").is_ok_and(|h| h.is_some()) { + if lua.named_registry_value::("HIDE_PERMIT").is_ok_and(|h| h.is_some()) { return Err("Cannot hide while already hidden".into_lua_err()); } let permit = HIDER.acquire().await.unwrap(); AppProxy::stop().await; - lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume as fn()))?; + lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume()))?; lua.named_registry_value::("HIDE_PERMIT") })?; diff --git a/yazi-plugin/src/utils/app.rs b/yazi-plugin/src/utils/app.rs index 3e5acc77..ec48ebbd 100644 --- a/yazi-plugin/src/utils/app.rs +++ b/yazi-plugin/src/utils/app.rs @@ -35,14 +35,14 @@ impl Utils { lua.create_async_function(|lua, ()| async move { deprecate!(lua, "`ya.hide()` is deprecated, use `ui.hide()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939"); - if lua.named_registry_value::>("HIDE_PERMIT").is_ok_and(|h| h.is_some()) { + if lua.named_registry_value::("HIDE_PERMIT").is_ok_and(|h| h.is_some()) { return Err("Cannot hide while already hidden".into_lua_err()); } let permit = HIDER.acquire().await.unwrap(); AppProxy::stop().await; - lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume as fn()))?; + lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume()))?; lua.named_registry_value::("HIDE_PERMIT") }) } diff --git a/yazi-proxy/src/app.rs b/yazi-proxy/src/app.rs index de62de15..7a15807a 100644 --- a/yazi-proxy/src/app.rs +++ b/yazi-proxy/src/app.rs @@ -13,8 +13,10 @@ impl AppProxy { rx.await.ok(); } - pub fn resume() { - emit!(Call(relay!(app:resume))); + pub async fn resume() { + let (tx, rx) = oneshot::channel::<()>(); + emit!(Call(relay!(app:resume).with_any("tx", tx))); + rx.await.ok(); } pub fn notify(opt: NotifyOpt) { diff --git a/yazi-scheduler/Cargo.toml b/yazi-scheduler/Cargo.toml index fda89e5e..3bf38372 100644 --- a/yazi-scheduler/Cargo.toml +++ b/yazi-scheduler/Cargo.toml @@ -12,15 +12,16 @@ repository = "https://github.com/sxyazi/yazi" workspace = true [dependencies] -yazi-config = { path = "../yazi-config", version = "25.9.15" } -yazi-dds = { path = "../yazi-dds", version = "25.9.15" } -yazi-fs = { path = "../yazi-fs", version = "25.9.15" } -yazi-macro = { path = "../yazi-macro", version = "25.9.15" } -yazi-parser = { path = "../yazi-parser", version = "25.9.15" } -yazi-plugin = { path = "../yazi-plugin", version = "25.9.15" } -yazi-proxy = { path = "../yazi-proxy", version = "25.9.15" } -yazi-shared = { path = "../yazi-shared", version = "25.9.15" } -yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" } +yazi-binding = { path = "../yazi-binding", version = "25.9.15" } +yazi-config = { path = "../yazi-config", version = "25.9.15" } +yazi-dds = { path = "../yazi-dds", version = "25.9.15" } +yazi-fs = { path = "../yazi-fs", version = "25.9.15" } +yazi-macro = { path = "../yazi-macro", version = "25.9.15" } +yazi-parser = { path = "../yazi-parser", version = "25.9.15" } +yazi-plugin = { path = "../yazi-plugin", version = "25.9.15" } +yazi-proxy = { path = "../yazi-proxy", version = "25.9.15" } +yazi-shared = { path = "../yazi-shared", version = "25.9.15" } +yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" } # External dependencies anyhow = { workspace = true } diff --git a/yazi-scheduler/src/process/process.rs b/yazi-scheduler/src/process/process.rs index a9fd59d3..2262bf7b 100644 --- a/yazi-scheduler/src/process/process.rs +++ b/yazi-scheduler/src/process/process.rs @@ -1,6 +1,6 @@ use anyhow::{Result, anyhow}; -use scopeguard::defer; use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::mpsc}; +use yazi_binding::Permit; use yazi_proxy::{AppProxy, HIDER}; use super::{ProcessInBg, ProcessInBlock, ProcessInOrphan, ShellOpt}; @@ -14,8 +14,7 @@ impl Process { pub(crate) fn new(ops: &mpsc::UnboundedSender) -> Self { Self { ops: ops.into() } } pub(crate) async fn block(&self, task: ProcessInBlock) -> Result<(), ProcessOutBlock> { - let _permit = HIDER.acquire().await.unwrap(); - defer!(AppProxy::resume()); + let _permit = Permit::new(HIDER.acquire().await.unwrap(), AppProxy::resume()); AppProxy::stop().await; let (id, cmd) = (task.id, task.cmd.clone());