From 592e70a1c9e311a1ffb12f2b4a48d5a156235a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Tue, 27 Jan 2026 01:29:14 +0800 Subject: [PATCH] feat: new `cx.which` API to access the which component state (#3617) --- CHANGELOG.md | 4 +- yazi-actor/src/core/preflight.rs | 4 +- yazi-actor/src/lives/which.rs | 17 ++++- yazi-actor/src/mgr/update_files.rs | 13 +--- yazi-actor/src/which/{show.rs => activate.rs} | 14 ++--- yazi-actor/src/which/mod.rs | 2 +- yazi-binding/src/chord_cow.rs | 2 +- yazi-binding/src/elements/gauge.rs | 4 +- yazi-binding/src/elements/table.rs | 16 ++--- yazi-binding/src/macros.rs | 4 +- yazi-binding/src/runtime.rs | 50 ++++++++------- yazi-binding/src/style.rs | 24 +++---- yazi-core/src/core.rs | 2 +- yazi-core/src/which/which.rs | 8 +-- yazi-dds/src/sendable.rs | 23 ++++--- yazi-dds/src/spark/kind.rs | 8 +-- yazi-dds/src/spark/spark.rs | 10 +-- yazi-fm/src/app/commands/accept_payload.rs | 4 +- yazi-fm/src/app/commands/plugin.rs | 4 +- yazi-fm/src/executor.rs | 2 +- yazi-fm/src/root.rs | 2 +- yazi-fm/src/router.rs | 2 +- .../src/which/{show.rs => activate.rs} | 24 ++++--- yazi-parser/src/which/mod.rs | 2 +- yazi-plugin/src/utils/layer.rs | 4 +- yazi-plugin/src/utils/sync.rs | 63 +++++++++++-------- yazi-plugin/src/utils/utils.rs | 2 +- yazi-proxy/src/which.rs | 6 +- yazi-scheduler/src/ongoing.rs | 8 +-- yazi-shared/src/event/cmd.rs | 4 ++ yazi-shared/src/event/cow.rs | 9 ++- 31 files changed, 190 insertions(+), 151 deletions(-) rename yazi-actor/src/which/{show.rs => activate.rs} (73%) rename yazi-parser/src/which/{show.rs => activate.rs} (76%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7640c944..dedac640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): ### Added -- New `ind-which-show` DDS event to change the which component behavior ([#3608]) +- New `cx.which` API to access the which component state ([#3617]) +- New `ind-which-activate` DDS event to change the which component behavior ([#3608]) ### Fixed @@ -1622,3 +1623,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3594]: https://github.com/sxyazi/yazi/pull/3594 [#3607]: https://github.com/sxyazi/yazi/pull/3607 [#3608]: https://github.com/sxyazi/yazi/pull/3608 +[#3617]: https://github.com/sxyazi/yazi/pull/3617 diff --git a/yazi-actor/src/core/preflight.rs b/yazi-actor/src/core/preflight.rs index 1c46a51c..30564ba2 100644 --- a/yazi-actor/src/core/preflight.rs +++ b/yazi-actor/src/core/preflight.rs @@ -18,9 +18,9 @@ impl Preflight { Ok(Lives::scope(cx.core, || { let mut body = opt.1.into_lua(&LUA)?; for (id, cb) in handlers { - runtime_mut!(LUA)?.push(&id); + let blocking = runtime_mut!(LUA)?.critical_push(&id, true); let result = cb.call::(&body); - runtime_mut!(LUA)?.pop(); + runtime_mut!(LUA)?.critical_pop(blocking); match result { Ok(Value::Nil) => { diff --git a/yazi-actor/src/lives/which.rs b/yazi-actor/src/lives/which.rs index ec622e0c..c4bc6cbe 100644 --- a/yazi-actor/src/lives/which.rs +++ b/yazi-actor/src/lives/which.rs @@ -1,11 +1,14 @@ use std::ops::Deref; -use mlua::{AnyUserData, UserData, UserDataFields}; +use mlua::{AnyUserData, UserData, UserDataFields, Value}; +use yazi_binding::cached_field; use super::{Lives, PtrCell}; pub(super) struct Which { inner: PtrCell, + + v_cands: Option, } impl Deref for Which { @@ -16,10 +19,18 @@ impl Deref for Which { impl Which { pub(super) fn make(inner: &yazi_core::which::Which) -> mlua::Result { - Lives::scoped_userdata(Self { inner: inner.into() }) + Lives::scoped_userdata(Self { inner: inner.into(), v_cands: None }) } } impl UserData for Which { - fn add_fields>(fields: &mut F) {} + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("times", |_, me| Ok(me.inner.times)); + cached_field!(fields, cands, |lua, me| { + lua.create_sequence_from(me.inner.cands.iter().cloned().map(yazi_binding::ChordCow)) + }); + + fields.add_field_method_get("active", |_, me| Ok(me.inner.active)); + fields.add_field_method_get("silent", |_, me| Ok(me.inner.silent)); + } } diff --git a/yazi-actor/src/mgr/update_files.rs b/yazi-actor/src/mgr/update_files.rs index 08e8d225..195bfd39 100644 --- a/yazi-actor/src/mgr/update_files.rs +++ b/yazi-actor/src/mgr/update_files.rs @@ -87,12 +87,7 @@ impl UpdateFiles { fn update_hovered(cx: &mut Ctx, op: FilesOp) -> Result { let (id, url) = (cx.tab().id, op.cwd()); - let (_, folder) = cx - .tab_mut() - .history - .raw_entry_mut() - .from_key(url) - .or_insert_with(|| (url.clone(), Folder::from(url))); + let folder = cx.tab_mut().history.entry_ref(url).or_insert_with(|| Folder::from(url)); if folder.update_pub(id, op) { act!(mgr:peek, cx, true)?; @@ -108,10 +103,8 @@ impl UpdateFiles { tab .history - .raw_entry_mut() - .from_key(op.cwd()) - .or_insert_with(|| (op.cwd().clone(), Folder::from(op.cwd()))) - .1 + .entry_ref(op.cwd()) + .or_insert_with(|| Folder::from(op.cwd())) .update_pub(tab.id, op); if leave { diff --git a/yazi-actor/src/which/show.rs b/yazi-actor/src/which/activate.rs similarity index 73% rename from yazi-actor/src/which/show.rs rename to yazi-actor/src/which/activate.rs index 0f63b691..24cdc387 100644 --- a/yazi-actor/src/which/show.rs +++ b/yazi-actor/src/which/activate.rs @@ -2,17 +2,17 @@ use anyhow::Result; use yazi_core::which::WhichSorter; use yazi_dds::spark::SparkKind; use yazi_macro::{render, succ}; -use yazi_parser::which::ShowOpt; +use yazi_parser::which::ActivateOpt; use yazi_shared::{Source, data::Data}; use crate::{Actor, Ctx}; -pub struct Show; +pub struct Activate; -impl Actor for Show { - type Options = ShowOpt; +impl Actor for Activate { + type Options = ActivateOpt; - const NAME: &str = "show"; + const NAME: &str = "activate"; fn act(cx: &mut Ctx, mut opt: Self::Options) -> Result { opt.cands.retain(|c| c.on.len() > opt.times); @@ -26,14 +26,14 @@ impl Actor for Show { which.times = opt.times; which.cands = opt.cands; - which.visible = true; + which.active = true; which.silent = opt.silent; succ!(render!()); } fn hook(cx: &Ctx, _opt: &Self::Options) -> Option { match cx.source() { - Source::Unknown => Some(SparkKind::IndWhichShow), + Source::Unknown => Some(SparkKind::IndWhichActivate), _ => None, } } diff --git a/yazi-actor/src/which/mod.rs b/yazi-actor/src/which/mod.rs index ab7eaca0..bb2bf97a 100644 --- a/yazi-actor/src/which/mod.rs +++ b/yazi-actor/src/which/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(callback show); +yazi_macro::mod_flat!(activate callback); diff --git a/yazi-binding/src/chord_cow.rs b/yazi-binding/src/chord_cow.rs index 796c9ef4..b381b93c 100644 --- a/yazi-binding/src/chord_cow.rs +++ b/yazi-binding/src/chord_cow.rs @@ -1,7 +1,7 @@ use mlua::UserData; use yazi_codegen::FromLuaOwned; -#[derive(FromLuaOwned)] +#[derive(Clone, FromLuaOwned)] pub struct ChordCow(pub yazi_config::keymap::ChordCow); impl From for yazi_config::keymap::ChordCow { diff --git a/yazi-binding/src/elements/gauge.rs b/yazi-binding/src/elements/gauge.rs index 2d1d1487..1a4283b1 100644 --- a/yazi-binding/src/elements/gauge.rs +++ b/yazi-binding/src/elements/gauge.rs @@ -66,8 +66,8 @@ impl UserData for Gauge { Ok(ud) }); - methods.add_function_mut("gauge_style", |_, (ud, value): (AnyUserData, Value)| { - ud.borrow_mut::()?.gauge_style = Style::try_from(value)?.0; + methods.add_function_mut("gauge_style", |_, (ud, style): (AnyUserData, Style)| { + ud.borrow_mut::()?.gauge_style = style.0; Ok(ud) }); } diff --git a/yazi-binding/src/elements/table.rs b/yazi-binding/src/elements/table.rs index 6ce06829..82ce5d07 100644 --- a/yazi-binding/src/elements/table.rs +++ b/yazi-binding/src/elements/table.rs @@ -127,20 +127,20 @@ impl UserData for Table { Ok(ud) }); - methods.add_function_mut("style", |_, (ud, value): (AnyUserData, Value)| { - ud.borrow_mut::()?.style = Style::try_from(value)?.0; + methods.add_function_mut("style", |_, (ud, style): (AnyUserData, Style)| { + ud.borrow_mut::()?.style = style.0; Ok(ud) }); - methods.add_function_mut("row_style", |_, (ud, value): (AnyUserData, Value)| { - ud.borrow_mut::()?.row_highlight_style = Style::try_from(value)?.0; + methods.add_function_mut("row_style", |_, (ud, style): (AnyUserData, Style)| { + ud.borrow_mut::()?.row_highlight_style = style.0; Ok(ud) }); - methods.add_function_mut("col_style", |_, (ud, value): (AnyUserData, Value)| { - ud.borrow_mut::()?.column_highlight_style = Style::try_from(value)?.0; + methods.add_function_mut("col_style", |_, (ud, style): (AnyUserData, Style)| { + ud.borrow_mut::()?.column_highlight_style = style.0; Ok(ud) }); - methods.add_function_mut("cell_style", |_, (ud, value): (AnyUserData, Value)| { - ud.borrow_mut::()?.cell_highlight_style = Style::try_from(value)?.0; + methods.add_function_mut("cell_style", |_, (ud, style): (AnyUserData, Style)| { + ud.borrow_mut::()?.cell_highlight_style = style.0; Ok(ud) }); } diff --git a/yazi-binding/src/macros.rs b/yazi-binding/src/macros.rs index 37e0a13f..e34534a0 100644 --- a/yazi-binding/src/macros.rs +++ b/yazi-binding/src/macros.rs @@ -71,8 +71,8 @@ macro_rules! impl_area_method { #[macro_export] macro_rules! impl_style_method { ($methods:ident, $($field:tt).+) => { - $methods.add_function_mut("style", |_, (ud, value): (mlua::AnyUserData, mlua::Value)| { - ud.borrow_mut::()?.$($field).+ = $crate::Style::try_from(value)?.0; + $methods.add_function_mut("style", |_, (ud, style): (mlua::AnyUserData, $crate::Style)| { + ud.borrow_mut::()?.$($field).+ = style.0; Ok(ud) }); }; diff --git a/yazi-binding/src/runtime.rs b/yazi-binding/src/runtime.rs index 3d33ff18..f9652941 100644 --- a/yazi-binding/src/runtime.rs +++ b/yazi-binding/src/runtime.rs @@ -1,6 +1,6 @@ -use std::collections::VecDeque; +use std::{collections::VecDeque, mem}; -use hashbrown::HashMap; +use hashbrown::{HashMap, hash_map::EntryRef}; use mlua::Function; #[derive(Debug)] @@ -12,8 +12,7 @@ pub struct Runtime { #[derive(Debug)] struct RuntimeFrame { - id: String, - calls: usize, + id: String, } impl Runtime { @@ -21,40 +20,45 @@ impl Runtime { pub fn new_isolate(id: &str) -> Self { Self { - frames: VecDeque::from([RuntimeFrame { id: id.to_owned(), calls: 0 }]), + frames: VecDeque::from([RuntimeFrame { id: id.to_owned() }]), blocks: <_>::default(), blocking: false, } } - pub fn push(&mut self, id: &str) { - self.frames.push_back(RuntimeFrame { id: id.to_owned(), calls: 0 }); - } + pub fn push(&mut self, id: &str) { self.frames.push_back(RuntimeFrame { id: id.to_owned() }); } pub fn pop(&mut self) { self.frames.pop_back(); } + pub fn critical_push(&mut self, id: &str, blocking: bool) -> bool { + self.push(id); + mem::replace(&mut self.blocking, blocking) + } + + pub fn critical_pop(&mut self, blocking: bool) { + self.pop(); + self.blocking = blocking; + } + pub fn current(&self) -> Option<&str> { self.frames.back().map(|f| f.id.as_str()) } pub fn current_owned(&self) -> Option { self.current().map(ToOwned::to_owned) } - pub fn next_block(&mut self) -> Option { - self.frames.back_mut().map(|f| { - f.calls += 1; - f.calls - 1 - }) - } - pub fn get_block(&self, id: &str, calls: usize) -> Option { self.blocks.get(id).and_then(|v| v.get(calls)).cloned() } - pub fn put_block(&mut self, f: &Function) -> bool { - let Some(cur) = self.frames.back() else { return false }; - if let Some(v) = self.blocks.get_mut(&cur.id) { - v.push(f.clone()); - } else { - self.blocks.insert(cur.id.clone(), vec![f.clone()]); - } - true + pub fn put_block(&mut self, f: &Function) -> Option { + let Some(cur) = self.frames.back() else { return None }; + Some(match self.blocks.entry_ref(&cur.id) { + EntryRef::Occupied(mut oe) => { + oe.get_mut().push(f.clone()); + oe.get().len() - 1 + } + EntryRef::Vacant(ve) => { + ve.insert(vec![f.clone()]); + 0 + } + }) } } diff --git a/yazi-binding/src/style.rs b/yazi-binding/src/style.rs index ddcaf181..7585ce23 100644 --- a/yazi-binding/src/style.rs +++ b/yazi-binding/src/style.rs @@ -1,4 +1,4 @@ -use mlua::{AnyUserData, ExternalError, IntoLua, Lua, LuaSerdeExt, MetaMethod, Table, UserData, UserDataMethods, Value}; +use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, MetaMethod, Table, UserData, UserDataMethods, Value}; use crate::SER_OPT; @@ -7,7 +7,7 @@ pub struct Style(pub ratatui::style::Style); impl Style { pub fn compose(lua: &Lua) -> mlua::Result { - let new = lua.create_function(|_, (_, value): (Table, Value)| Self::try_from(value))?; + let new = lua.create_function(|_, (_, style): (Table, Self)| Ok(style))?; let style = lua.create_table()?; style.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?; @@ -16,10 +16,12 @@ impl Style { } } -impl TryFrom for Style { - type Error = mlua::Error; +impl From for Style { + fn from(value: yazi_config::Style) -> Self { Self(value.into()) } +} - fn try_from(value: Value) -> Result { +impl FromLua for Style { + fn from_lua(value: Value, _: &Lua) -> mlua::Result { Ok(Self(match value { Value::Nil => Default::default(), Value::UserData(ud) => ud.borrow::()?.0, @@ -28,10 +30,6 @@ impl TryFrom for Style { } } -impl From for Style { - fn from(value: yazi_config::Style) -> Self { Self(value.into()) } -} - impl UserData for Style { fn add_methods>(methods: &mut M) { crate::impl_style_shorthands!(methods, 0); @@ -39,11 +37,9 @@ impl UserData for Style { methods .add_method("raw", |lua, me, ()| lua.to_value_with(&yazi_config::Style::from(me.0), SER_OPT)); - methods.add_function_mut("patch", |_, (ud, value): (AnyUserData, Value)| { - { - let mut me = ud.borrow_mut::()?; - me.0 = me.0.patch(Self::try_from(value)?.0); - } + methods.add_function_mut("patch", |_, (ud, style): (AnyUserData, Self)| { + let mut me = ud.borrow_mut::()?; + me.0 = me.0.patch(style.0); Ok(ud) }) } diff --git a/yazi-core/src/core.rs b/yazi-core/src/core.rs index 504d4e18..8df6f81a 100644 --- a/yazi-core/src/core.rs +++ b/yazi-core/src/core.rs @@ -46,7 +46,7 @@ impl Core { } pub fn layer(&self) -> Layer { - if self.which.visible { + if self.which.active { Layer::Which } else if self.cmp.visible { Layer::Cmp diff --git a/yazi-core/src/which/which.rs b/yazi-core/src/which/which.rs index d499f1a6..78a82328 100644 --- a/yazi-core/src/which/which.rs +++ b/yazi-core/src/which/which.rs @@ -6,9 +6,9 @@ pub struct Which { pub times: usize, pub cands: Vec, - // Visibility - pub visible: bool, - pub silent: bool, + // Active state + pub active: bool, + pub silent: bool, } impl Which { @@ -33,7 +33,7 @@ impl Which { self.times = 0; self.cands.clear(); - self.visible = false; + self.active = false; self.silent = false; } } diff --git a/yazi-dds/src/sendable.rs b/yazi-dds/src/sendable.rs index 49598cfa..0c0fdb70 100644 --- a/yazi-dds/src/sendable.rs +++ b/yazi-dds/src/sendable.rs @@ -58,6 +58,9 @@ impl Sendable { Some(t) if t == TypeId::of::() => { Data::Any(Box::new(ud.take::()?.into_opt(lua)?)) } + Some(t) if t == TypeId::of::() => { + Data::Any(Box::new(ud.take::()?)) + } _ => Err(format!("unsupported userdata included: {ud:?}").into_lua_err())?, }, Value::Error(_) => Err("error is not supported".into_lua_err())?, @@ -98,6 +101,7 @@ impl Sendable { try_cast!(|v: yazi_fs::FilesOp| lua.create_any_userdata(v)); try_cast!(|v: yazi_parser::mgr::UpdateYankedOpt| v.into_lua(lua)); + try_cast!(|v: yazi_binding::ChordCow| v.into_lua(lua)); Err("unsupported DataAny included".into_lua_err())? } data => Self::data_to_value_ref(lua, &data)?, @@ -130,14 +134,19 @@ impl Sendable { Data::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?, Data::Path(u) => yazi_binding::Path::new(u).into_lua(lua)?, Data::Bytes(b) => Value::String(lua.create_string(b)?), - Data::Any(a) => { - if let Some(t) = a.as_any().downcast_ref::() { - lua.create_any_userdata(t.clone())?.into_lua(lua)? - } else if let Some(t) = a.as_any().downcast_ref::() { - t.clone().into_lua(lua)? - } else { - Err("unsupported DataAny included".into_lua_err())? + Data::Any(b) => { + macro_rules! try_cast { + ($f:expr) => { + if let Some(v) = b.as_any().downcast_ref() { + return $f(Clone::clone(v))?.into_lua(lua); + } + }; } + + try_cast!(|v: yazi_fs::FilesOp| lua.create_any_userdata(v)); + try_cast!(|v: yazi_parser::mgr::UpdateYankedOpt| v.into_lua(lua)); + try_cast!(|v: yazi_binding::ChordCow| v.into_lua(lua)); + Err("unsupported DataAny included".into_lua_err())? } }) } diff --git a/yazi-dds/src/spark/kind.rs b/yazi-dds/src/spark/kind.rs index 1ab6c3fd..5ee1e3dc 100644 --- a/yazi-dds/src/spark/kind.rs +++ b/yazi-dds/src/spark/kind.rs @@ -10,8 +10,8 @@ pub enum SparkKind { RelayStash, // quit KeyQuit, - // which:show - IndWhichShow, + // which:activate + IndWhichActivate, } impl AsRef for SparkKind { @@ -25,8 +25,8 @@ impl AsRef for SparkKind { Self::RelayStash => "relay-stash", // quit Self::KeyQuit => "key-quit", - // which:show - Self::IndWhichShow => "ind-which-show", + // which:activate + Self::IndWhichActivate => "ind-which-activate", } } } diff --git a/yazi-dds/src/spark/spark.rs b/yazi-dds/src/spark/spark.rs index dc8d3a93..fa0b11cd 100644 --- a/yazi-dds/src/spark/spark.rs +++ b/yazi-dds/src/spark/spark.rs @@ -132,7 +132,7 @@ pub enum Spark<'a> { // Which WhichCallback(yazi_parser::which::CallbackOpt), - WhichShow(yazi_parser::which::ShowOpt), + WhichActivate(yazi_parser::which::ActivateOpt), } impl<'a> Spark<'a> { @@ -148,8 +148,8 @@ impl<'a> Spark<'a> { RelayStash => Self::Stash(<_>::from_lua(value, lua)?), // quit KeyQuit => Self::Quit(<_>::from_lua(value, lua)?), - // which:show - IndWhichShow => Self::WhichShow(<_>::from_lua(value, lua)?), + // which:activate + IndWhichActivate => Self::WhichActivate(<_>::from_lua(value, lua)?), }) } } @@ -285,7 +285,7 @@ impl<'a> IntoLua for Spark<'a> { // Which Self::WhichCallback(b) => b.into_lua(lua), - Self::WhichShow(b) => b.into_lua(lua), + Self::WhichActivate(b) => b.into_lua(lua), } } } @@ -378,4 +378,4 @@ try_from_spark!(spot::CopyOpt, spot:copy); try_from_spark!(tasks::ProcessOpenOpt, tasks:process_open); try_from_spark!(tasks::UpdateSucceedOpt, tasks:update_succeed); try_from_spark!(which::CallbackOpt, which:callback); -try_from_spark!(which::ShowOpt, which:show); +try_from_spark!(which::ActivateOpt, which:activate); diff --git a/yazi-fm/src/app/commands/accept_payload.rs b/yazi-fm/src/app/commands/accept_payload.rs index 2648869f..676782c6 100644 --- a/yazi-fm/src/app/commands/accept_payload.rs +++ b/yazi-fm/src/app/commands/accept_payload.rs @@ -29,11 +29,11 @@ impl App { succ!(Lives::scope(&self.core, || { let body = payload.body.into_lua(&LUA)?; for (id, cb) in handlers { - runtime_mut!(LUA)?.push(&id); + let blocking = runtime_mut!(LUA)?.critical_push(&id, true); if let Err(e) = cb.call::<()>(body.clone()) { error!("Failed to run `{kind}` event handler in your `{id}` plugin: {e}"); } - runtime_mut!(LUA)?.pop(); + runtime_mut!(LUA)?.critical_pop(blocking); } Ok(()) })?); diff --git a/yazi-fm/src/app/commands/plugin.rs b/yazi-fm/src/app/commands/plugin.rs index d15d45d5..a7f93356 100644 --- a/yazi-fm/src/app/commands/plugin.rs +++ b/yazi-fm/src/app/commands/plugin.rs @@ -50,8 +50,8 @@ impl App { succ!(self.core.tasks.plugin_entry(opt)); } - runtime_mut!(LUA)?.push(&opt.id); - defer! { _ = runtime_mut!(LUA).map(|mut r| r.pop()) } + let blocking = runtime_mut!(LUA)?.critical_push(&opt.id, true); + defer! { _ = runtime_mut!(LUA).map(|mut r| r.critical_pop(blocking)) } let plugin = match LOADER.load_with(&LUA, &opt.id, chunk) { Ok(t) => t, diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 684ed033..291550b9 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -340,7 +340,7 @@ impl<'a> Executor<'a> { }; } - on!(show); + on!(activate); on!(callback); succ!(); diff --git a/yazi-fm/src/root.rs b/yazi-fm/src/root.rs index 47073260..77f60683 100644 --- a/yazi-fm/src/root.rs +++ b/yazi-fm/src/root.rs @@ -65,7 +65,7 @@ impl Widget for Root<'_> { cmp::Cmp::new(self.core).render(area, buf); } - if self.core.which.visible { + if self.core.which.active { which::Which::new(self.core).render(area, buf); } } diff --git a/yazi-fm/src/router.rs b/yazi-fm/src/router.rs index df6febe0..039b913c 100644 --- a/yazi-fm/src/router.rs +++ b/yazi-fm/src/router.rs @@ -43,7 +43,7 @@ impl<'a> Router<'a> { if on.len() > 1 { let cx = &mut Ctx::active(&mut self.app.core); - act!(which:show, cx, (layer, key)).ok(); + act!(which:activate, cx, (layer, key)).ok(); } else { emit!(Seq(ChordCow::from(chord).into_seq())); } diff --git a/yazi-parser/src/which/show.rs b/yazi-parser/src/which/activate.rs similarity index 76% rename from yazi-parser/src/which/show.rs rename to yazi-parser/src/which/activate.rs index dbc847ef..f717a006 100644 --- a/yazi-parser/src/which/show.rs +++ b/yazi-parser/src/which/activate.rs @@ -1,27 +1,31 @@ -use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, Value}; use yazi_config::{KEYMAP, keymap::{ChordCow, Key}}; use yazi_shared::{Layer, event::CmdCow}; #[derive(Clone, Debug)] -pub struct ShowOpt { +pub struct ActivateOpt { pub cands: Vec, pub silent: bool, pub times: usize, } -impl TryFrom for ShowOpt { +impl TryFrom for ActivateOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { - match c.take_any2("opt") { - Some(opt) => opt, - None => bail!("missing 'opt' argument"), + if let Some(opt) = c.take_any2("opt") { + return opt; } + + Ok(Self { + cands: c.take_any_iter::().map(Into::into).collect(), + silent: c.bool("silent"), + times: c.get("times").unwrap_or(0), + }) } } -impl From<(Layer, Key)> for ShowOpt { +impl From<(Layer, Key)> for ActivateOpt { fn from((layer, key): (Layer, Key)) -> Self { Self { cands: KEYMAP @@ -36,13 +40,13 @@ impl From<(Layer, Key)> for ShowOpt { } } -impl FromLua for ShowOpt { +impl FromLua for ActivateOpt { fn from_lua(value: Value, _: &Lua) -> mlua::Result { let Value::Table(t) = value else { return Err("expected a table".into_lua_err()); }; - Ok(ShowOpt { + Ok(Self { cands: t .raw_get::("cands")? .sequence_values::() @@ -54,7 +58,7 @@ impl FromLua for ShowOpt { } } -impl IntoLua for ShowOpt { +impl IntoLua for ActivateOpt { #[rustfmt::skip] fn into_lua(self, lua: &Lua) -> mlua::Result { lua diff --git a/yazi-parser/src/which/mod.rs b/yazi-parser/src/which/mod.rs index ab7eaca0..bb2bf97a 100644 --- a/yazi-parser/src/which/mod.rs +++ b/yazi-parser/src/which/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(callback show); +yazi_macro::mod_flat!(activate callback); diff --git a/yazi-plugin/src/utils/layer.rs b/yazi-plugin/src/utils/layer.rs index 2a199643..d0f7a81d 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -6,7 +6,7 @@ use tokio_stream::wrappers::UnboundedReceiverStream; use yazi_binding::{elements::{Line, Pos, Text}, runtime}; use yazi_config::{keymap::{Chord, ChordCow, Key}, popup::{ConfirmCfg, InputCfg}}; use yazi_macro::relay; -use yazi_parser::which::ShowOpt; +use yazi_parser::which::ActivateOpt; use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy}; use yazi_shared::Debounce; @@ -37,7 +37,7 @@ impl Utils { .collect::>()?; drop(tx); - WhichProxy::show(ShowOpt { cands, times: 0, silent: t.raw_get("silent")? }); + WhichProxy::activate(ActivateOpt { cands, times: 0, silent: t.raw_get("silent")? }); Ok(rx.recv().await.map(|idx| idx + 1)) }) diff --git a/yazi-plugin/src/utils/sync.rs b/yazi-plugin/src/utils/sync.rs index 00f9f132..372d3bb0 100644 --- a/yazi-plugin/src/utils/sync.rs +++ b/yazi-plugin/src/utils/sync.rs @@ -1,3 +1,5 @@ +use std::mem; + use anyhow::Context; use futures::future::join_all; use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, MultiValue, Table, Value, Variadic}; @@ -12,39 +14,34 @@ use super::Utils; use crate::{bindings::{MpscRx, MpscTx, MpscUnboundedRx, MpscUnboundedTx, OneshotRx, OneshotTx}, loader::LOADER}; impl Utils { - pub(super) fn sync(lua: &Lua, isolate: bool) -> mlua::Result { - if isolate { - lua.create_function(|lua, ()| { - let Some(block) = runtime_mut!(lua)?.next_block() else { - return Err("`ya.sync()` must be called in a plugin").into_lua_err(); - }; + pub(super) fn sync(lua: &Lua) -> mlua::Result { + lua.create_function(|lua, f: Function| { + let Some(block) = runtime_mut!(lua)?.put_block(&f) else { + return Err("`ya.sync()` must be called in a plugin").into_lua_err(); + }; - lua.create_async_function(move |lua, args: MultiValue| async move { - let Some(cur) = runtime!(lua)?.current_owned() else { + lua.create_async_function(move |lua, mut args: MultiValue| { + let f = f.clone(); + async move { + let rt = runtime!(lua)?; + let (Some(cur), blocking) = (rt.current_owned(), rt.blocking) else { return Err("`ya.sync()` block must be used within a plugin").into_lua_err(); }; + drop(rt); - Self::retrieve(&lua, &cur, block, args) - .await - .and_then(|data| Sendable::list_to_values(&lua, data)) - .with_context(|| format!("Failed to execute sync block-{block} in `{cur}` plugin")) - .into_lua_err() - }) - }) - } else { - lua.create_function(|lua, f: Function| { - let mut rt = runtime_mut!(lua)?; - if !rt.put_block(&f) { - return Err("`ya.sync()` must be called in a plugin").into_lua_err(); + if blocking { + args.push_front(Value::Table(LOADER.try_load(&lua, &cur)?)); + f.call::(args) + } else { + Self::retrieve(&lua, &cur, block, args) + .await + .and_then(|data| Sendable::list_to_values(&lua, data)) + .with_context(|| format!("Failed to execute sync block-{block} in `{cur}` plugin")) + .into_lua_err() + } } - - let cur = rt.current_owned().unwrap(); - lua.create_function(move |lua, mut args: MultiValue| { - args.push_front(Value::Table(LOADER.try_load(lua, &cur)?)); - f.call::(args) - }) }) - } + }) } pub(super) fn r#async(lua: &Lua, isolate: bool) -> mlua::Result { @@ -55,9 +52,21 @@ impl Utils { } else { lua.create_function(|lua, (f, args): (Function, MultiValue)| { let name = runtime!(lua)?.current_owned(); + let lua = lua.clone(); Ok(Handle::AsyncFn(LOCAL_SET.spawn_local(async move { + let blocking = mem::replace(&mut runtime_mut!(lua)?.blocking, false); + if let Some(s) = &name { + runtime_mut!(lua)?.push(s); // make `current_owned` always return Some to eliminate the check + } + let result = f.call_async::(args).await; + + runtime_mut!(lua)?.blocking = blocking; + if name.is_some() { + runtime_mut!(lua)?.pop(); + } + if let Err(ref e) = result { match name { Some(s) => tracing::error!("Failed to execute async block in `{s}` plugin: {e}"), diff --git a/yazi-plugin/src/utils/utils.rs b/yazi-plugin/src/utils/utils.rs index fa246071..32936581 100644 --- a/yazi-plugin/src/utils/utils.rs +++ b/yazi-plugin/src/utils/utils.rs @@ -50,7 +50,7 @@ pub fn compose( b"spot_widgets" => Utils::spot_widgets(lua)?, // Sync - b"sync" => Utils::sync(lua, isolate)?, + b"sync" => Utils::sync(lua)?, b"async" => Utils::r#async(lua, isolate)?, b"chan" => Utils::chan(lua)?, b"join" => Utils::join(lua)?, diff --git a/yazi-proxy/src/which.rs b/yazi-proxy/src/which.rs index 843d92c2..45d4a511 100644 --- a/yazi-proxy/src/which.rs +++ b/yazi-proxy/src/which.rs @@ -1,10 +1,10 @@ use yazi_macro::{emit, relay}; -use yazi_parser::which::ShowOpt; +use yazi_parser::which::ActivateOpt; pub struct WhichProxy; impl WhichProxy { - pub fn show(opt: ShowOpt) { - emit!(Call(relay!(which:show).with_any("opt", opt))); + pub fn activate(opt: ActivateOpt) { + emit!(Call(relay!(which:activate).with_any("opt", opt))); } } diff --git a/yazi-scheduler/src/ongoing.rs b/yazi-scheduler/src/ongoing.rs index e01caec9..a2845814 100644 --- a/yazi-scheduler/src/ongoing.rs +++ b/yazi-scheduler/src/ongoing.rs @@ -1,4 +1,4 @@ -use hashbrown::{HashMap, hash_map::RawEntryMut}; +use hashbrown::{HashMap, hash_map::Entry}; use ordered_float::OrderedFloat; use yazi_config::YAZI; use yazi_parser::app::TaskSummary; @@ -24,8 +24,8 @@ impl Ongoing { } pub(super) fn cancel(&mut self, id: Id) -> Option { - match self.inner.raw_entry_mut().from_key(&id) { - RawEntryMut::Occupied(mut oe) => { + match self.inner.entry(id) { + Entry::Occupied(mut oe) => { let task = oe.get_mut(); task.done.complete(false); @@ -35,7 +35,7 @@ impl Ongoing { oe.remove(); } - RawEntryMut::Vacant(_) => {} + Entry::Vacant(_) => {} } None } diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index 37bf044f..ac13f30d 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -185,6 +185,10 @@ impl Cmd { self.args.remove(&name.into()).map(Data::into_any2) } + pub fn take_any_iter(&mut self) -> impl Iterator { + (0..self.len()).filter_map(|i| self.args.remove(&DataKey::from(i))?.into_any()) + } + // Parse pub fn parse_args(words: I, last: Option) -> Result> where diff --git a/yazi-shared/src/event/cow.rs b/yazi-shared/src/event/cow.rs index 5e510489..c9685a90 100644 --- a/yazi-shared/src/event/cow.rs +++ b/yazi-shared/src/event/cow.rs @@ -1,4 +1,4 @@ -use std::ops::Deref; +use std::{iter, ops::Deref}; use anyhow::Result; @@ -92,4 +92,11 @@ impl CmdCow { Self::Borrowed(_) => None, } } + + pub fn take_any_iter<'a, T: 'static>(&'a mut self) -> Box + 'a> { + match self { + Self::Owned(c) => Box::new(c.take_any_iter()), + Self::Borrowed(_) => Box::new(iter::empty()), + } + } }