diff --git a/Cargo.lock b/Cargo.lock index 1deba84e..671c8632 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3670,6 +3670,7 @@ dependencies = [ "yazi-boot", "yazi-fs", "yazi-macro", + "yazi-parser", "yazi-shared", ] @@ -3772,7 +3773,6 @@ dependencies = [ "yazi-binding", "yazi-boot", "yazi-config", - "yazi-dds", "yazi-fs", "yazi-macro", "yazi-shared", diff --git a/yazi-actor/src/cmp/trigger.rs b/yazi-actor/src/cmp/trigger.rs index dc94b8a8..b5086a13 100644 --- a/yazi-actor/src/cmp/trigger.rs +++ b/yazi-actor/src/cmp/trigger.rs @@ -3,9 +3,10 @@ use std::{ffi::OsString, mem, path::{MAIN_SEPARATOR_STR, Path, PathBuf}}; use anyhow::Result; use tokio::fs; use yazi_fs::{CWD, expand_path}; -use yazi_macro::{act, emit, render, succ}; +use yazi_macro::{act, render, succ}; use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt}; -use yazi_shared::{event::{Cmd, Data}, natsort}; +use yazi_proxy::CmpProxy; +use yazi_shared::{event::Data, natsort}; use crate::{Actor, Ctx}; @@ -55,13 +56,7 @@ impl Actor for Trigger { cache.sort_unstable_by(|a, b| { natsort(a.name.as_encoded_bytes(), b.name.as_encoded_bytes(), false) }); - emit!(Call( - Cmd::new("cmp:show") - .with_any("cache", cache) - .with_any("cache-name", parent) - .with("word", word) - .with("ticket", ticket) - )); + CmpProxy::show(ShowOpt { cache, cache_name: parent, word: word.into(), ticket }); } Ok::<_, anyhow::Error>(()) diff --git a/yazi-actor/src/mgr/filter.rs b/yazi-actor/src/mgr/filter.rs index d3d0192c..fd112045 100644 --- a/yazi-actor/src/mgr/filter.rs +++ b/yazi-actor/src/mgr/filter.rs @@ -4,11 +4,10 @@ use anyhow::Result; use tokio::pin; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use yazi_config::popup::InputCfg; -use yazi_fs::FilterCase; -use yazi_macro::{emit, succ}; +use yazi_macro::succ; use yazi_parser::tab::FilterOpt; -use yazi_proxy::InputProxy; -use yazi_shared::{Debounce, errors::InputError, event::{Cmd, Data}}; +use yazi_proxy::{InputProxy, MgrProxy}; +use yazi_shared::{Debounce, errors::InputError, event::Data}; use crate::{Actor, Ctx}; @@ -30,12 +29,7 @@ impl Actor for Filter { let done = result.is_ok(); let (Ok(s) | Err(InputError::Typed(s))) = result else { continue }; - emit!(Call( - Cmd::args("mgr:filter_do", [s]) - .with("smart", opt.case == FilterCase::Smart) - .with("insensitive", opt.case == FilterCase::Insensitive) - .with("done", done) - )); + MgrProxy::filter_do(FilterOpt { query: s.into(), case: opt.case, done }); } }); succ!(); diff --git a/yazi-actor/src/mgr/find.rs b/yazi-actor/src/mgr/find.rs index d14566a1..735a215c 100644 --- a/yazi-actor/src/mgr/find.rs +++ b/yazi-actor/src/mgr/find.rs @@ -4,11 +4,10 @@ use anyhow::Result; use tokio::pin; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use yazi_config::popup::InputCfg; -use yazi_fs::FilterCase; -use yazi_macro::{emit, succ}; -use yazi_parser::tab::FindOpt; -use yazi_proxy::InputProxy; -use yazi_shared::{Debounce, errors::InputError, event::{Cmd, Data}}; +use yazi_macro::succ; +use yazi_parser::tab::{FindDoOpt, FindOpt}; +use yazi_proxy::{InputProxy, MgrProxy}; +use yazi_shared::{Debounce, errors::InputError, event::Data}; use crate::{Actor, Ctx}; @@ -27,12 +26,7 @@ impl Actor for Find { pin!(rx); while let Some(Ok(s)) | Some(Err(InputError::Typed(s))) = rx.next().await { - emit!(Call( - Cmd::args("mgr:find_do", [s]) - .with("previous", opt.prev) - .with("smart", opt.case == FilterCase::Smart) - .with("insensitive", opt.case == FilterCase::Insensitive) - )); + MgrProxy::find_do(FindDoOpt { query: s.into(), prev: opt.prev, case: opt.case }); } }); succ!(); diff --git a/yazi-actor/src/mgr/update_yanked.rs b/yazi-actor/src/mgr/update_yanked.rs index dd363063..d3ad773d 100644 --- a/yazi-actor/src/mgr/update_yanked.rs +++ b/yazi-actor/src/mgr/update_yanked.rs @@ -9,7 +9,7 @@ use crate::{Actor, Ctx}; pub struct UpdateYanked; impl Actor for UpdateYanked { - type Options = UpdateYankedOpt; + type Options = UpdateYankedOpt<'static>; const NAME: &'static str = "update_yanked"; @@ -18,7 +18,7 @@ impl Actor for UpdateYanked { succ!(); } - cx.mgr.yanked = Yanked::new(opt.cut, opt.urls); + cx.mgr.yanked = Yanked::new(opt.cut, opt.urls.into_owned()); succ!(render!()); } } diff --git a/yazi-binding/src/iter.rs b/yazi-binding/src/iter.rs new file mode 100644 index 00000000..29abe1f7 --- /dev/null +++ b/yazi-binding/src/iter.rs @@ -0,0 +1,68 @@ +use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, IntoLuaMulti, Lua, MetaMethod, UserData, UserDataMethods, UserDataRefMut, Value}; + +pub struct Iter, T> { + iter: I, + len: Option, + + count: usize, + cache: Vec, +} + +impl Iter +where + I: Iterator + 'static, + T: IntoLua + 'static, +{ + #[inline] + pub fn new(iter: I, len: Option) -> Self { Self { iter, len, count: 0, cache: vec![] } } +} + +impl Iter +where + I: Iterator + 'static, + T: FromLua + 'static, +{ + #[inline] + pub fn into_iter(self, lua: &Lua) -> impl Iterator> { + self + .cache + .into_iter() + .map(|cached| T::from_lua(cached, lua)) + .chain(self.iter.map(|rest| Ok(rest))) + } +} + +impl UserData for Iter +where + I: Iterator + 'static, + T: IntoLua + 'static, +{ + fn add_methods>(methods: &mut M) { + methods.add_meta_method(MetaMethod::Len, |_, me, ()| { + if let Some(len) = me.len { + Ok(len) + } else { + Err(format!("Length is unknown for {}", std::any::type_name::()).into_lua_err()) + } + }); + + methods.add_meta_function(MetaMethod::Pairs, |lua, ud: AnyUserData| { + let iter = lua.create_function(|lua, mut me: UserDataRefMut| { + if let Some(next) = me.cache.get(me.count).cloned() { + me.count += 1; + (me.count, next).into_lua_multi(lua) + } else if let Some(next) = me.iter.next() { + let value = next.into_lua(lua)?; + me.cache.push(value.clone()); + me.count += 1; + (me.count, value).into_lua_multi(lua) + } else { + ().into_lua_multi(lua) + } + })?; + + ud.borrow_mut::()?.count = 0; + Ok((iter, ud)) + }); + } +} diff --git a/yazi-binding/src/lib.rs b/yazi-binding/src/lib.rs index ecff73bc..0271786a 100644 --- a/yazi-binding/src/lib.rs +++ b/yazi-binding/src/lib.rs @@ -4,4 +4,4 @@ mod macros; yazi_macro::mod_pub!(elements); -yazi_macro::mod_flat!(cha color composer error file icon id permit runtime stage style url urn); +yazi_macro::mod_flat!(cha color composer error file icon id iter permit runtime stage style url urn utils); diff --git a/yazi-binding/src/utils.rs b/yazi-binding/src/utils.rs new file mode 100644 index 00000000..52cada49 --- /dev/null +++ b/yazi-binding/src/utils.rs @@ -0,0 +1,10 @@ +use mlua::{IntoLua, Lua, Table, Value}; + +pub fn get_metatable(lua: &Lua, value: impl IntoLua) -> mlua::Result { + let (_, mt): (Value, Table) = unsafe { + lua.exec_raw(value.into_lua(lua)?, |state| { + mlua::ffi::lua_getmetatable(state, -1); + }) + }?; + Ok(mt) +} diff --git a/yazi-core/src/tasks/tasks.rs b/yazi-core/src/tasks/tasks.rs index ff1b9023..e243a0b9 100644 --- a/yazi-core/src/tasks/tasks.rs +++ b/yazi-core/src/tasks/tasks.rs @@ -3,10 +3,9 @@ use std::{sync::Arc, time::Duration}; use parking_lot::Mutex; use tokio::{task::JoinHandle, time::sleep}; use yazi_adapter::Dimension; -use yazi_macro::emit; use yazi_parser::app::TasksProgress; +use yazi_proxy::AppProxy; use yazi_scheduler::{Ongoing, Scheduler, TaskSummary}; -use yazi_shared::event::Cmd; use super::{TASKS_BORDER, TASKS_PADDING, TASKS_PERCENT}; @@ -33,7 +32,7 @@ impl Tasks { let new = ongoing.lock().progress(); if last != new { last = new; - emit!(Call(Cmd::new("app:update_progress").with_any("progress", new))); + AppProxy::update_progress(new); } } }); diff --git a/yazi-dds/Cargo.toml b/yazi-dds/Cargo.toml index c62fb67d..11808838 100644 --- a/yazi-dds/Cargo.toml +++ b/yazi-dds/Cargo.toml @@ -17,6 +17,7 @@ yazi-binding = { path = "../yazi-binding", version = "25.6.11" } yazi-boot = { path = "../yazi-boot", version = "25.6.11" } yazi-fs = { path = "../yazi-fs", version = "25.6.11" } yazi-macro = { path = "../yazi-macro", version = "25.6.11" } +yazi-parser = { path = "../yazi-parser", version = "25.6.11" } yazi-shared = { path = "../yazi-shared", version = "25.6.11" } # External dependencies diff --git a/yazi-dds/src/body/before_quit.rs b/yazi-dds/src/body/before_quit.rs new file mode 100644 index 00000000..a1998bbf --- /dev/null +++ b/yazi-dds/src/body/before_quit.rs @@ -0,0 +1,7 @@ +use yazi_shared::Source; + +pub struct BeforeQuit { + // FIXME + // pub opts: BeforeQuitOpt, + pub source: Source, +} diff --git a/yazi-dds/src/body/body.rs b/yazi-dds/src/body/body.rs index dcb3b721..9ab81362 100644 --- a/yazi-dds/src/body/body.rs +++ b/yazi-dds/src/body/body.rs @@ -47,9 +47,9 @@ impl Body<'static> { }) } - pub fn from_lua(kind: &str, value: Value) -> mlua::Result { + pub fn from_lua(lua: &Lua, kind: &str, value: Value) -> mlua::Result { Self::validate(kind).into_lua_err()?; - BodyCustom::from_lua(kind, value) + BodyCustom::from_lua(lua, kind, value) } pub fn validate(kind: &str) -> Result<()> { diff --git a/yazi-dds/src/body/bulk.rs b/yazi-dds/src/body/bulk.rs index d15972a6..0dd77b5e 100644 --- a/yazi-dds/src/body/bulk.rs +++ b/yazi-dds/src/body/bulk.rs @@ -41,6 +41,7 @@ impl IntoLua for BodyBulk<'static> { } // --- Iterator +// TODO: use `yazi_binding::Iter` instead pub struct BodyBulkIter { pub inner: hash_map::IntoIter, Cow<'static, Url>>, } diff --git a/yazi-dds/src/body/custom.rs b/yazi-dds/src/body/custom.rs index ec19e2be..ef4cbe92 100644 --- a/yazi-dds/src/body/custom.rs +++ b/yazi-dds/src/body/custom.rs @@ -16,8 +16,8 @@ impl BodyCustom { Ok(Self { kind: kind.to_owned(), data: serde_json::from_str(data)? }.into()) } - pub fn from_lua(kind: &str, data: Value) -> mlua::Result> { - Ok(Self { kind: kind.to_owned(), data: Sendable::value_to_data(data)? }.into()) + pub fn from_lua(lua: &Lua, kind: &str, data: Value) -> mlua::Result> { + Ok(Self { kind: kind.to_owned(), data: Sendable::value_to_data(lua, data)? }.into()) } } diff --git a/yazi-dds/src/body/mod.rs b/yazi-dds/src/body/mod.rs index f19aac64..99d8f0b2 100644 --- a/yazi-dds/src/body/mod.rs +++ b/yazi-dds/src/body/mod.rs @@ -1,5 +1,5 @@ #![allow(clippy::module_inception)] yazi_macro::mod_flat!( - body bulk bye cd custom delete hey hi hover load mount r#move rename tab trash yank + before_quit body bulk bye cd custom delete hey hi hover load mount r#move rename tab trash yank ); diff --git a/yazi-dds/src/body/yank.rs b/yazi-dds/src/body/yank.rs index fb6885ad..0b072307 100644 --- a/yazi-dds/src/body/yank.rs +++ b/yazi-dds/src/body/yank.rs @@ -1,28 +1,24 @@ use std::{borrow::Cow, collections::HashSet}; -use mlua::{IntoLua, Lua, MetaMethod, UserData, Value}; +use mlua::{IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; +use yazi_parser::mgr::UpdateYankedOpt; use yazi_shared::url::Url; use super::Body; #[derive(Debug, Serialize, Deserialize)] -pub struct BodyYank<'a> { - pub cut: bool, - pub urls: Cow<'a, HashSet>, - #[serde(skip)] - dummy: bool, -} +pub struct BodyYank<'a>(UpdateYankedOpt<'a>); impl<'a> BodyYank<'a> { pub fn borrowed(cut: bool, urls: &'a HashSet) -> Body<'a> { - Self { cut, urls: Cow::Borrowed(urls), dummy: false }.into() + Self(UpdateYankedOpt { cut, urls: Cow::Borrowed(urls) }).into() } } impl BodyYank<'static> { pub fn owned(cut: bool, _: &HashSet) -> Body<'static> { - Self { cut, urls: Default::default(), dummy: true }.into() + Self(UpdateYankedOpt { cut, urls: Default::default() }).into() } } @@ -31,36 +27,5 @@ impl<'a> From> for Body<'a> { } impl IntoLua for BodyYank<'static> { - fn into_lua(self, lua: &Lua) -> mlua::Result { - if let Some(Cow::Owned(urls)) = Some(self.urls).filter(|_| !self.dummy) { - BodyYankIter { cut: self.cut, urls: urls.into_iter().collect() }.into_lua(lua) - } else { - lua.create_table()?.into_lua(lua) - } - } -} - -// --- Iterator -#[derive(Clone)] -pub struct BodyYankIter { - pub cut: bool, - pub urls: Vec, -} - -impl UserData for BodyYankIter { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("cut", |_, me| Ok(me.cut)); - } - - fn add_methods>(methods: &mut M) { - methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.urls.len())); - - methods.add_meta_method(MetaMethod::Index, |_, me, idx: usize| { - Ok(if idx > me.urls.len() || idx == 0 { - None - } else { - Some(yazi_binding::Url::new(me.urls[idx - 1].clone())) - }) - }); - } + fn into_lua(self, lua: &Lua) -> mlua::Result { self.0.into_lua(lua) } } diff --git a/yazi-dds/src/sendable.rs b/yazi-dds/src/sendable.rs index 1a7f6328..87b23cb3 100644 --- a/yazi-dds/src/sendable.rs +++ b/yazi-dds/src/sendable.rs @@ -7,7 +7,7 @@ use yazi_shared::{event::{Data, DataKey}, replace_cow}; pub struct Sendable; impl Sendable { - pub fn value_to_data(value: Value) -> mlua::Result { + pub fn value_to_data(lua: &Lua, value: Value) -> mlua::Result { Ok(match value { Value::Nil => Data::Nil, Value::Boolean(b) => Data::Boolean(b), @@ -30,7 +30,7 @@ impl Sendable { if k == DataKey::Integer(i) { i += 1; } - map.insert(k, Self::value_to_data(v)?); + map.insert(k, Self::value_to_data(lua, v)?); } if map.len() == i as usize - 1 { @@ -54,8 +54,8 @@ impl Sendable { Some(t) if t == TypeId::of::() => { Data::Any(Box::new(ud.take::()?)) } - Some(t) if t == TypeId::of::() => { - Data::Any(Box::new(ud.take::()?)) + Some(t) if t == TypeId::of::() => { + Data::Any(Box::new(ud.take::()?.into_opt(lua)?)) } _ => Err(format!("unsupported userdata included: {ud:?}").into_lua_err())?, }, @@ -83,13 +83,15 @@ impl Sendable { } Data::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?, Data::Urn(u) => yazi_binding::Urn::new(u).into_lua(lua)?, - Data::Any(a) => Value::UserData(if a.is::() { - lua.create_any_userdata(*a.downcast::().unwrap())? - } else if a.is::() { - lua.create_userdata(*a.downcast::().unwrap())? - } else { - Err("unsupported Data::Any included".into_lua_err())? - }), + Data::Any(a) => { + if a.is::() { + lua.create_any_userdata(*a.downcast::().unwrap())?.into_lua(lua)? + } else if a.is::() { + a.downcast::().unwrap().into_lua(lua)? + } else { + Err("unsupported Data::Any included".into_lua_err())? + } + } data => Self::data_to_value_ref(lua, &data)?, }) } @@ -120,28 +122,30 @@ impl Sendable { Data::Url(u) => yazi_binding::Url::new(u.clone()).into_lua(lua)?, Data::Urn(u) => yazi_binding::Urn::new(u.clone()).into_lua(lua)?, Data::Bytes(b) => Value::String(lua.create_string(b)?), - Data::Any(a) => Value::UserData(if let Some(t) = a.downcast_ref::() { - lua.create_any_userdata(t.clone())? - } else if let Some(t) = a.downcast_ref::() { - lua.create_userdata(t.clone())? - } else { - Err("unsupported Data::Any included".into_lua_err())? - }), + Data::Any(a) => { + if let Some(t) = a.downcast_ref::() { + lua.create_any_userdata(t.clone())?.into_lua(lua)? + } else if let Some(t) = a.downcast_ref::() { + t.clone().into_lua(lua)? + } else { + Err("unsupported Data::Any included".into_lua_err())? + } + } }) } - pub fn table_to_args(t: Table) -> mlua::Result> { + pub fn table_to_args(lua: &Lua, t: Table) -> mlua::Result> { let mut args = HashMap::with_capacity(t.raw_len()); for pair in t.pairs::() { let (k, v) = pair?; match k { Value::Integer(i) if i > 0 => { - args.insert(DataKey::Integer(i - 1), Self::value_to_data(v)?); + args.insert(DataKey::Integer(i - 1), Self::value_to_data(lua, v)?); } Value::String(s) => { args.insert( DataKey::String(Cow::Owned(s.to_str()?.replace('_', "-"))), - Self::value_to_data(v)?, + Self::value_to_data(lua, v)?, ); } _ => return Err("invalid key in Cmd".into_lua_err()), @@ -182,8 +186,8 @@ impl Sendable { data.into_iter().map(|d| Self::data_to_value(lua, d)).collect() } - pub fn values_to_list(values: MultiValue) -> mlua::Result> { - values.into_iter().map(Self::value_to_data).collect() + pub fn values_to_list(lua: &Lua, values: MultiValue) -> mlua::Result> { + values.into_iter().map(|v| Self::value_to_data(lua, v)).collect() } } diff --git a/yazi-fm/src/app/commands/accept_payload.rs b/yazi-fm/src/app/commands/accept_payload.rs index 36584b90..cc82f48f 100644 --- a/yazi-fm/src/app/commands/accept_payload.rs +++ b/yazi-fm/src/app/commands/accept_payload.rs @@ -1,19 +1,22 @@ -use anyhow::Result; +use anyhow::{Result, bail}; use mlua::IntoLua; use tracing::error; use yazi_binding::runtime_mut; -use yazi_dds::{LOCAL, REMOTE}; +use yazi_dds::{LOCAL, Payload, REMOTE}; use yazi_macro::succ; -use yazi_parser::app::AcceptPayload; use yazi_plugin::LUA; -use yazi_shared::event::Data; +use yazi_shared::event::{CmdCow, Data}; use crate::{app::App, lives::Lives}; impl App { - pub(crate) fn accept_payload(&mut self, opt: AcceptPayload) -> Result { - let kind = opt.payload.body.kind().to_owned(); - let lock = if opt.payload.receiver == 0 || opt.payload.receiver != opt.payload.sender { + pub(crate) fn accept_payload(&mut self, mut c: CmdCow) -> Result { + let Some(payload) = c.take_any2::("payload").transpose()? else { + bail!("'payload' is required for accept_payload"); + }; + + let kind = payload.body.kind().to_owned(); + let lock = if payload.receiver == 0 || payload.receiver != payload.sender { REMOTE.read() } else { LOCAL.read() @@ -23,7 +26,7 @@ impl App { drop(lock); succ!(Lives::scope(&self.core, || { - let body = opt.payload.body.into_lua(&LUA)?; + let body = payload.body.into_lua(&LUA)?; for (id, cb) in handlers { runtime_mut!(LUA)?.push(&id); if let Err(e) = cb.call::<()>(body.clone()) { diff --git a/yazi-fm/src/lives/iter.rs b/yazi-fm/src/lives/iter.rs deleted file mode 100644 index 845a8e30..00000000 --- a/yazi-fm/src/lives/iter.rs +++ /dev/null @@ -1,27 +0,0 @@ -use mlua::{AnyUserData, UserData}; - -use super::Lives; - -pub(super) struct Iter, T> { - inner: I, - count: usize, -} - -impl + 'static, T: 'static> Iter { - #[inline] - pub(super) fn make(inner: I) -> mlua::Result { - Lives::scoped_userdata(Self { inner, count: 0 }) - } -} - -impl, T> Iterator for Iter { - type Item = (usize, T); - - fn next(&mut self) -> Option { - let next = self.inner.next()?; - self.count += 1; - Some((self.count, next)) - } -} - -impl, T> UserData for Iter {} diff --git a/yazi-fm/src/lives/mod.rs b/yazi-fm/src/lives/mod.rs index b14c0faf..aed480e1 100644 --- a/yazi-fm/src/lives/mod.rs +++ b/yazi-fm/src/lives/mod.rs @@ -1,3 +1,3 @@ #![allow(clippy::module_inception)] -yazi_macro::mod_flat!(core file files filter finder folder iter lives mode preference preview ptr selected tab tabs tasks yanked); +yazi_macro::mod_flat!(core file files filter finder folder lives mode preference preview ptr selected tab tabs tasks yanked); diff --git a/yazi-fm/src/lives/selected.rs b/yazi-fm/src/lives/selected.rs index 3276569d..dcab02b3 100644 --- a/yazi-fm/src/lives/selected.rs +++ b/yazi-fm/src/lives/selected.rs @@ -1,45 +1,20 @@ -use std::ops::Deref; +use indexmap::IndexMap; +use mlua::AnyUserData; -use indexmap::{IndexMap, map::Keys}; -use mlua::{AnyUserData, IntoLuaMulti, MetaMethod, UserData, UserDataMethods, UserDataRefMut}; -use yazi_binding::Url; - -use super::{Iter, Lives, PtrCell}; +use super::Lives; +use crate::lives::PtrCell; #[derive(Clone, Copy)] -pub(super) struct Selected { - inner: PtrCell>, -} - -impl Deref for Selected { - type Target = IndexMap; - - fn deref(&self) -> &Self::Target { &self.inner } -} +pub(super) struct Selected; impl Selected { #[inline] pub(super) fn make(inner: &IndexMap) -> mlua::Result { - Lives::scoped_userdata(Self { inner: inner.into() }) - } -} - -impl UserData for Selected { - fn add_methods>(methods: &mut M) { - methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len())); - - methods.add_meta_method(MetaMethod::Pairs, |lua, me, ()| { - let iter = lua.create_function( - |lua, mut iter: UserDataRefMut, _>>| { - if let Some(next) = iter.next() { - (next.0, Url::new(next.1.clone())).into_lua_multi(lua) - } else { - ().into_lua_multi(lua) - } - }, - )?; - - Ok((iter, Iter::make(me.inner.as_static().keys()))) - }); + let inner = PtrCell::from(inner); + + Lives::scoped_userdata(yazi_binding::Iter::new( + inner.as_static().keys().cloned().map(yazi_binding::Url::new), + Some(inner.len()), + )) } } diff --git a/yazi-fm/src/lives/yanked.rs b/yazi-fm/src/lives/yanked.rs index cdacb7c8..d7dd120c 100644 --- a/yazi-fm/src/lives/yanked.rs +++ b/yazi-fm/src/lives/yanked.rs @@ -1,12 +1,13 @@ -use std::{collections::hash_set, ops::Deref}; +use std::ops::Deref; -use mlua::{AnyUserData, IntoLuaMulti, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRefMut}; -use yazi_binding::Url; +use mlua::{AnyUserData, MetaMethod, MultiValue, ObjectLike, UserData, UserDataFields, UserDataMethods}; +use yazi_binding::{Iter, get_metatable}; -use super::{Iter, Lives, PtrCell}; +use super::{Lives, PtrCell}; pub(super) struct Yanked { inner: PtrCell, + iter: AnyUserData, } impl Deref for Yanked { @@ -18,7 +19,15 @@ impl Deref for Yanked { impl Yanked { #[inline] pub(super) fn make(inner: &yazi_core::mgr::Yanked) -> mlua::Result { - Lives::scoped_userdata(Self { inner: inner.into() }) + let inner = PtrCell::from(inner); + + Lives::scoped_userdata(Self { + inner, + iter: Lives::scoped_userdata(Iter::new( + inner.as_static().iter().cloned().map(yazi_binding::Url::new), + Some(inner.len()), + ))?, + }) } } @@ -30,18 +39,9 @@ impl UserData for Yanked { fn add_methods>(methods: &mut M) { methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len())); - methods.add_meta_method(MetaMethod::Pairs, |lua, me, ()| { - let iter = lua.create_function( - |lua, mut iter: UserDataRefMut, _>>| { - if let Some(next) = iter.next() { - (next.0, Url::new(next.1.clone())).into_lua_multi(lua) - } else { - ().into_lua_multi(lua) - } - }, - )?; - - Ok((iter, Iter::make(me.inner.as_static().iter()))) + methods.add_meta_function(MetaMethod::Pairs, |lua, ud: AnyUserData| { + let me = ud.borrow::()?; + get_metatable(lua, &me.iter)?.call_function::(MetaMethod::Pairs.name(), ud) }); } } diff --git a/yazi-fs/src/filter.rs b/yazi-fs/src/filter.rs index b0a55cf1..71acc30b 100644 --- a/yazi-fs/src/filter.rs +++ b/yazi-fs/src/filter.rs @@ -41,7 +41,7 @@ impl Display for Filter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.raw) } } -#[derive(Default, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub enum FilterCase { Smart, #[default] diff --git a/yazi-parser/Cargo.toml b/yazi-parser/Cargo.toml index 985c2c7c..cb246dc5 100644 --- a/yazi-parser/Cargo.toml +++ b/yazi-parser/Cargo.toml @@ -12,7 +12,6 @@ repository = "https://github.com/sxyazi/yazi" yazi-binding = { path = "../yazi-binding", version = "25.6.11" } yazi-boot = { path = "../yazi-boot", version = "25.6.11" } yazi-config = { path = "../yazi-config", version = "25.6.11" } -yazi-dds = { path = "../yazi-dds", version = "25.6.11" } yazi-fs = { path = "../yazi-fs", version = "25.6.11" } yazi-macro = { path = "../yazi-macro", version = "25.6.11" } yazi-shared = { path = "../yazi-shared", version = "25.6.11" } diff --git a/yazi-parser/src/app/accept_payload.rs b/yazi-parser/src/app/accept_payload.rs deleted file mode 100644 index b25dfafc..00000000 --- a/yazi-parser/src/app/accept_payload.rs +++ /dev/null @@ -1,19 +0,0 @@ -use anyhow::bail; -use yazi_dds::Payload; -use yazi_shared::event::CmdCow; - -pub struct AcceptPayload { - pub payload: Payload<'static>, -} - -impl TryFrom for AcceptPayload { - type Error = anyhow::Error; - - fn try_from(mut c: CmdCow) -> Result { - let Some(payload) = c.take_any("payload") else { - bail!("Invalid 'payload' in AcceptPayload"); - }; - - Ok(Self { payload }) - } -} diff --git a/yazi-parser/src/app/mod.rs b/yazi-parser/src/app/mod.rs index d4c47930..66ed1206 100644 --- a/yazi-parser/src/app/mod.rs +++ b/yazi-parser/src/app/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(accept_payload deprecate mouse notify plugin stop update_progress); +yazi_macro::mod_flat!(deprecate mouse notify plugin stop update_progress); diff --git a/yazi-parser/src/cmp/show.rs b/yazi-parser/src/cmp/show.rs index 2dba7352..57da8865 100644 --- a/yazi-parser/src/cmp/show.rs +++ b/yazi-parser/src/cmp/show.rs @@ -1,6 +1,6 @@ use std::{ffi::OsString, path::{MAIN_SEPARATOR_STR, PathBuf}}; -use yazi_shared::{Id, SStr, event::{Cmd, CmdCow}}; +use yazi_shared::{Id, SStr, event::CmdCow}; #[derive(Default)] pub struct ShowOpt { @@ -10,21 +10,23 @@ pub struct ShowOpt { pub ticket: Id, } -impl From for ShowOpt { - fn from(mut c: CmdCow) -> Self { - Self { +impl TryFrom for ShowOpt { + type Error = anyhow::Error; + + fn try_from(mut c: CmdCow) -> Result { + if let Some(opt) = c.take_any2("opt") { + return opt; + } + + Ok(Self { cache: c.take_any("cache").unwrap_or_default(), cache_name: c.take_any("cache-name").unwrap_or_default(), word: c.take_str("word").unwrap_or_default(), ticket: c.id("ticket").unwrap_or_default(), - } + }) } } -impl From for ShowOpt { - fn from(c: Cmd) -> Self { Self::from(CmdCow::from(c)) } -} - // --- Item #[derive(Debug, Clone)] pub struct CmpItem { diff --git a/yazi-parser/src/mgr/quit.rs b/yazi-parser/src/mgr/quit.rs index 9dcad59c..4aeebe6d 100644 --- a/yazi-parser/src/mgr/quit.rs +++ b/yazi-parser/src/mgr/quit.rs @@ -1,6 +1,8 @@ +use mlua::{IntoLua, Lua, LuaSerdeExt, Value}; +use serde::{Deserialize, Serialize}; use yazi_shared::event::{CmdCow, Data, EventQuit}; -#[derive(Default)] +#[derive(Default, Serialize, Deserialize)] pub struct QuitOpt { pub code: i32, pub no_cwd_file: bool, @@ -20,3 +22,7 @@ impl From for EventQuit { EventQuit { code: value.code, no_cwd_file: value.no_cwd_file, ..Default::default() } } } + +impl IntoLua for QuitOpt { + fn into_lua(self, lua: &Lua) -> mlua::Result { lua.to_value(&self) } +} diff --git a/yazi-parser/src/mgr/update_yanked.rs b/yazi-parser/src/mgr/update_yanked.rs index 12088c9c..463840bf 100644 --- a/yazi-parser/src/mgr/update_yanked.rs +++ b/yazi-parser/src/mgr/update_yanked.rs @@ -1,23 +1,76 @@ -use std::collections::HashSet; +use std::{borrow::Cow, collections::HashSet}; use anyhow::bail; +use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, MultiValue, ObjectLike, UserData, UserDataFields, UserDataMethods, Value}; +use serde::{Deserialize, Serialize}; +use yazi_binding::get_metatable; use yazi_shared::{event::CmdCow, url::Url}; -#[derive(Default)] -pub struct UpdateYankedOpt { +type Iter = yazi_binding::Iter< + std::iter::Map, fn(Url) -> yazi_binding::Url>, + yazi_binding::Url, +>; + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct UpdateYankedOpt<'a> { pub cut: bool, - pub urls: HashSet, + pub urls: Cow<'a, HashSet>, } -impl TryFrom for UpdateYankedOpt { +impl TryFrom for UpdateYankedOpt<'_> { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { - // TODO: remove `BodyYankIter` - if let Some(iter) = c.take_any::("urls") { - Ok(Self { urls: iter.urls.into_iter().collect(), cut: iter.cut }) + if let Some(opt) = c.take_any2("opt") { + opt } else { - bail!("Invalid 'urls' argument in UpdateYankedOpt"); + bail!("'opt' is required for UpdateYankedOpt"); } } } + +impl IntoLua for UpdateYankedOpt<'static> { + fn into_lua(self, lua: &Lua) -> mlua::Result { + let len = self.urls.len(); + let iter = Iter::new(self.urls.into_owned().into_iter().map(yazi_binding::Url::new), Some(len)); + UpdateYankedIter { cut: self.cut, len, inner: lua.create_userdata(iter)? }.into_lua(lua) + } +} + +// --- Iter +pub struct UpdateYankedIter { + cut: bool, + len: usize, + inner: AnyUserData, +} + +impl UpdateYankedIter { + pub fn into_opt(self, lua: &Lua) -> mlua::Result> { + Ok(UpdateYankedOpt { + cut: self.cut, + urls: Cow::Owned( + self + .inner + .take::()? + .into_iter(lua) + .map(|result| result.map(Into::into)) + .collect::>()?, + ), + }) + } +} + +impl UserData for UpdateYankedIter { + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("cut", |_, me| Ok(me.cut)); + } + + fn add_methods>(methods: &mut M) { + methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len)); + + methods.add_meta_function(MetaMethod::Pairs, |lua, ud: AnyUserData| { + let me = ud.borrow::()?; + get_metatable(lua, &me.inner)?.call_function::(MetaMethod::Pairs.name(), ud) + }); + } +} diff --git a/yazi-parser/src/tab/filter.rs b/yazi-parser/src/tab/filter.rs index cf01f68c..cd9e3f8e 100644 --- a/yazi-parser/src/tab/filter.rs +++ b/yazi-parser/src/tab/filter.rs @@ -8,12 +8,18 @@ pub struct FilterOpt { pub done: bool, } -impl From for FilterOpt { - fn from(mut c: CmdCow) -> Self { - Self { +impl TryFrom for FilterOpt { + type Error = anyhow::Error; + + fn try_from(mut c: CmdCow) -> Result { + if let Some(opt) = c.take_any2("opt") { + return opt; + } + + Ok(Self { query: c.take_first_str().unwrap_or_default(), case: FilterCase::from(&*c), done: c.bool("done"), - } + }) } } diff --git a/yazi-parser/src/tab/filter_do.rs b/yazi-parser/src/tab/filter_do.rs deleted file mode 100644 index 2c77dd07..00000000 --- a/yazi-parser/src/tab/filter_do.rs +++ /dev/null @@ -1,21 +0,0 @@ -use anyhow::bail; -use yazi_fs::FilterCase; -use yazi_shared::{SStr, event::CmdCow}; - -pub struct FindDoOpt { - pub query: SStr, - pub prev: bool, - pub case: FilterCase, -} - -impl TryFrom for FindDoOpt { - type Error = anyhow::Error; - - fn try_from(mut c: CmdCow) -> Result { - let Some(query) = c.take_first_str() else { - bail!("'query' is required for FindOpt"); - }; - - Ok(Self { query, prev: c.bool("previous"), case: FilterCase::from(&*c) }) - } -} diff --git a/yazi-parser/src/tab/find_do.rs b/yazi-parser/src/tab/find_do.rs index 8b137891..0cbc9828 100644 --- a/yazi-parser/src/tab/find_do.rs +++ b/yazi-parser/src/tab/find_do.rs @@ -1 +1,25 @@ +use anyhow::bail; +use yazi_fs::FilterCase; +use yazi_shared::{SStr, event::CmdCow}; +pub struct FindDoOpt { + pub query: SStr, + pub prev: bool, + pub case: FilterCase, +} + +impl TryFrom for FindDoOpt { + type Error = anyhow::Error; + + fn try_from(mut c: CmdCow) -> Result { + if let Some(opt) = c.take_any2("opt") { + return opt; + } + + let Some(query) = c.take_first_str() else { + bail!("'query' is required for FindDoOpt"); + }; + + Ok(Self { query, prev: c.bool("previous"), case: FilterCase::from(&*c) }) + } +} diff --git a/yazi-parser/src/tab/mod.rs b/yazi-parser/src/tab/mod.rs index ecf696d3..cec1d11b 100644 --- a/yazi-parser/src/tab/mod.rs +++ b/yazi-parser/src/tab/mod.rs @@ -5,7 +5,6 @@ yazi_macro::mod_flat!( enter escape filter - filter_do find find_arrow find_do diff --git a/yazi-parser/src/tab/update_peeked.rs b/yazi-parser/src/tab/update_peeked.rs index eb495f7d..d60a5801 100644 --- a/yazi-parser/src/tab/update_peeked.rs +++ b/yazi-parser/src/tab/update_peeked.rs @@ -11,6 +11,10 @@ impl TryFrom for UpdatePeekedOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { + if let Some(opt) = c.take_any2("opt") { + return opt; + } + let Some(lock) = c.take_any("lock") else { bail!("Invalid 'lock' argument in UpdatePeekedOpt"); }; diff --git a/yazi-parser/src/tab/update_spotted.rs b/yazi-parser/src/tab/update_spotted.rs index 205b3103..f0c1838f 100644 --- a/yazi-parser/src/tab/update_spotted.rs +++ b/yazi-parser/src/tab/update_spotted.rs @@ -11,6 +11,10 @@ impl TryFrom for UpdateSpottedOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { + if let Some(opt) = c.take_any2("opt") { + return opt; + } + let Some(lock) = c.take_any("lock") else { bail!("Invalid 'lock' argument in UpdateSpottedOpt"); }; diff --git a/yazi-parser/src/which/show.rs b/yazi-parser/src/which/show.rs index ec7fa392..d8755e19 100644 --- a/yazi-parser/src/which/show.rs +++ b/yazi-parser/src/which/show.rs @@ -10,6 +10,10 @@ impl TryFrom for ShowOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { + if let Some(opt) = c.take_any2("opt") { + return opt; + } + Ok(Self { cands: c.take_any("candidates").unwrap_or_default(), silent: c.bool("silent") }) } } diff --git a/yazi-plugin/preset/plugins/session.lua b/yazi-plugin/preset/plugins/session.lua index 6da3ca7f..6d4e5b4d 100644 --- a/yazi-plugin/preset/plugins/session.lua +++ b/yazi-plugin/preset/plugins/session.lua @@ -1,6 +1,6 @@ local function setup(_, opts) if opts.sync_yanked then - ps.sub_remote("@yank", function(body) ya.emit("update_yanked", { cut = body.cut, urls = body }) end) + ps.sub_remote("@yank", function(opt) ya.emit("update_yanked", { opt = opt }) end) end end diff --git a/yazi-plugin/src/pubsub/pubsub.rs b/yazi-plugin/src/pubsub/pubsub.rs index 750765e2..52e20b09 100644 --- a/yazi-plugin/src/pubsub/pubsub.rs +++ b/yazi-plugin/src/pubsub/pubsub.rs @@ -6,14 +6,15 @@ pub struct Pubsub; impl Pubsub { pub(super) fn r#pub(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (kind, value): (mlua::String, Value)| { - yazi_dds::Pubsub::r#pub(Body::from_lua(&kind.to_str()?, value)?).into_lua_err() + lua.create_function(|lua, (kind, value): (mlua::String, Value)| { + yazi_dds::Pubsub::r#pub(Body::from_lua(lua, &kind.to_str()?, value)?).into_lua_err() }) } pub(super) fn pub_to(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (receiver, kind, value): (Id, mlua::String, Value)| { - yazi_dds::Pubsub::pub_to(*receiver, Body::from_lua(&kind.to_str()?, value)?).into_lua_err() + lua.create_function(|lua, (receiver, kind, value): (Id, mlua::String, Value)| { + yazi_dds::Pubsub::pub_to(*receiver, Body::from_lua(lua, &kind.to_str()?, value)?) + .into_lua_err() }) } diff --git a/yazi-plugin/src/utils/call.rs b/yazi-plugin/src/utils/call.rs index 564cc253..c9636184 100644 --- a/yazi-plugin/src/utils/call.rs +++ b/yazi-plugin/src/utils/call.rs @@ -17,18 +17,18 @@ impl Utils { } pub(super) fn emit(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (name, args): (String, Table)| { + lua.create_function(|lua, (name, args): (String, Table)| { let mut cmd = Cmd::new_or(name, Layer::Mgr)?; - cmd.args = Sendable::table_to_args(args)?; + cmd.args = Sendable::table_to_args(lua, args)?; Ok(emit!(Call(cmd))) }) } pub(super) fn mgr_emit(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (name, args): (String, Table)| { + lua.create_function(|lua, (name, args): (String, Table)| { emit!(Call(Cmd { name: name.into(), - args: Sendable::table_to_args(args)?, + args: Sendable::table_to_args(lua, args)?, layer: Layer::Mgr, })); Ok(()) diff --git a/yazi-plugin/src/utils/layer.rs b/yazi-plugin/src/utils/layer.rs index a2abc27a..579dcd8d 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -5,8 +5,8 @@ use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; use yazi_binding::{deprecate, elements::{Line, Pos, Text}}; use yazi_config::{keymap::{Chord, Key}, popup::{ConfirmCfg, InputCfg}}; -use yazi_macro::emit; -use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy}; +use yazi_parser::which::ShowOpt; +use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy}; use yazi_shared::{Debounce, event::Cmd}; use super::Utils; @@ -29,11 +29,7 @@ impl Utils { } drop(tx); - emit!(Call( - Cmd::new("which:show") - .with_any("candidates", cands) - .with("silent", t.raw_get::("silent").unwrap_or_default()) - )); + WhichProxy::show(ShowOpt { cands, silent: t.raw_get("silent").unwrap_or_default() }); Ok(rx.recv().await.map(|idx| idx + 1)) }) diff --git a/yazi-plugin/src/utils/preview.rs b/yazi-plugin/src/utils/preview.rs index 55a95a61..df78a65f 100644 --- a/yazi-plugin/src/utils/preview.rs +++ b/yazi-plugin/src/utils/preview.rs @@ -1,9 +1,9 @@ use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value}; use yazi_binding::{Error, elements::{Area, Renderable, Text}}; use yazi_config::YAZI; -use yazi_macro::emit; -use yazi_parser::tab::PreviewLock; -use yazi_shared::{errors::PeekError, event::Cmd}; +use yazi_parser::tab::{PreviewLock, UpdatePeekedOpt}; +use yazi_proxy::MgrProxy; +use yazi_shared::errors::PeekError; use super::Utils; use crate::external::Highlighter; @@ -29,7 +29,7 @@ impl Utils { scroll: Default::default(), })]; - emit!(Call(Cmd::new("mgr:update_peeked").with_any("lock", lock))); + MgrProxy::update_peeked(UpdatePeekedOpt { lock }); ().into_lua_multi(&lua) }) } @@ -56,7 +56,7 @@ impl Utils { _ => Err("preview widget must be a renderable element or a table of them".into_lua_err())?, }; - emit!(Call(Cmd::new("mgr:update_peeked").with_any("lock", lock))); + MgrProxy::update_peeked(UpdatePeekedOpt { lock }); Ok(()) }) } diff --git a/yazi-plugin/src/utils/spot.rs b/yazi-plugin/src/utils/spot.rs index 743573eb..d2c16281 100644 --- a/yazi-plugin/src/utils/spot.rs +++ b/yazi-plugin/src/utils/spot.rs @@ -1,9 +1,8 @@ use mlua::{AnyUserData, Function, Lua, Table}; use yazi_binding::elements::{Edge, Renderable}; use yazi_config::THEME; -use yazi_macro::emit; -use yazi_parser::tab::SpotLock; -use yazi_shared::event::Cmd; +use yazi_parser::tab::{SpotLock, UpdateSpottedOpt}; +use yazi_proxy::MgrProxy; use super::Utils; @@ -32,7 +31,7 @@ impl Utils { }), Renderable::Table(Box::new(table)), ]; - emit!(Call(Cmd::new("mgr:update_spotted").with_any("lock", lock))); + MgrProxy::update_spotted(UpdateSpottedOpt { lock }); Ok(()) }) @@ -43,7 +42,7 @@ impl Utils { let mut lock = SpotLock::try_from(t)?; lock.data = widgets.into_iter().map(Renderable::try_from).collect::>()?; - emit!(Call(Cmd::new("mgr:update_spotted").with_any("lock", lock))); + MgrProxy::update_spotted(UpdateSpottedOpt { lock }); Ok(()) }) } diff --git a/yazi-plugin/src/utils/sync.rs b/yazi-plugin/src/utils/sync.rs index 5f1ee3eb..445e5187 100644 --- a/yazi-plugin/src/utils/sync.rs +++ b/yazi-plugin/src/utils/sync.rs @@ -22,7 +22,7 @@ impl Utils { let Some(cur) = runtime!(lua)?.current_owned() else { return Err("block spawned by `ya.sync()` must be called in a plugin").into_lua_err(); }; - Sendable::list_to_values(&lua, Self::retrieve(cur, block, args).await?) + Sendable::list_to_values(&lua, Self::retrieve(&lua, cur, block, args).await?) }) }) } else { @@ -79,8 +79,13 @@ impl Utils { lua.create_async_function(|_lua, _futs: MultiValue| async move { Ok(()) }) } - async fn retrieve(id: String, calls: usize, args: MultiValue) -> mlua::Result> { - let args = Sendable::values_to_list(args)?; + async fn retrieve( + lua: &Lua, + id: String, + calls: usize, + args: MultiValue, + ) -> mlua::Result> { + let args = Sendable::values_to_list(lua, args)?; let (tx, rx) = oneshot::channel::>(); let callback: PluginCallback = { @@ -95,7 +100,7 @@ impl Utils { .chain(args.into_iter().map(|d| Sendable::data_to_value(lua, d))) .collect::>()?; - let values = Sendable::values_to_list(block.call(args)?)?; + let values = Sendable::values_to_list(lua, block.call(args)?)?; tx.send(values).map_err(|_| "send failed".into_lua_err()) }) }; diff --git a/yazi-proxy/src/app.rs b/yazi-proxy/src/app.rs index f0a518eb..0a0c7987 100644 --- a/yazi-proxy/src/app.rs +++ b/yazi-proxy/src/app.rs @@ -2,7 +2,7 @@ use std::time::Duration; use tokio::sync::oneshot; use yazi_macro::emit; -use yazi_parser::app::{NotifyLevel, NotifyOpt, PluginOpt}; +use yazi_parser::app::{NotifyLevel, NotifyOpt, PluginOpt, TasksProgress}; use yazi_shared::event::Cmd; pub struct AppProxy; @@ -51,4 +51,8 @@ impl AppProxy { pub fn plugin_do(opt: PluginOpt) { emit!(Call(Cmd::new("app:plugin_do").with_any("opt", opt))); } + + pub fn update_progress(progress: TasksProgress) { + emit!(Call(Cmd::new("app:update_progress").with_any("progress", progress))); + } } diff --git a/yazi-proxy/src/cmp.rs b/yazi-proxy/src/cmp.rs index ca7c5108..3ca2ba6d 100644 --- a/yazi-proxy/src/cmp.rs +++ b/yazi-proxy/src/cmp.rs @@ -1,9 +1,14 @@ use yazi_macro::emit; +use yazi_parser::cmp::ShowOpt; use yazi_shared::{Id, event::Cmd}; pub struct CmpProxy; impl CmpProxy { + pub fn show(opt: ShowOpt) { + emit!(Call(Cmd::new("cmp:show").with_any("opt", opt))); + } + pub fn trigger(word: &str, ticket: Id) { emit!(Call(Cmd::args("cmp:trigger", [word]).with("ticket", ticket))); } diff --git a/yazi-proxy/src/lib.rs b/yazi-proxy/src/lib.rs index fc84b981..50f0d758 100644 --- a/yazi-proxy/src/lib.rs +++ b/yazi-proxy/src/lib.rs @@ -1,5 +1,5 @@ mod macros; -yazi_macro::mod_flat!(app cmp confirm input mgr pick semaphore tasks); +yazi_macro::mod_flat!(app cmp confirm input mgr pick semaphore tasks which); pub fn init() { crate::init_semaphore(); } diff --git a/yazi-proxy/src/mgr.rs b/yazi-proxy/src/mgr.rs index 36f1b18e..c163dcbf 100644 --- a/yazi-proxy/src/mgr.rs +++ b/yazi-proxy/src/mgr.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use yazi_macro::emit; -use yazi_parser::mgr::{OpenDoOpt, SearchOpt}; +use yazi_parser::{mgr::{OpenDoOpt, SearchOpt}, tab::{FilterOpt, FindDoOpt, UpdatePeekedOpt, UpdateSpottedOpt}}; use yazi_shared::{SStr, event::Cmd, url::Url}; pub struct MgrProxy; @@ -29,6 +29,14 @@ impl MgrProxy { )); } + pub fn find_do(opt: FindDoOpt) { + emit!(Call(Cmd::new("mgr:find_do").with_any("opt", opt))); + } + + pub fn filter_do(opt: FilterOpt) { + emit!(Call(Cmd::new("mgr:filter_do").with_any("opt", opt))); + } + pub fn search_do(opt: SearchOpt) { emit!(Call( // TODO: use second positional argument instead of `args` parameter @@ -38,6 +46,14 @@ impl MgrProxy { )); } + pub fn update_peeked(opt: UpdatePeekedOpt) { + emit!(Call(Cmd::new("mgr:update_peeked").with_any("opt", opt))); + } + + pub fn update_spotted(opt: UpdateSpottedOpt) { + emit!(Call(Cmd::new("mgr:update_spotted").with_any("opt", opt))); + } + pub fn update_tasks(url: &Url) { emit!(Call(Cmd::new("mgr:update_tasks").with_any("urls", vec![url.clone()]))); } diff --git a/yazi-proxy/src/which.rs b/yazi-proxy/src/which.rs new file mode 100644 index 00000000..cf5c89a1 --- /dev/null +++ b/yazi-proxy/src/which.rs @@ -0,0 +1,11 @@ +use yazi_macro::emit; +use yazi_parser::which::ShowOpt; +use yazi_shared::event::Cmd; + +pub struct WhichProxy; + +impl WhichProxy { + pub fn show(opt: ShowOpt) { + emit!(Call(Cmd::new("which:show").with_any("opt", opt))); + } +} diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index 1ad89a37..30262acd 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -85,20 +85,16 @@ impl Cmd { pub fn get(&self, name: impl Into) -> Option<&Data> { self.args.get(&name.into()) } #[inline] - pub fn str(&self, name: impl Into) -> Option<&str> { - self.get(name).and_then(Data::as_str) - } + pub fn str(&self, name: impl Into) -> Option<&str> { self.get(name)?.as_str() } #[inline] pub fn bool(&self, name: impl Into) -> bool { self.maybe_bool(name).unwrap_or(false) } #[inline] - pub fn maybe_bool(&self, name: impl Into) -> Option { - self.get(name).and_then(Data::as_bool) - } + pub fn maybe_bool(&self, name: impl Into) -> Option { self.get(name)?.as_bool() } #[inline] - pub fn id(&self, name: impl Into) -> Option { self.get(name).and_then(Data::as_id) } + pub fn id(&self, name: impl Into) -> Option { self.get(name)?.as_id() } #[inline] pub fn first(&self) -> Option<&Data> { self.get(0) } @@ -136,7 +132,12 @@ impl Cmd { #[inline] pub fn take_any(&mut self, name: impl Into) -> Option { - self.args.remove(&name.into()).and_then(|d| d.into_any()) + self.args.remove(&name.into())?.into_any() + } + + #[inline] + pub fn take_any2(&mut self, name: impl Into) -> Option> { + self.args.remove(&name.into()).map(Data::into_any2) } // Parse diff --git a/yazi-shared/src/event/cow.rs b/yazi-shared/src/event/cow.rs index 6222524d..be2b2b1a 100644 --- a/yazi-shared/src/event/cow.rs +++ b/yazi-shared/src/event/cow.rs @@ -1,5 +1,7 @@ use std::{borrow::Cow, ops::Deref}; +use anyhow::Result; + use super::{Cmd, Data, DataKey}; use crate::{SStr, url::Url}; @@ -75,4 +77,12 @@ impl CmdCow { Self::Borrowed(_) => None, } } + + #[inline] + pub fn take_any2(&mut self, name: impl Into) -> Option> { + match self { + Self::Owned(c) => c.take_any2(name), + Self::Borrowed(_) => None, + } + } } diff --git a/yazi-shared/src/event/data.rs b/yazi-shared/src/event/data.rs index 4aec859e..7aefce8d 100644 --- a/yazi-shared/src/event/data.rs +++ b/yazi-shared/src/event/data.rs @@ -1,5 +1,6 @@ use std::{any::Any, borrow::Cow, collections::HashMap}; +use anyhow::{Result, bail}; use ordered_float::OrderedFloat; use serde::{Deserialize, Serialize, de}; @@ -80,6 +81,18 @@ impl Data { } } + // FIXME: find a better name + #[inline] + pub fn into_any2(self) -> Result { + if let Self::Any(b) = self + && let Ok(t) = b.downcast::() + { + Ok(*t) + } else { + bail!("Failed to downcast Data into {}", std::any::type_name::()) + } + } + #[inline] pub fn to_url(&self) -> Option { match self {