feat: new cx.which API to access the which component state (#3617)

This commit is contained in:
三咲雅 misaki masa 2026-01-27 01:29:14 +08:00 committed by GitHub
parent 06c665a086
commit 592e70a1c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 190 additions and 151 deletions

View file

@ -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

View file

@ -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::<Value>(&body);
runtime_mut!(LUA)?.pop();
runtime_mut!(LUA)?.critical_pop(blocking);
match result {
Ok(Value::Nil) => {

View file

@ -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<yazi_core::which::Which>,
v_cands: Option<Value>,
}
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<AnyUserData> {
Lives::scoped_userdata(Self { inner: inner.into() })
Lives::scoped_userdata(Self { inner: inner.into(), v_cands: None })
}
}
impl UserData for Which {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {}
fn add_fields<F: UserDataFields<Self>>(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));
}
}

View file

@ -87,12 +87,7 @@ impl UpdateFiles {
fn update_hovered(cx: &mut Ctx, op: FilesOp) -> Result<Data> {
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 {

View file

@ -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<Data> {
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<SparkKind> {
match cx.source() {
Source::Unknown => Some(SparkKind::IndWhichShow),
Source::Unknown => Some(SparkKind::IndWhichActivate),
_ => None,
}
}

View file

@ -1 +1 @@
yazi_macro::mod_flat!(callback show);
yazi_macro::mod_flat!(activate callback);

View file

@ -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<ChordCow> for yazi_config::keymap::ChordCow {

View file

@ -66,8 +66,8 @@ impl UserData for Gauge {
Ok(ud)
});
methods.add_function_mut("gauge_style", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.gauge_style = Style::try_from(value)?.0;
methods.add_function_mut("gauge_style", |_, (ud, style): (AnyUserData, Style)| {
ud.borrow_mut::<Self>()?.gauge_style = style.0;
Ok(ud)
});
}

View file

@ -127,20 +127,20 @@ impl UserData for Table {
Ok(ud)
});
methods.add_function_mut("style", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.style = Style::try_from(value)?.0;
methods.add_function_mut("style", |_, (ud, style): (AnyUserData, Style)| {
ud.borrow_mut::<Self>()?.style = style.0;
Ok(ud)
});
methods.add_function_mut("row_style", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.row_highlight_style = Style::try_from(value)?.0;
methods.add_function_mut("row_style", |_, (ud, style): (AnyUserData, Style)| {
ud.borrow_mut::<Self>()?.row_highlight_style = style.0;
Ok(ud)
});
methods.add_function_mut("col_style", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.column_highlight_style = Style::try_from(value)?.0;
methods.add_function_mut("col_style", |_, (ud, style): (AnyUserData, Style)| {
ud.borrow_mut::<Self>()?.column_highlight_style = style.0;
Ok(ud)
});
methods.add_function_mut("cell_style", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.cell_highlight_style = Style::try_from(value)?.0;
methods.add_function_mut("cell_style", |_, (ud, style): (AnyUserData, Style)| {
ud.borrow_mut::<Self>()?.cell_highlight_style = style.0;
Ok(ud)
});
}

View file

@ -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::<Self>()?.$($field).+ = $crate::Style::try_from(value)?.0;
$methods.add_function_mut("style", |_, (ud, style): (mlua::AnyUserData, $crate::Style)| {
ud.borrow_mut::<Self>()?.$($field).+ = style.0;
Ok(ud)
});
};

View file

@ -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<String> { self.current().map(ToOwned::to_owned) }
pub fn next_block(&mut self) -> Option<usize> {
self.frames.back_mut().map(|f| {
f.calls += 1;
f.calls - 1
})
}
pub fn get_block(&self, id: &str, calls: usize) -> Option<Function> {
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<usize> {
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
}
})
}
}

View file

@ -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<Value> {
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<Value> for Style {
type Error = mlua::Error;
impl From<yazi_config::Style> for Style {
fn from(value: yazi_config::Style) -> Self { Self(value.into()) }
}
fn try_from(value: Value) -> Result<Self, Self::Error> {
impl FromLua for Style {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(Self(match value {
Value::Nil => Default::default(),
Value::UserData(ud) => ud.borrow::<Self>()?.0,
@ -28,10 +30,6 @@ impl TryFrom<Value> for Style {
}
}
impl From<yazi_config::Style> for Style {
fn from(value: yazi_config::Style) -> Self { Self(value.into()) }
}
impl UserData for Style {
fn add_methods<M: UserDataMethods<Self>>(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::<Self>()?;
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::<Self>()?;
me.0 = me.0.patch(style.0);
Ok(ud)
})
}

View file

@ -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

View file

@ -6,9 +6,9 @@ pub struct Which {
pub times: usize,
pub cands: Vec<ChordCow>,
// 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;
}
}

View file

@ -58,6 +58,9 @@ impl Sendable {
Some(t) if t == TypeId::of::<yazi_parser::mgr::UpdateYankedIter>() => {
Data::Any(Box::new(ud.take::<yazi_parser::mgr::UpdateYankedIter>()?.into_opt(lua)?))
}
Some(t) if t == TypeId::of::<yazi_binding::ChordCow>() => {
Data::Any(Box::new(ud.take::<yazi_binding::ChordCow>()?))
}
_ => 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::<yazi_fs::FilesOp>() {
lua.create_any_userdata(t.clone())?.into_lua(lua)?
} else if let Some(t) = a.as_any().downcast_ref::<yazi_parser::mgr::UpdateYankedOpt>() {
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())?
}
})
}

View file

@ -10,8 +10,8 @@ pub enum SparkKind {
RelayStash,
// quit
KeyQuit,
// which:show
IndWhichShow,
// which:activate
IndWhichActivate,
}
impl AsRef<str> for SparkKind {
@ -25,8 +25,8 @@ impl AsRef<str> 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",
}
}
}

View file

@ -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);

View file

@ -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(())
})?);

View file

@ -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,

View file

@ -340,7 +340,7 @@ impl<'a> Executor<'a> {
};
}
on!(show);
on!(activate);
on!(callback);
succ!();

View file

@ -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);
}
}

View file

@ -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()));
}

View file

@ -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<ChordCow>,
pub silent: bool,
pub times: usize,
}
impl TryFrom<CmdCow> for ShowOpt {
impl TryFrom<CmdCow> for ActivateOpt {
type Error = anyhow::Error;
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
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::<yazi_binding::ChordCow>().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<Self> {
let Value::Table(t) = value else {
return Err("expected a table".into_lua_err());
};
Ok(ShowOpt {
Ok(Self {
cands: t
.raw_get::<Table>("cands")?
.sequence_values::<yazi_binding::ChordCow>()
@ -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<Value> {
lua

View file

@ -1 +1 @@
yazi_macro::mod_flat!(callback show);
yazi_macro::mod_flat!(activate callback);

View file

@ -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::<mlua::Result<_>>()?;
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))
})

View file

@ -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<Function> {
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<Function> {
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::<MultiValue>(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::<MultiValue>(args)
})
})
}
})
}
pub(super) fn r#async(lua: &Lua, isolate: bool) -> mlua::Result<Function> {
@ -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::<MultiValue>(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}"),

View file

@ -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)?,

View file

@ -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)));
}
}

View file

@ -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<TaskIn> {
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
}

View file

@ -185,6 +185,10 @@ impl Cmd {
self.args.remove(&name.into()).map(Data::into_any2)
}
pub fn take_any_iter<T: 'static>(&mut self) -> impl Iterator<Item = T> {
(0..self.len()).filter_map(|i| self.args.remove(&DataKey::from(i))?.into_any())
}
// Parse
pub fn parse_args<I>(words: I, last: Option<String>) -> Result<HashMap<DataKey, Data>>
where

View file

@ -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<dyn Iterator<Item = T> + 'a> {
match self {
Self::Owned(c) => Box::new(c.take_any_iter()),
Self::Borrowed(_) => Box::new(iter::empty()),
}
}
}