diff --git a/yazi-config/src/keymap/control.rs b/yazi-config/src/keymap/control.rs index a236e5a0e..adbfb626d 100644 --- a/yazi-config/src/keymap/control.rs +++ b/yazi-config/src/keymap/control.rs @@ -15,9 +15,7 @@ pub struct Control { impl Control { #[inline] - pub fn to_seq(&self) -> VecDeque { - self.run.iter().map(|e| e.clone_without_data()).collect() - } + pub fn to_seq(&self) -> VecDeque { self.run.iter().map(|c| c.shallow_clone()).collect() } } impl Control { diff --git a/yazi-config/src/keymap/run.rs b/yazi-config/src/keymap/run.rs index c4bdfbeb6..65307a9c4 100644 --- a/yazi-config/src/keymap/run.rs +++ b/yazi-config/src/keymap/run.rs @@ -1,8 +1,8 @@ -use std::fmt; +use std::{fmt, mem}; use anyhow::{bail, Result}; use serde::{de::{self, Visitor}, Deserializer}; -use yazi_shared::event::Cmd; +use yazi_shared::event::{Cmd, Data}; pub(super) fn run_deserialize<'de, D>(deserializer: D) -> Result, D::Error> where @@ -10,21 +10,28 @@ where { struct RunVisitor; + #[allow(clippy::explicit_counter_loop)] fn parse(s: &str) -> Result { - let s = shell_words::split(s)?; - if s.is_empty() { - bail!("`run` cannot be empty"); - } + let mut args = shell_words::split(s)?; + let mut cmd = Cmd { name: mem::take(&mut args[0]), ..Default::default() }; + + let mut i = 0usize; + for arg in args.into_iter().skip(1) { + let Some(arg) = arg.strip_prefix("--") else { + cmd.args.insert(i.to_string(), Data::String(arg)); + i += 1; + continue; + }; + + let mut parts = arg.splitn(2, '='); + let Some(key) = parts.next().map(|s| s.to_owned()) else { + bail!("invalid argument: {arg}"); + }; - let mut cmd = Cmd { name: s[0].clone(), ..Default::default() }; - for arg in s.into_iter().skip(1) { - if arg.starts_with("--") { - let mut arg = arg.splitn(2, '='); - let key = arg.next().unwrap().trim_start_matches('-'); - let val = arg.next().unwrap_or("").to_string(); - cmd.named.insert(key.to_string(), val); + if let Some(val) = parts.next() { + cmd.args.insert(key, Data::String(val.to_owned())); } else { - cmd.args.push(arg); + cmd.args.insert(key, Data::Boolean(true)); } } Ok(cmd) diff --git a/yazi-core/src/completion/commands/arrow.rs b/yazi-core/src/completion/commands/arrow.rs index 5598be2d6..2aaca25cf 100644 --- a/yazi-core/src/completion/commands/arrow.rs +++ b/yazi-core/src/completion/commands/arrow.rs @@ -8,7 +8,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) } + Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) } } } diff --git a/yazi-core/src/completion/commands/close.rs b/yazi-core/src/completion/commands/close.rs index a884587af..c3117ba20 100644 --- a/yazi-core/src/completion/commands/close.rs +++ b/yazi-core/src/completion/commands/close.rs @@ -8,7 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { submit: c.named.contains_key("submit") } } + fn from(c: Cmd) -> Self { Self { submit: c.get_bool("submit") } } } impl Completion { diff --git a/yazi-core/src/completion/commands/show.rs b/yazi-core/src/completion/commands/show.rs index 0ba8a25df..b5b69ebd2 100644 --- a/yazi-core/src/completion/commands/show.rs +++ b/yazi-core/src/completion/commands/show.rs @@ -16,10 +16,10 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - cache: mem::take(&mut c.args), - cache_name: c.take_name("cache-name").unwrap_or_default(), - word: c.take_name("word").unwrap_or_default(), - ticket: c.take_name("ticket").and_then(|v| v.parse().ok()).unwrap_or(0), + cache: c.take_any("cache").unwrap_or_default(), + cache_name: c.take_str("cache-name").unwrap_or_default(), + word: c.take_str("word").unwrap_or_default(), + ticket: c.take_str("ticket").and_then(|v| v.parse().ok()).unwrap_or(0), } } } @@ -63,7 +63,7 @@ impl Completion { } if !opt.cache.is_empty() { - self.caches.insert(opt.cache_name.to_owned(), opt.cache.clone()); + self.caches.insert(opt.cache_name.to_owned(), opt.cache); } let Some(cache) = self.caches.get(&opt.cache_name) else { return; diff --git a/yazi-core/src/completion/commands/trigger.rs b/yazi-core/src/completion/commands/trigger.rs index d3d7054f6..7b4a5241f 100644 --- a/yazi-core/src/completion/commands/trigger.rs +++ b/yazi-core/src/completion/commands/trigger.rs @@ -19,8 +19,8 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - word: c.take_first().unwrap_or_default(), - ticket: c.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0), + word: c.take_first_str().unwrap_or_default(), + ticket: c.take_str("ticket").and_then(|s| s.parse().ok()).unwrap_or(0), } } } @@ -57,7 +57,8 @@ impl Completion { if !cache.is_empty() { emit!(Call( - Cmd::args("show", cache) + Cmd::new("show") + .with_any("cache", cache) .with("cache-name", parent) .with("word", child) .with("ticket", ticket), diff --git a/yazi-core/src/folder/filter.rs b/yazi-core/src/folder/filter.rs index 61d909e57..0c40bf896 100644 --- a/yazi-core/src/folder/filter.rs +++ b/yazi-core/src/folder/filter.rs @@ -45,7 +45,7 @@ pub enum FilterCase { impl From<&Cmd> for FilterCase { fn from(c: &Cmd) -> Self { - match (c.named.contains_key("smart"), c.named.contains_key("insensitive")) { + match (c.get_bool("smart"), c.get_bool("insensitive")) { (true, _) => Self::Smart, (_, false) => Self::Sensitive, (_, true) => Self::Insensitive, diff --git a/yazi-core/src/help/commands/arrow.rs b/yazi-core/src/help/commands/arrow.rs index 8cef1f115..bd98a1563 100644 --- a/yazi-core/src/help/commands/arrow.rs +++ b/yazi-core/src/help/commands/arrow.rs @@ -8,7 +8,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) } + Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) } } } impl From for Opt { diff --git a/yazi-core/src/input/commands/backspace.rs b/yazi-core/src/input/commands/backspace.rs index 3796771f3..5377529a4 100644 --- a/yazi-core/src/input/commands/backspace.rs +++ b/yazi-core/src/input/commands/backspace.rs @@ -7,7 +7,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { under: c.named.contains_key("under") } } + fn from(c: Cmd) -> Self { Self { under: c.get_bool("under") } } } impl From for Opt { fn from(under: bool) -> Self { Self { under } } diff --git a/yazi-core/src/input/commands/close.rs b/yazi-core/src/input/commands/close.rs index 38e6c215a..c27927b37 100644 --- a/yazi-core/src/input/commands/close.rs +++ b/yazi-core/src/input/commands/close.rs @@ -8,7 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { submit: c.named.contains_key("submit") } } + fn from(c: Cmd) -> Self { Self { submit: c.get_bool("submit") } } } impl From for Opt { fn from(submit: bool) -> Self { Self { submit } } diff --git a/yazi-core/src/input/commands/complete.rs b/yazi-core/src/input/commands/complete.rs index a14a30fc0..e22726952 100644 --- a/yazi-core/src/input/commands/complete.rs +++ b/yazi-core/src/input/commands/complete.rs @@ -18,8 +18,8 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - word: c.take_first().unwrap_or_default(), - ticket: c.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0), + word: c.take_first_str().unwrap_or_default(), + ticket: c.take_str("ticket").and_then(|s| s.parse().ok()).unwrap_or(0), } } } diff --git a/yazi-core/src/input/commands/delete.rs b/yazi-core/src/input/commands/delete.rs index 415df466f..367bd7d3c 100644 --- a/yazi-core/src/input/commands/delete.rs +++ b/yazi-core/src/input/commands/delete.rs @@ -8,9 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { - Self { cut: c.named.contains_key("cut"), insert: c.named.contains_key("insert") } - } + fn from(c: Cmd) -> Self { Self { cut: c.get_bool("cut"), insert: c.get_bool("insert") } } } impl Input { diff --git a/yazi-core/src/input/commands/forward.rs b/yazi-core/src/input/commands/forward.rs index 339c2177a..44514a899 100644 --- a/yazi-core/src/input/commands/forward.rs +++ b/yazi-core/src/input/commands/forward.rs @@ -7,7 +7,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { end_of_word: c.named.contains_key("end-of-word") } } + fn from(c: Cmd) -> Self { Self { end_of_word: c.get_bool("end-of-word") } } } impl Input { diff --git a/yazi-core/src/input/commands/insert.rs b/yazi-core/src/input/commands/insert.rs index c5289b653..28d860e89 100644 --- a/yazi-core/src/input/commands/insert.rs +++ b/yazi-core/src/input/commands/insert.rs @@ -7,7 +7,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { append: c.named.contains_key("append") } } + fn from(c: Cmd) -> Self { Self { append: c.get_bool("append") } } } impl From for Opt { fn from(append: bool) -> Self { Self { append } } diff --git a/yazi-core/src/input/commands/kill.rs b/yazi-core/src/input/commands/kill.rs index eeac2245f..754f04ded 100644 --- a/yazi-core/src/input/commands/kill.rs +++ b/yazi-core/src/input/commands/kill.rs @@ -9,7 +9,7 @@ pub struct Opt { } impl From for Opt { - fn from(mut c: Cmd) -> Self { Self { kind: c.take_first().unwrap_or_default() } } + fn from(mut c: Cmd) -> Self { Self { kind: c.take_first_str().unwrap_or_default() } } } impl Input { diff --git a/yazi-core/src/input/commands/move_.rs b/yazi-core/src/input/commands/move_.rs index 0e032b351..2c0536c6b 100644 --- a/yazi-core/src/input/commands/move_.rs +++ b/yazi-core/src/input/commands/move_.rs @@ -11,8 +11,8 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0), - in_operating: c.named.contains_key("in-operating"), + step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0), + in_operating: c.get_bool("in-operating"), } } } diff --git a/yazi-core/src/input/commands/paste.rs b/yazi-core/src/input/commands/paste.rs index c89621164..58417341d 100644 --- a/yazi-core/src/input/commands/paste.rs +++ b/yazi-core/src/input/commands/paste.rs @@ -7,7 +7,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { before: c.named.contains_key("before") } } + fn from(c: Cmd) -> Self { Self { before: c.get_bool("before") } } } impl Input { diff --git a/yazi-core/src/input/commands/show.rs b/yazi-core/src/input/commands/show.rs index 0e09f77f2..1601ca19a 100644 --- a/yazi-core/src/input/commands/show.rs +++ b/yazi-core/src/input/commands/show.rs @@ -1,10 +1,24 @@ -use yazi_proxy::options::InputOpt; -use yazi_shared::render; +use tokio::sync::mpsc; +use yazi_config::popup::InputCfg; +use yazi_shared::{event::Cmd, render, InputError}; use crate::input::Input; +pub struct Opt { + cfg: InputCfg, + tx: mpsc::UnboundedSender>, +} + +impl TryFrom for Opt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { + Ok(Self { cfg: c.take_any("cfg").ok_or(())?, tx: c.take_any("tx").ok_or(())? }) + } +} + impl Input { - pub fn show(&mut self, opt: impl TryInto) { + pub fn show(&mut self, opt: impl TryInto) { let Ok(opt) = opt.try_into() else { return }; self.close(false); diff --git a/yazi-core/src/manager/commands/create.rs b/yazi-core/src/manager/commands/create.rs index 6aa886d98..7dc0a5d69 100644 --- a/yazi-core/src/manager/commands/create.rs +++ b/yazi-core/src/manager/commands/create.rs @@ -12,7 +12,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { force: c.named.contains_key("force") } } + fn from(c: Cmd) -> Self { Self { force: c.get_bool("force") } } } impl Manager { diff --git a/yazi-core/src/manager/commands/hover.rs b/yazi-core/src/manager/commands/hover.rs index 94df57d0b..287e36d96 100644 --- a/yazi-core/src/manager/commands/hover.rs +++ b/yazi-core/src/manager/commands/hover.rs @@ -9,7 +9,7 @@ pub struct Opt { } impl From for Opt { - fn from(mut c: Cmd) -> Self { Self { url: c.take_first().map(Url::from) } } + fn from(mut c: Cmd) -> Self { Self { url: c.take_first_str().map(Url::from) } } } impl From> for Opt { fn from(url: Option) -> Self { Self { url } } diff --git a/yazi-core/src/manager/commands/link.rs b/yazi-core/src/manager/commands/link.rs index 2329782f4..bb8935c10 100644 --- a/yazi-core/src/manager/commands/link.rs +++ b/yazi-core/src/manager/commands/link.rs @@ -8,9 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { - Self { relative: c.named.contains_key("relative"), force: c.named.contains_key("force") } - } + fn from(c: Cmd) -> Self { Self { relative: c.get_bool("relative"), force: c.get_bool("force") } } } impl Manager { diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index 1f1de96ec..60d0af98c 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -17,10 +17,7 @@ pub struct Opt { impl From for Opt { fn from(c: Cmd) -> Self { - Self { - interactive: c.named.contains_key("interactive"), - hovered: c.named.contains_key("hovered"), - } + Self { interactive: c.get_bool("interactive"), hovered: c.get_bool("hovered") } } } diff --git a/yazi-core/src/manager/commands/paste.rs b/yazi-core/src/manager/commands/paste.rs index f551f0230..c85ed6324 100644 --- a/yazi-core/src/manager/commands/paste.rs +++ b/yazi-core/src/manager/commands/paste.rs @@ -8,9 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { - Self { force: c.named.contains_key("force"), follow: c.named.contains_key("follow") } - } + fn from(c: Cmd) -> Self { Self { force: c.get_bool("force"), follow: c.get_bool("follow") } } } impl Manager { diff --git a/yazi-core/src/manager/commands/peek.rs b/yazi-core/src/manager/commands/peek.rs index 217c00671..2c3e40b97 100644 --- a/yazi-core/src/manager/commands/peek.rs +++ b/yazi-core/src/manager/commands/peek.rs @@ -13,10 +13,10 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - skip: c.take_first().and_then(|s| s.parse().ok()), - force: c.named.contains_key("force"), - only_if: c.take_name("only-if").map(Url::from), - upper_bound: c.named.contains_key("upper-bound"), + skip: c.take_first_str().and_then(|s| s.parse().ok()), + force: c.get_bool("force"), + only_if: c.take_str("only-if").map(Url::from), + upper_bound: c.get_bool("upper-bound"), } } } diff --git a/yazi-core/src/manager/commands/quit.rs b/yazi-core/src/manager/commands/quit.rs index 7fd09b270..9f5f34833 100644 --- a/yazi-core/src/manager/commands/quit.rs +++ b/yazi-core/src/manager/commands/quit.rs @@ -12,7 +12,7 @@ impl From<()> for Opt { fn from(_: ()) -> Self { Self::default() } } impl From for Opt { - fn from(c: Cmd) -> Self { Self { no_cwd_file: c.named.contains_key("no-cwd-file") } } + fn from(c: Cmd) -> Self { Self { no_cwd_file: c.get_bool("no-cwd-file") } } } impl Manager { diff --git a/yazi-core/src/manager/commands/remove.rs b/yazi-core/src/manager/commands/remove.rs index 356f926a7..3826b175d 100644 --- a/yazi-core/src/manager/commands/remove.rs +++ b/yazi-core/src/manager/commands/remove.rs @@ -13,9 +13,9 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - force: c.named.contains_key("force"), - permanently: c.named.contains_key("permanently"), - targets: c.take_data().unwrap_or_default(), + force: c.get_bool("force"), + permanently: c.get_bool("permanently"), + targets: c.take_any("targets").unwrap_or_default(), } } } diff --git a/yazi-core/src/manager/commands/rename.rs b/yazi-core/src/manager/commands/rename.rs index af0c28ee7..d9fffff4d 100644 --- a/yazi-core/src/manager/commands/rename.rs +++ b/yazi-core/src/manager/commands/rename.rs @@ -18,9 +18,9 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - force: c.named.contains_key("force"), - empty: c.take_name("empty").unwrap_or_default(), - cursor: c.take_name("cursor").unwrap_or_default(), + force: c.get_bool("force"), + empty: c.take_str("empty").unwrap_or_default(), + cursor: c.take_str("cursor").unwrap_or_default(), } } } diff --git a/yazi-core/src/manager/commands/seek.rs b/yazi-core/src/manager/commands/seek.rs index ef7f6e3aa..936d7b9e9 100644 --- a/yazi-core/src/manager/commands/seek.rs +++ b/yazi-core/src/manager/commands/seek.rs @@ -11,7 +11,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { units: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) } + Self { units: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) } } } diff --git a/yazi-core/src/manager/commands/tab_close.rs b/yazi-core/src/manager/commands/tab_close.rs index 4d28c19d6..90cf441b7 100644 --- a/yazi-core/src/manager/commands/tab_close.rs +++ b/yazi-core/src/manager/commands/tab_close.rs @@ -8,7 +8,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { idx: c.take_first().and_then(|i| i.parse().ok()).unwrap_or(0) } + Self { idx: c.take_first_str().and_then(|i| i.parse().ok()).unwrap_or(0) } } } diff --git a/yazi-core/src/manager/commands/tab_create.rs b/yazi-core/src/manager/commands/tab_create.rs index b5f28aa93..10bf033a4 100644 --- a/yazi-core/src/manager/commands/tab_create.rs +++ b/yazi-core/src/manager/commands/tab_create.rs @@ -13,11 +13,11 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - if c.named.contains_key("current") { + if c.get_bool("current") { Self { url: Default::default(), current: true } } else { Self { - url: c.take_first().map_or_else(|| Url::from(&BOOT.cwd), Url::from), + url: c.take_first_str().map_or_else(|| Url::from(&BOOT.cwd), Url::from), current: false, } } diff --git a/yazi-core/src/manager/commands/tab_swap.rs b/yazi-core/src/manager/commands/tab_swap.rs index 2dec19e1d..4f0660479 100644 --- a/yazi-core/src/manager/commands/tab_swap.rs +++ b/yazi-core/src/manager/commands/tab_swap.rs @@ -8,7 +8,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) } + Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) } } } diff --git a/yazi-core/src/manager/commands/tab_switch.rs b/yazi-core/src/manager/commands/tab_switch.rs index 049a0e3e9..ed99615f0 100644 --- a/yazi-core/src/manager/commands/tab_switch.rs +++ b/yazi-core/src/manager/commands/tab_switch.rs @@ -10,8 +10,8 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0), - relative: c.named.contains_key("relative"), + step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0), + relative: c.get_bool("relative"), } } } diff --git a/yazi-core/src/manager/commands/update_files.rs b/yazi-core/src/manager/commands/update_files.rs index 690d3e74a..6be2cfcdc 100644 --- a/yazi-core/src/manager/commands/update_files.rs +++ b/yazi-core/src/manager/commands/update_files.rs @@ -12,7 +12,9 @@ pub struct Opt { impl TryFrom for Opt { type Error = (); - fn try_from(mut c: Cmd) -> Result { Ok(Self { op: c.take_data().ok_or(())? }) } + fn try_from(mut c: Cmd) -> Result { + Ok(Self { op: c.take_any("op").ok_or(())? }) + } } impl Manager { diff --git a/yazi-core/src/manager/commands/update_mimetype.rs b/yazi-core/src/manager/commands/update_mimetype.rs index 28f3f5231..23c425ecc 100644 --- a/yazi-core/src/manager/commands/update_mimetype.rs +++ b/yazi-core/src/manager/commands/update_mimetype.rs @@ -1,19 +1,18 @@ use std::collections::HashMap; -use yazi_dds::ValueSendable; use yazi_shared::{event::Cmd, fs::Url, render}; use crate::{manager::{Manager, LINKED}, tasks::Tasks}; pub struct Opt { - data: ValueSendable, + updates: HashMap, } impl TryFrom for Opt { type Error = (); fn try_from(mut c: Cmd) -> Result { - Ok(Self { data: c.take_data().ok_or(())? }) + Ok(Self { updates: c.take_data("updates").ok_or(())?.into_table_string() }) } } @@ -25,8 +24,7 @@ impl Manager { let linked = LINKED.read(); let updates = opt - .data - .into_table_string() + .updates .into_iter() .map(|(url, mime)| (Url::from(url), mime)) .filter(|(url, mime)| self.mimetype.get(url) != Some(mime)) diff --git a/yazi-core/src/manager/commands/update_paged.rs b/yazi-core/src/manager/commands/update_paged.rs index fea908185..378c874ed 100644 --- a/yazi-core/src/manager/commands/update_paged.rs +++ b/yazi-core/src/manager/commands/update_paged.rs @@ -11,8 +11,8 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - page: c.take_first().and_then(|s| s.parse().ok()), - only_if: c.take_name("only-if").map(Url::from), + page: c.take_first_str().and_then(|s| s.parse().ok()), + only_if: c.take_str("only-if").map(Url::from), } } } diff --git a/yazi-core/src/manager/commands/yank.rs b/yazi-core/src/manager/commands/yank.rs index 0532e2914..676387b98 100644 --- a/yazi-core/src/manager/commands/yank.rs +++ b/yazi-core/src/manager/commands/yank.rs @@ -8,7 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { cut: c.named.contains_key("cut") } } + fn from(c: Cmd) -> Self { Self { cut: c.get_bool("cut") } } } impl Manager { diff --git a/yazi-core/src/notify/commands/tick.rs b/yazi-core/src/notify/commands/tick.rs index ba8536cf3..b48260e7f 100644 --- a/yazi-core/src/notify/commands/tick.rs +++ b/yazi-core/src/notify/commands/tick.rs @@ -13,7 +13,7 @@ impl TryFrom for Opt { type Error = (); fn try_from(mut c: Cmd) -> Result { - let interval = c.take_first().and_then(|s| s.parse::().ok()).ok_or(())?; + let interval = c.take_first_str().and_then(|s| s.parse::().ok()).ok_or(())?; if interval < 0.0 { return Err(()); } diff --git a/yazi-core/src/select/commands/arrow.rs b/yazi-core/src/select/commands/arrow.rs index 1373e4f29..a434cc82a 100644 --- a/yazi-core/src/select/commands/arrow.rs +++ b/yazi-core/src/select/commands/arrow.rs @@ -8,7 +8,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) } + Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) } } } diff --git a/yazi-core/src/select/commands/close.rs b/yazi-core/src/select/commands/close.rs index b4c60c8ae..01fd90663 100644 --- a/yazi-core/src/select/commands/close.rs +++ b/yazi-core/src/select/commands/close.rs @@ -8,7 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { submit: c.named.contains_key("submit") } } + fn from(c: Cmd) -> Self { Self { submit: c.get_bool("submit") } } } impl From for Opt { fn from(submit: bool) -> Self { Self { submit } } diff --git a/yazi-core/src/select/commands/show.rs b/yazi-core/src/select/commands/show.rs index 1b6d6d1fd..c273e7dc4 100644 --- a/yazi-core/src/select/commands/show.rs +++ b/yazi-core/src/select/commands/show.rs @@ -1,10 +1,24 @@ -use yazi_proxy::options::SelectOpt; -use yazi_shared::render; +use tokio::sync::oneshot; +use yazi_config::popup::SelectCfg; +use yazi_shared::{event::Cmd, render}; use crate::select::Select; +pub struct Opt { + cfg: SelectCfg, + tx: oneshot::Sender>, +} + +impl TryFrom for Opt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { + Ok(Self { cfg: c.take_any("cfg").ok_or(())?, tx: c.take_any("tx").ok_or(())? }) + } +} + impl Select { - pub fn show(&mut self, opt: impl TryInto) { + pub fn show(&mut self, opt: impl TryInto) { let Ok(opt) = opt.try_into() else { return; }; diff --git a/yazi-core/src/tab/commands/arrow.rs b/yazi-core/src/tab/commands/arrow.rs index 13c643783..bf789cac5 100644 --- a/yazi-core/src/tab/commands/arrow.rs +++ b/yazi-core/src/tab/commands/arrow.rs @@ -10,7 +10,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or_default() } + Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or_default() } } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 379f49035..1990ee75e 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -16,12 +16,12 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - let mut target = Url::from(c.take_first().unwrap_or_default()); + let mut target = Url::from(c.take_first_str().unwrap_or_default()); if target.is_regular() { target.set_path(expand_path(&target)) } - Self { target, interactive: c.named.contains_key("interactive") } + Self { target, interactive: c.get_bool("interactive") } } } impl From for Opt { diff --git a/yazi-core/src/tab/commands/copy.rs b/yazi-core/src/tab/commands/copy.rs index f2af284d1..22344720b 100644 --- a/yazi-core/src/tab/commands/copy.rs +++ b/yazi-core/src/tab/commands/copy.rs @@ -9,7 +9,7 @@ pub struct Opt { } impl From for Opt { - fn from(mut c: Cmd) -> Self { Self { type_: c.take_first().unwrap_or_default() } } + fn from(mut c: Cmd) -> Self { Self { type_: c.take_first_str().unwrap_or_default() } } } impl Tab { diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index 100158725..23bbc0d2e 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -16,14 +16,16 @@ bitflags! { impl From for Opt { fn from(c: Cmd) -> Self { - c.named.iter().fold(Opt::empty(), |acc, (k, _)| match k.as_str() { - "all" => Self::all(), - "find" => acc | Self::FIND, - "visual" => acc | Self::VISUAL, - "select" => acc | Self::SELECT, - "filter" => acc | Self::FILTER, - "search" => acc | Self::SEARCH, - _ => acc, + c.args.iter().fold(Opt::empty(), |acc, (k, v)| { + match (k.as_str(), v.as_bool().unwrap_or(false)) { + ("all", true) => Self::all(), + ("find", true) => acc | Self::FIND, + ("visual", true) => acc | Self::VISUAL, + ("select", true) => acc | Self::SELECT, + ("filter", true) => acc | Self::FILTER, + ("search", true) => acc | Self::SEARCH, + _ => acc, + } }) } } diff --git a/yazi-core/src/tab/commands/filter.rs b/yazi-core/src/tab/commands/filter.rs index 56000b00d..0516a0b65 100644 --- a/yazi-core/src/tab/commands/filter.rs +++ b/yazi-core/src/tab/commands/filter.rs @@ -18,9 +18,9 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - query: c.take_first().unwrap_or_default(), + query: c.take_first_str().unwrap_or_default(), case: FilterCase::from(&c), - done: c.named.contains_key("done"), + done: c.get_bool("done"), } } } diff --git a/yazi-core/src/tab/commands/find.rs b/yazi-core/src/tab/commands/find.rs index 950a73cc1..d4b02dc48 100644 --- a/yazi-core/src/tab/commands/find.rs +++ b/yazi-core/src/tab/commands/find.rs @@ -16,11 +16,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { - query: c.take_first(), - prev: c.named.contains_key("previous"), - case: FilterCase::from(&c), - } + Self { query: c.take_first_str(), prev: c.get_bool("previous"), case: FilterCase::from(&c) } } } @@ -29,7 +25,7 @@ pub struct ArrowOpt { } impl From for ArrowOpt { - fn from(c: Cmd) -> Self { Self { prev: c.named.contains_key("previous") } } + fn from(c: Cmd) -> Self { Self { prev: c.get_bool("previous") } } } impl Tab { diff --git a/yazi-core/src/tab/commands/hidden.rs b/yazi-core/src/tab/commands/hidden.rs index 6e71d8d2c..62b6e93c2 100644 --- a/yazi-core/src/tab/commands/hidden.rs +++ b/yazi-core/src/tab/commands/hidden.rs @@ -4,8 +4,8 @@ use yazi_shared::event::Cmd; use crate::tab::Tab; impl Tab { - pub fn hidden(&mut self, c: Cmd) { - self.conf.show_hidden = match c.args.first().map(|s| s.as_str()) { + pub fn hidden(&mut self, mut c: Cmd) { + self.conf.show_hidden = match c.take_first_str().as_deref() { Some("show") => true, Some("hide") => false, _ => !self.conf.show_hidden, diff --git a/yazi-core/src/tab/commands/jump.rs b/yazi-core/src/tab/commands/jump.rs index 47bd09760..810abbbf8 100644 --- a/yazi-core/src/tab/commands/jump.rs +++ b/yazi-core/src/tab/commands/jump.rs @@ -17,9 +17,9 @@ pub enum OptType { } impl From for Opt { - fn from(c: Cmd) -> Self { + fn from(mut c: Cmd) -> Self { Self { - type_: match c.args.first().map(|s| s.as_str()) { + type_: match c.take_first_str().as_deref() { Some("fzf") => OptType::Fzf, Some("zoxide") => OptType::Zoxide, _ => OptType::None, diff --git a/yazi-core/src/tab/commands/linemode.rs b/yazi-core/src/tab/commands/linemode.rs index b4852200f..123995f24 100644 --- a/yazi-core/src/tab/commands/linemode.rs +++ b/yazi-core/src/tab/commands/linemode.rs @@ -5,7 +5,7 @@ use crate::tab::Tab; impl Tab { pub fn linemode(&mut self, mut c: Cmd) { render!(self.conf.patch(|new| { - let Some(mode) = c.take_first() else { + let Some(mode) = c.take_first_str() else { return; }; if !mode.is_empty() && mode.len() <= 20 { diff --git a/yazi-core/src/tab/commands/preview.rs b/yazi-core/src/tab/commands/preview.rs index 8c1b68a22..ed838b828 100644 --- a/yazi-core/src/tab/commands/preview.rs +++ b/yazi-core/src/tab/commands/preview.rs @@ -11,7 +11,7 @@ impl TryFrom for Opt { type Error = (); fn try_from(mut c: Cmd) -> Result { - Ok(Self { lock: c.take_data().ok_or(())? }) + Ok(Self { lock: c.take_any("lock").ok_or(())? }) } } diff --git a/yazi-core/src/tab/commands/reveal.rs b/yazi-core/src/tab/commands/reveal.rs index cf49d7365..44f9c38c4 100644 --- a/yazi-core/src/tab/commands/reveal.rs +++ b/yazi-core/src/tab/commands/reveal.rs @@ -9,7 +9,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - let mut target = Url::from(c.take_first().unwrap_or_default()); + let mut target = Url::from(c.take_first_str().unwrap_or_default()); if target.is_regular() { target.set_path(expand_path(&target)) } diff --git a/yazi-core/src/tab/commands/search.rs b/yazi-core/src/tab/commands/search.rs index 4f71ffc03..d4119e903 100644 --- a/yazi-core/src/tab/commands/search.rs +++ b/yazi-core/src/tab/commands/search.rs @@ -42,7 +42,7 @@ pub struct Opt { } impl From for Opt { - fn from(mut c: Cmd) -> Self { Self { type_: c.take_first().unwrap_or_default().into() } } + fn from(mut c: Cmd) -> Self { Self { type_: c.take_first_str().unwrap_or_default().into() } } } impl Tab { diff --git a/yazi-core/src/tab/commands/select.rs b/yazi-core/src/tab/commands/select.rs index 10a9d9872..753829237 100644 --- a/yazi-core/src/tab/commands/select.rs +++ b/yazi-core/src/tab/commands/select.rs @@ -13,8 +13,8 @@ pub struct Opt<'a> { impl<'a> From for Opt<'a> { fn from(mut c: Cmd) -> Self { Self { - url: c.take_name("url").map(|s| Cow::Owned(Url::from(s))), - state: match c.named.get("state").map(|s| s.as_str()) { + url: c.take_str("url").map(|s| Cow::Owned(Url::from(s))), + state: match c.take_str("state").as_deref() { Some("true") => Some(true), Some("false") => Some(false), _ => None, diff --git a/yazi-core/src/tab/commands/select_all.rs b/yazi-core/src/tab/commands/select_all.rs index f081bbde9..f87f9b708 100644 --- a/yazi-core/src/tab/commands/select_all.rs +++ b/yazi-core/src/tab/commands/select_all.rs @@ -8,9 +8,9 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { + fn from(mut c: Cmd) -> Self { Self { - state: match c.named.get("state").map(|s| s.as_str()) { + state: match c.take_str("state").as_deref() { Some("true") => Some(true), Some("false") => Some(false), _ => None, diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index ec566163a..a66e525a4 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -16,10 +16,10 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - run: c.take_first().unwrap_or_default(), - block: c.named.contains_key("block"), - orphan: c.named.contains_key("orphan"), - confirm: c.named.contains_key("confirm"), + run: c.take_first_str().unwrap_or_default(), + block: c.get_bool("block"), + orphan: c.get_bool("orphan"), + confirm: c.get_bool("confirm"), } } } diff --git a/yazi-core/src/tab/commands/sort.rs b/yazi-core/src/tab/commands/sort.rs index c36321db9..c7aebf77d 100644 --- a/yazi-core/src/tab/commands/sort.rs +++ b/yazi-core/src/tab/commands/sort.rs @@ -7,13 +7,13 @@ use yazi_shared::event::Cmd; use crate::{tab::Tab, tasks::Tasks}; impl Tab { - pub fn sort(&mut self, c: Cmd, tasks: &Tasks) { - if let Some(by) = c.args.first() { - self.conf.sort_by = SortBy::from_str(by).unwrap_or_default(); + pub fn sort(&mut self, mut c: Cmd, tasks: &Tasks) { + if let Some(by) = c.take_first_str() { + self.conf.sort_by = SortBy::from_str(&by).unwrap_or_default(); } - self.conf.sort_sensitive = c.named.contains_key("sensitive"); - self.conf.sort_reverse = c.named.contains_key("reverse"); - self.conf.sort_dir_first = c.named.contains_key("dir-first"); + self.conf.sort_sensitive = c.get_bool("sensitive"); + self.conf.sort_reverse = c.get_bool("reverse"); + self.conf.sort_dir_first = c.get_bool("dir-first"); self.apply_files_attrs(); ManagerProxy::update_paged(); diff --git a/yazi-core/src/tab/commands/visual_mode.rs b/yazi-core/src/tab/commands/visual_mode.rs index 8e19ace52..606a7e627 100644 --- a/yazi-core/src/tab/commands/visual_mode.rs +++ b/yazi-core/src/tab/commands/visual_mode.rs @@ -9,7 +9,7 @@ pub struct Opt { } impl From for Opt { - fn from(c: Cmd) -> Self { Self { unset: c.named.contains_key("unset") } } + fn from(c: Cmd) -> Self { Self { unset: c.get_bool("unset") } } } impl Tab { diff --git a/yazi-core/src/tasks/commands/arrow.rs b/yazi-core/src/tasks/commands/arrow.rs index 9b68c9fec..baf1859c2 100644 --- a/yazi-core/src/tasks/commands/arrow.rs +++ b/yazi-core/src/tasks/commands/arrow.rs @@ -8,7 +8,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) } + Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) } } } diff --git a/yazi-core/src/tasks/plugin.rs b/yazi-core/src/tasks/plugin.rs index ea1581a56..db4dab56a 100644 --- a/yazi-core/src/tasks/plugin.rs +++ b/yazi-core/src/tasks/plugin.rs @@ -1,15 +1,15 @@ -use yazi_dds::ValueSendable; +use yazi_shared::event::Data; use super::Tasks; impl Tasks { #[inline] - pub fn plugin_micro(&self, name: String, args: Vec) { + pub fn plugin_micro(&self, name: String, args: Vec) { self.scheduler.plugin_micro(name, args); } #[inline] - pub fn plugin_macro(&self, name: String, args: Vec) { + pub fn plugin_macro(&self, name: String, args: Vec) { self.scheduler.plugin_macro(name, args); } } diff --git a/yazi-core/src/tasks/tasks.rs b/yazi-core/src/tasks/tasks.rs index 2b680d46c..1f1378674 100644 --- a/yazi-core/src/tasks/tasks.rs +++ b/yazi-core/src/tasks/tasks.rs @@ -29,7 +29,7 @@ impl Tasks { let new = TasksProgress::from(&*ongoing.lock()); if last != new { last = new; - emit!(Call(Cmd::new("update_progress").with_data(new), Layer::App)); + emit!(Call(Cmd::new("update_progress").with_any("progress", new), Layer::App)); } } }); diff --git a/yazi-core/src/which/commands/callback.rs b/yazi-core/src/which/commands/callback.rs index ef0fc5fed..3970f214f 100644 --- a/yazi-core/src/which/commands/callback.rs +++ b/yazi-core/src/which/commands/callback.rs @@ -14,8 +14,8 @@ impl TryFrom for Opt { fn try_from(mut c: Cmd) -> Result { Ok(Self { - tx: c.take_data().ok_or(())?, - idx: c.take_first().and_then(|s| s.parse().ok()).ok_or(())?, + tx: c.take_any("tx").ok_or(())?, + idx: c.take_first_str().and_then(|s| s.parse().ok()).ok_or(())?, }) } } diff --git a/yazi-core/src/which/commands/show.rs b/yazi-core/src/which/commands/show.rs index 22994c6d7..ea68d6905 100644 --- a/yazi-core/src/which/commands/show.rs +++ b/yazi-core/src/which/commands/show.rs @@ -16,9 +16,9 @@ impl TryFrom for Opt { fn try_from(mut c: Cmd) -> Result { Ok(Self { - cands: c.take_data().unwrap_or_default(), - layer: Layer::from_str(&c.take_name("layer").unwrap_or_default())?, - silent: c.named.contains_key("silent"), + cands: c.take_any("candidates").unwrap_or_default(), + layer: Layer::from_str(&c.take_str("layer").unwrap_or_default())?, + silent: c.get_bool("silent"), }) } } diff --git a/yazi-dds/src/body/custom.rs b/yazi-dds/src/body/custom.rs index 686c5d349..3ef50058d 100644 --- a/yazi-dds/src/body/custom.rs +++ b/yazi-dds/src/body/custom.rs @@ -1,24 +1,25 @@ use mlua::{IntoLua, Lua, Value}; use serde::Serialize; +use yazi_shared::event::Data; use super::Body; -use crate::ValueSendable; +use crate::Sendable; #[derive(Debug)] pub struct BodyCustom { - pub kind: String, - pub value: ValueSendable, + pub kind: String, + pub data: Data, } impl BodyCustom { #[inline] - pub fn from_str(kind: &str, value: &str) -> anyhow::Result> { - Ok(Self { kind: kind.to_owned(), value: serde_json::from_str(value)? }.into()) + pub fn from_str(kind: &str, data: &str) -> anyhow::Result> { + Ok(Self { kind: kind.to_owned(), data: serde_json::from_str(data)? }.into()) } #[inline] - pub fn from_lua(kind: &str, value: Value) -> mlua::Result> { - Ok(Self { kind: kind.to_owned(), value: value.try_into()? }.into()) + pub fn from_lua(kind: &str, data: Value) -> mlua::Result> { + Ok(Self { kind: kind.to_owned(), data: Sendable::value_to_data(data)? }.into()) } } @@ -27,11 +28,11 @@ impl From for Body<'_> { } impl IntoLua<'_> for BodyCustom { - fn into_lua(self, lua: &Lua) -> mlua::Result { self.value.into_lua(lua) } + fn into_lua(self, lua: &Lua) -> mlua::Result { Sendable::data_to_value(lua, self.data) } } impl Serialize for BodyCustom { fn serialize(&self, serializer: S) -> Result { - serde::Serialize::serialize(&self.value, serializer) + serde::Serialize::serialize(&self.data, serializer) } } diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index 2365dc613..855a77940 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -67,7 +67,7 @@ impl Payload<'static> { pub(super) fn emit(self) { self.try_flush(); - emit!(Call(Cmd::new("accept_payload").with_data(self), Layer::App)); + emit!(Call(Cmd::new("accept_payload").with_any("payload", self), Layer::App)); } } diff --git a/yazi-dds/src/sendable.rs b/yazi-dds/src/sendable.rs index cc1125151..d9957420a 100644 --- a/yazi-dds/src/sendable.rs +++ b/yazi-dds/src/sendable.rs @@ -1,129 +1,122 @@ use std::collections::HashMap; -use mlua::{ExternalError, IntoLua, Lua, Value, Variadic}; -use serde::{Deserialize, Serialize}; -use yazi_shared::OrderedFloat; +use mlua::{ExternalError, Lua, Table, Value, Variadic}; +use yazi_shared::{event::{Data, DataKey}, OrderedFloat}; -#[derive(Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ValueSendable { - Nil, - Boolean(bool), - Integer(i64), - Number(f64), - String(String), - Table(HashMap), -} - -impl ValueSendable { - pub fn try_from_variadic(values: Variadic) -> mlua::Result> { - let mut vec = Vec::with_capacity(values.len()); - for value in values { - vec.push(Self::try_from(value)?); - } - Ok(vec) - } - - pub fn into_table_string(self) -> HashMap { - let Self::Table(table) = self else { - return Default::default(); - }; - - let mut map = HashMap::with_capacity(table.len()); - for pair in table { - if let (ValueSendableKey::String(k), Self::String(v)) = pair { - map.insert(k, v); - } - } - map - } -} - -impl<'a> TryFrom> for ValueSendable { - type Error = mlua::Error; +pub struct Sendable; - fn try_from(value: Value) -> Result { +impl Sendable { + pub fn value_to_data(value: Value) -> mlua::Result { Ok(match value { - Value::Nil => Self::Nil, - Value::Boolean(b) => Self::Boolean(b), + Value::Nil => Data::Nil, + Value::Boolean(b) => Data::Boolean(b), Value::LightUserData(_) => Err("light userdata is not supported".into_lua_err())?, - Value::Integer(n) => Self::Integer(n), - Value::Number(n) => Self::Number(n), - Value::String(s) => Self::String(s.to_str()?.to_owned()), + Value::Integer(n) => Data::Integer(n), + Value::Number(n) => Data::Number(n), + Value::String(s) => Data::String(s.to_str()?.to_owned()), Value::Table(t) => { - let mut map = HashMap::with_capacity(t.len().map(|l| l as usize)?); + let mut map = HashMap::with_capacity(t.raw_len()); for result in t.pairs::() { let (k, v) = result?; - map.insert(Self::try_from(k)?.try_into()?, v.try_into()?); + map.insert(Self::value_to_key(k)?, Self::value_to_data(v)?); } - Self::Table(map) + Data::Table(map) } Value::Function(_) => Err("function is not supported".into_lua_err())?, Value::Thread(_) => Err("thread is not supported".into_lua_err())?, - Value::UserData(_) => Err("userdata is not supported".into_lua_err())?, + Value::UserData(ud) => { + if let Ok(t) = ud.take::() { + Data::Url(t) + } else if let Ok(t) = ud.take::() { + Data::Any(Box::new(t)) + } else { + Err("unsupported userdata included".into_lua_err())? + } + } Value::Error(_) => Err("error is not supported".into_lua_err())?, }) } -} -impl IntoLua<'_> for ValueSendable { - fn into_lua(self, lua: &Lua) -> mlua::Result { - match self { - Self::Nil => Ok(Value::Nil), - Self::Boolean(v) => Ok(Value::Boolean(v)), - Self::Integer(v) => Ok(Value::Integer(v)), - Self::Number(v) => Ok(Value::Number(v)), - Self::String(v) => Ok(Value::String(lua.create_string(v)?)), - Self::Table(v) => { - let seq_len = v.keys().filter(|&k| !k.is_numeric()).count(); - let table = lua.create_table_with_capacity(seq_len, v.len() - seq_len)?; - for (k, v) in v { - table.raw_set(k, v)?; + pub fn data_to_value(lua: &Lua, data: Data) -> mlua::Result { + Ok(match data { + Data::Nil => Value::Nil, + Data::Boolean(v) => Value::Boolean(v), + Data::Integer(v) => Value::Integer(v), + Data::Number(v) => Value::Number(v), + Data::String(v) => Value::String(lua.create_string(v)?), + Data::Table(t) => { + let seq_len = t.keys().filter(|&k| !k.is_numeric()).count(); + let table = lua.create_table_with_capacity(seq_len, t.len() - seq_len)?; + for (k, v) in t { + table.raw_set(Self::key_to_value(lua, k)?, Self::data_to_value(lua, v)?)?; } - Ok(Value::Table(table)) + Value::Table(table) } - } + Data::Url(v) => Value::UserData(lua.create_any_userdata(v)?), + Data::Any(v) => { + if let Ok(t) = v.downcast::() { + Value::UserData(lua.create_userdata(*t)?) + } else { + Err("unsupported userdata included".into_lua_err())? + } + } + }) } -} -#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ValueSendableKey { - Nil, - Boolean(bool), - Integer(i64), - Number(OrderedFloat), - String(String), -} + pub fn vec_to_table(lua: &Lua, data: Vec) -> mlua::Result { + let mut vec = Vec::with_capacity(data.len()); + for v in data.into_iter() { + vec.push(Self::data_to_value(lua, v)?); + } + lua.create_sequence_from(vec) + } -impl ValueSendableKey { - #[inline] - fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) } -} + pub fn vec_to_variadic(lua: &Lua, data: Vec) -> mlua::Result> { + let mut vec = Vec::with_capacity(data.len()); + for v in data { + vec.push(Self::data_to_value(lua, v)?); + } + Ok(Variadic::from_iter(vec)) + } -impl TryInto for ValueSendable { - type Error = mlua::Error; + pub fn variadic_to_vec(values: Variadic) -> mlua::Result> { + let mut vec = Vec::with_capacity(values.len()); + for value in values { + vec.push(Self::value_to_data(value)?); + } + Ok(vec) + } - fn try_into(self) -> Result { - Ok(match self { - Self::Nil => ValueSendableKey::Nil, - Self::Boolean(v) => ValueSendableKey::Boolean(v), - Self::Integer(v) => ValueSendableKey::Integer(v), - Self::Number(v) => ValueSendableKey::Number(OrderedFloat::new(v)), - Self::String(v) => ValueSendableKey::String(v), - Self::Table(_) => Err("table is not supported".into_lua_err())?, + fn value_to_key(value: Value) -> mlua::Result { + Ok(match value { + Value::Nil => DataKey::Nil, + Value::Boolean(v) => DataKey::Boolean(v), + Value::LightUserData(_) => Err("light userdata is not supported".into_lua_err())?, + Value::Integer(v) => DataKey::Integer(v), + Value::Number(v) => DataKey::Number(OrderedFloat::new(v)), + Value::String(v) => DataKey::String(v.to_str()?.to_owned()), + Value::Table(_) => Err("table is not supported".into_lua_err())?, + Value::Function(_) => Err("function is not supported".into_lua_err())?, + Value::Thread(_) => Err("thread is not supported".into_lua_err())?, + Value::UserData(ud) => { + if let Ok(t) = ud.take::() { + DataKey::Url(t) + } else { + Err("unsupported userdata included".into_lua_err())? + } + } + Value::Error(_) => Err("error is not supported".into_lua_err())?, }) } -} -impl IntoLua<'_> for ValueSendableKey { - fn into_lua(self, lua: &Lua) -> mlua::Result { - match self { - Self::Nil => Ok(Value::Nil), - Self::Boolean(k) => Ok(Value::Boolean(k)), - Self::Integer(k) => Ok(Value::Integer(k)), - Self::Number(k) => Ok(Value::Number(k.get())), - Self::String(k) => Ok(Value::String(lua.create_string(k)?)), - } + fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result { + Ok(match key { + DataKey::Nil => Value::Nil, + DataKey::Boolean(k) => Value::Boolean(k), + DataKey::Integer(k) => Value::Integer(k), + DataKey::Number(k) => Value::Number(k.get()), + DataKey::String(k) => Value::String(lua.create_string(k)?), + DataKey::Url(k) => Value::UserData(lua.create_any_userdata(k)?), + }) } } diff --git a/yazi-fm/src/app/commands/accept_payload.rs b/yazi-fm/src/app/commands/accept_payload.rs index 6e6781876..7048a6e58 100644 --- a/yazi-fm/src/app/commands/accept_payload.rs +++ b/yazi-fm/src/app/commands/accept_payload.rs @@ -8,7 +8,7 @@ use crate::{app::App, lives::Lives}; impl App { pub(crate) fn accept_payload(&mut self, mut cmd: Cmd) { - let Some(payload) = cmd.take_data::() else { + let Some(payload) = cmd.take_any::("payload") else { return; }; diff --git a/yazi-fm/src/app/commands/plugin.rs b/yazi-fm/src/app/commands/plugin.rs index ba71f5e00..cc2ee9be2 100644 --- a/yazi-fm/src/app/commands/plugin.rs +++ b/yazi-fm/src/app/commands/plugin.rs @@ -3,7 +3,8 @@ use std::fmt::Display; use mlua::TableExt; use scopeguard::defer; use tracing::warn; -use yazi_plugin::{loader::LOADER, OptData, RtRef, LUA}; +use yazi_dds::Sendable; +use yazi_plugin::{loader::LOADER, RtRef, LUA}; use yazi_shared::{emit, event::Cmd, Layer}; use crate::{app::App, lives::Lives}; @@ -16,7 +17,7 @@ impl App { }; if !opt.sync { - return self.cx.tasks.plugin_micro(opt.name, opt.data.args); + return self.cx.tasks.plugin_micro(opt.name, opt.args); } if LOADER.read().contains_key(&opt.name) { @@ -25,14 +26,15 @@ impl App { tokio::spawn(async move { if LOADER.ensure(&opt.name).await.is_ok() { - Self::_plugin_do(opt.name, opt.data); + Self::_plugin_do(opt); } }); } #[inline] - pub(crate) fn _plugin_do(name: String, data: OptData) { - emit!(Call(Cmd::args("plugin_do", vec![name]).with_data(data), Layer::App)); + pub(crate) fn _plugin_do(opt: yazi_plugin::Opt) { + let cmd: Cmd = opt.into(); + emit!(Call(cmd.with_name("plugin_do"), Layer::App)); } pub(crate) fn plugin_do(&mut self, opt: impl TryInto) { @@ -53,10 +55,10 @@ impl App { }; _ = Lives::scope(&self.cx, |_| { - if let Some(cb) = opt.data.cb { + if let Some(cb) = opt.cb { cb(&LUA, plugin) } else { - plugin.call_method("entry", opt.data.args) + plugin.call_method("entry", Sendable::vec_to_table(&LUA, opt.args)?) } }); } diff --git a/yazi-fm/src/app/commands/stop.rs b/yazi-fm/src/app/commands/stop.rs index cfc0e1255..1088c7d74 100644 --- a/yazi-fm/src/app/commands/stop.rs +++ b/yazi-fm/src/app/commands/stop.rs @@ -8,7 +8,7 @@ pub struct Opt { } impl From for Opt { - fn from(mut c: Cmd) -> Self { Self { tx: c.take_data() } } + fn from(mut c: Cmd) -> Self { Self { tx: c.take_any("tx") } } } impl App { diff --git a/yazi-fm/src/app/commands/update_progress.rs b/yazi-fm/src/app/commands/update_progress.rs index ed2756b4e..21a626902 100644 --- a/yazi-fm/src/app/commands/update_progress.rs +++ b/yazi-fm/src/app/commands/update_progress.rs @@ -12,7 +12,7 @@ impl TryFrom for Opt { type Error = (); fn try_from(mut c: Cmd) -> Result { - Ok(Self { progress: c.take_data().ok_or(())? }) + Ok(Self { progress: c.take_any("progress").ok_or(())? }) } } diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 1c347bdfb..b7a056cae 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -214,7 +214,7 @@ impl<'a> Executor<'a> { on!(forward); if cmd.name.as_str() == "complete" { - return if cmd.named.contains_key("trigger") { + return if cmd.get_bool("trigger") { self.app.cx.completion.trigger(cmd) } else { self.app.cx.input.complete(cmd) diff --git a/yazi-plugin/preset/plugins/mime.lua b/yazi-plugin/preset/plugins/mime.lua index 61327da36..334169658 100644 --- a/yazi-plugin/preset/plugins/mime.lua +++ b/yazi-plugin/preset/plugins/mime.lua @@ -22,18 +22,18 @@ function M:preload() return 0 end - local mimes, last = {}, ya.time() + local updates, last = {}, ya.time() local flush = function(force) if not force and ya.time() - last < 0.3 then return end - if next(mimes) then - ya.manager_emit("update_mimetype", {}, mimes) - mimes, last = {}, ya.time() + if next(updates) then + ya.manager_emit("update_mimetype", { updates = updates }) + updates, last = {}, ya.time() end end - local i, j, mime = 1, 0, nil + local i, j, valid = 1, 0, nil repeat local line, event = child:read_line_with { timeout = 300 } if event == 3 then @@ -43,11 +43,11 @@ function M:preload() break end - mime = match_mimetype(line) - if mime and string.find(line, mime, 1, true) ~= 1 then + valid = match_mimetype(line) + if valid and string.find(line, valid, 1, true) ~= 1 then goto continue - elseif mime then - j, mimes[urls[i]] = j + 1, mime + elseif valid then + j, updates[urls[i]] = j + 1, valid flush(false) end diff --git a/yazi-plugin/src/isolate/entry.rs b/yazi-plugin/src/isolate/entry.rs index 0edea6183..a68278cf1 100644 --- a/yazi-plugin/src/isolate/entry.rs +++ b/yazi-plugin/src/isolate/entry.rs @@ -1,11 +1,12 @@ use mlua::{ExternalError, ExternalResult, Table, TableExt}; use tokio::runtime::Handle; -use yazi_dds::ValueSendable; +use yazi_dds::Sendable; +use yazi_shared::event::Data; use super::slim_lua; use crate::loader::LOADER; -pub async fn entry(name: String, args: Vec) -> mlua::Result<()> { +pub async fn entry(name: String, args: Vec) -> mlua::Result<()> { LOADER.ensure(&name).await.into_lua_err()?; tokio::task::spawn_blocking(move || { @@ -16,7 +17,8 @@ pub async fn entry(name: String, args: Vec) -> mlua::Result<()> { return Err("unloaded plugin".into_lua_err()); }; - Handle::current().block_on(plugin.call_async_method("entry", args)) + Handle::current() + .block_on(plugin.call_async_method("entry", Sendable::vec_to_table(&lua, args))) }) .await .into_lua_err()? diff --git a/yazi-plugin/src/isolate/peek.rs b/yazi-plugin/src/isolate/peek.rs index 2ad97463f..886caf941 100644 --- a/yazi-plugin/src/isolate/peek.rs +++ b/yazi-plugin/src/isolate/peek.rs @@ -6,7 +6,7 @@ use yazi_config::LAYOUT; use yazi_shared::{emit, event::Cmd, Layer}; use super::slim_lua; -use crate::{bindings::{Cast, File, Window}, elements::Rect, loader::LOADER, OptData, LUA}; +use crate::{bindings::{Cast, File, Window}, elements::Rect, loader::LOADER, Opt, OptCallback, LUA}; pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> CancellationToken { let ct = CancellationToken::new(); @@ -56,18 +56,16 @@ pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> Cancellation } pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) { - let data = OptData { - cb: Some(Box::new(move |_, plugin| { - plugin.raw_set("file", File::cast(&LUA, file)?)?; - plugin.raw_set("skip", skip)?; - plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?; - plugin.raw_set("window", Window::default())?; - plugin.call_method("peek", ()) - })), - ..Default::default() - }; - emit!(Call( - Cmd::args("plugin", vec![cmd.name.to_owned()]).with_bool("sync", true).with_data(data), - Layer::App - )); + let cb: OptCallback = Box::new(move |_, plugin| { + plugin.raw_set("file", File::cast(&LUA, file)?)?; + plugin.raw_set("skip", skip)?; + plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?; + plugin.raw_set("window", Window::default())?; + plugin.call_method("peek", ()) + }); + + let cmd: Cmd = + Opt { name: cmd.name.to_owned(), sync: true, cb: Some(cb), ..Default::default() }.into(); + + emit!(Call(cmd.with_name("plugin"), Layer::App)); } diff --git a/yazi-plugin/src/isolate/seek.rs b/yazi-plugin/src/isolate/seek.rs index 56a3cdcc0..74af4f86b 100644 --- a/yazi-plugin/src/isolate/seek.rs +++ b/yazi-plugin/src/isolate/seek.rs @@ -2,19 +2,17 @@ use mlua::TableExt; use yazi_config::LAYOUT; use yazi_shared::{emit, event::Cmd, Layer}; -use crate::{bindings::{Cast, File}, elements::Rect, OptData, LUA}; +use crate::{bindings::{Cast, File}, elements::Rect, Opt, OptCallback, LUA}; pub fn seek_sync(cmd: &Cmd, file: yazi_shared::fs::File, units: i16) { - let data = OptData { - cb: Some(Box::new(move |_, plugin| { - plugin.raw_set("file", File::cast(&LUA, file)?)?; - plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?; - plugin.call_method("seek", units) - })), - ..Default::default() - }; - emit!(Call( - Cmd::args("plugin", vec![cmd.name.to_owned()]).with_bool("sync", true).with_data(data), - Layer::App - )); + let cb: OptCallback = Box::new(move |_, plugin| { + plugin.raw_set("file", File::cast(&LUA, file)?)?; + plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?; + plugin.call_method("seek", units) + }); + + let cmd: Cmd = + Opt { name: cmd.name.to_owned(), sync: true, cb: Some(cb), ..Default::default() }.into(); + + emit!(Call(cmd.with_name("plugin"), Layer::App)); } diff --git a/yazi-plugin/src/opt.rs b/yazi-plugin/src/opt.rs index d97b5c70d..87cee4f4c 100644 --- a/yazi-plugin/src/opt.rs +++ b/yazi-plugin/src/opt.rs @@ -1,34 +1,43 @@ use anyhow::bail; use mlua::{Lua, Table}; -use yazi_dds::ValueSendable; -use yazi_shared::event::Cmd; +use yazi_shared::event::{Cmd, Data}; +pub(super) type OptCallback = Box mlua::Result<()> + Send>; + +#[derive(Default)] pub struct Opt { pub name: String, pub sync: bool, - pub data: OptData, -} - -#[derive(Default)] -pub struct OptData { - pub args: Vec, - pub cb: Option mlua::Result<()> + Send>>, + pub args: Vec, + pub cb: Option, } impl TryFrom for Opt { type Error = anyhow::Error; fn try_from(mut c: Cmd) -> Result { - let Some(name) = c.take_first().filter(|s| !s.is_empty()) else { + let Some(name) = c.take_first_str().filter(|s| !s.is_empty()) else { bail!("plugin name cannot be empty"); }; - let mut data: OptData = c.take_data().unwrap_or_default(); + let args = if let Some(s) = c.get_str("args") { + shell_words::split(s)?.into_iter().map(Data::String).collect() + } else { + c.take_any::>("args").unwrap_or_default() + }; - if let Some(args) = c.named.get("args") { - data.args = shell_words::split(args)?.into_iter().map(ValueSendable::String).collect(); - } + Ok(Self { name, sync: c.get_bool("sync"), args, cb: c.take_any("callback") }) + } +} - Ok(Self { name, sync: c.named.contains_key("sync"), data }) +impl From for Cmd { + fn from(value: Opt) -> Self { + let mut cmd = + Cmd::args("", vec![value.name]).with_bool("sync", value.sync).with_any("args", value.args); + + if let Some(cb) = value.cb { + cmd = cmd.with_any("callback", cb); + } + cmd } } diff --git a/yazi-plugin/src/utils/call.rs b/yazi-plugin/src/utils/call.rs index 860de583f..c788aea7c 100644 --- a/yazi-plugin/src/utils/call.rs +++ b/yazi-plugin/src/utils/call.rs @@ -1,52 +1,27 @@ use std::collections::HashMap; use mlua::{ExternalError, Lua, Table, Value}; -use yazi_dds::ValueSendable; -use yazi_shared::{emit, event::Cmd, render, Layer}; +use yazi_dds::Sendable; +use yazi_shared::{emit, event::{Cmd, Data}, render, Layer}; use super::Utils; impl Utils { - fn parse_args(t: Table) -> mlua::Result<(Vec, HashMap)> { - let mut args = vec![]; - let mut named = HashMap::new(); - for result in t.pairs::() { - let (k, v) = result?; + fn parse_args(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(_) => { - args.push(match v { - Value::Integer(i) => i.to_string(), - Value::Number(n) => n.to_string(), - Value::String(s) => s.to_string_lossy().into_owned(), - _ => return Err("invalid value in cmd".into_lua_err()), - }); + Value::Integer(i) if i > 0 => { + args.insert((i - 1).to_string(), Sendable::value_to_data(v)?); } Value::String(s) => { - let v = match v { - Value::Boolean(b) if b => String::new(), - Value::Boolean(b) if !b => continue, - Value::Integer(i) => i.to_string(), - Value::Number(n) => n.to_string(), - Value::String(s) => s.to_string_lossy().into_owned(), - _ => return Err("invalid value in cmd".into_lua_err()), - }; - named.insert(s.to_str()?.replace('_', "-"), v); + args.insert(s.to_str()?.replace('_', "-"), Sendable::value_to_data(v)?); } _ => return Err("invalid key in cmd".into_lua_err()), } } - Ok((args, named)) - } - - #[inline] - fn create_cmd(name: String, table: Table, data: Option) -> mlua::Result { - let (args, named) = Self::parse_args(table)?; - let mut cmd = Cmd { name, args, named, ..Default::default() }; - - if let Some(data) = data.and_then(|v| ValueSendable::try_from(v).ok()) { - cmd = cmd.with_data(data); - } - Ok(cmd) + Ok(args) } pub(super) fn call(lua: &Lua, ya: &Table) -> mlua::Result<()> { @@ -60,16 +35,16 @@ impl Utils { ya.raw_set( "app_emit", - lua.create_function(|_, (name, table, data): (String, Table, Option)| { - emit!(Call(Self::create_cmd(name, table, data)?, Layer::App)); + lua.create_function(|_, (name, args): (String, Table)| { + emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::App)); Ok(()) })?, )?; ya.raw_set( "manager_emit", - lua.create_function(|_, (name, table, data): (String, Table, Option)| { - emit!(Call(Self::create_cmd(name, table, data)?, Layer::Manager)); + lua.create_function(|_, (name, args): (String, Table)| { + emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Manager)); Ok(()) })?, )?; diff --git a/yazi-plugin/src/utils/layer.rs b/yazi-plugin/src/utils/layer.rs index 90bff80a4..0ed0335da 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -37,7 +37,7 @@ impl Utils { let cand = cand?; cands.push(Control { on: Self::parse_keys(cand.raw_get("on")?)?, - run: vec![Cmd::args("callback", vec![i.to_string()]).with_data(tx.clone())], + run: vec![Cmd::args("callback", vec![i.to_string()]).with_any("tx", tx.clone())], desc: cand.raw_get("desc").ok(), }); } @@ -46,8 +46,8 @@ impl Utils { emit!(Call( Cmd::new("show") .with("layer", Layer::Which) - .with_bool("silent", t.raw_get("silent").unwrap_or_default()) - .with_data(cands), + .with_any("candidates", cands) + .with_bool("silent", t.raw_get("silent").unwrap_or_default()), Layer::Which )); diff --git a/yazi-plugin/src/utils/preview.rs b/yazi-plugin/src/utils/preview.rs index 54eec6973..73a6aed99 100644 --- a/yazi-plugin/src/utils/preview.rs +++ b/yazi-plugin/src/utils/preview.rs @@ -44,7 +44,7 @@ impl Utils { }; lock.data = vec![Box::new(Paragraph { area: *area, text, ..Default::default() })]; - emit!(Call(Cmd::new("preview").with_data(lock), Layer::Manager)); + emit!(Call(Cmd::new("preview").with_any("lock", lock), Layer::Manager)); (true, Value::Nil).into_lua_multi(lua) })?, )?; @@ -67,7 +67,7 @@ impl Utils { ..Default::default() })]; - emit!(Call(Cmd::new("preview").with_data(lock), Layer::Manager)); + emit!(Call(Cmd::new("preview").with_any("lock", lock), Layer::Manager)); (true, Value::Nil).into_lua_multi(lua) })?, )?; @@ -78,7 +78,7 @@ impl Utils { let mut lock = PreviewLock::try_from(t)?; lock.data = widgets.into_iter().filter_map(cast_to_renderable).collect(); - emit!(Call(Cmd::new("preview").with_data(lock), Layer::Manager)); + emit!(Call(Cmd::new("preview").with_any("lock", lock), Layer::Manager)); Ok(()) })?, )?; diff --git a/yazi-plugin/src/utils/sync.rs b/yazi-plugin/src/utils/sync.rs index 55fd6b90d..667c3f44f 100644 --- a/yazi-plugin/src/utils/sync.rs +++ b/yazi-plugin/src/utils/sync.rs @@ -1,10 +1,10 @@ use mlua::{ExternalError, ExternalResult, Function, IntoLua, Lua, Table, Value, Variadic}; use tokio::sync::oneshot; -use yazi_dds::ValueSendable; -use yazi_shared::{emit, event::Cmd, Layer}; +use yazi_dds::Sendable; +use yazi_shared::{emit, event::{Cmd, Data}, Layer}; use super::Utils; -use crate::{loader::LOADER, runtime::RtRef, OptData}; +use crate::{loader::LOADER, runtime::RtRef, OptCallback}; impl Utils { pub(super) fn sync(lua: &'static Lua, ya: &Table) -> mlua::Result<()> { @@ -37,7 +37,7 @@ impl Utils { return Err("`ya.sync()` must be called in a plugin").into_lua_err(); }; - Self::retrieve(cur, block, args).await + Sendable::vec_to_variadic(lua, Self::retrieve(cur, block, args).await?) }) })?, )?; @@ -49,39 +49,37 @@ impl Utils { name: String, calls: usize, args: Variadic>, - ) -> mlua::Result> { - let args = ValueSendable::try_from_variadic(args)?; - let (tx, rx) = oneshot::channel::>(); + ) -> mlua::Result> { + let args = Sendable::variadic_to_vec(args)?; + let (tx, rx) = oneshot::channel::>(); - let data = OptData { - cb: Some({ - let name = name.clone(); - Box::new(move |lua, plugin| { - let Some(block) = lua.named_registry_value::("rt")?.get_block(&name, calls) else { - return Err("sync block not found".into_lua_err()); - }; + let callback: OptCallback = { + let name = name.clone(); + Box::new(move |lua, plugin| { + let Some(block) = lua.named_registry_value::("rt")?.get_block(&name, calls) else { + return Err("sync block not found".into_lua_err()); + }; - let mut self_args = Vec::with_capacity(args.len() + 1); - self_args.push(Value::Table(plugin)); - for arg in args { - self_args.push(arg.into_lua(lua)?); - } + let mut self_args = Vec::with_capacity(args.len() + 1); + self_args.push(Value::Table(plugin)); + for arg in args { + self_args.push(Sendable::data_to_value(lua, arg)?); + } - let values = - ValueSendable::try_from_variadic(block.call(Variadic::from_iter(self_args))?)?; - tx.send(values).map_err(|_| "send failed".into_lua_err()) - }) - }), - ..Default::default() + let values = Sendable::variadic_to_vec(block.call(Variadic::from_iter(self_args))?)?; + tx.send(values).map_err(|_| "send failed".into_lua_err()) + }) }; emit!(Call( - Cmd::args("plugin", vec![name.clone()]).with_bool("sync", true).with_data(data), + Cmd::args("plugin", vec![name.clone()]) + .with_bool("sync", true) + .with_any("callback", callback), Layer::App )); - Ok(Variadic::from_iter(rx.await.map_err(|_| { + rx.await.map_err(|_| { format!("Failed to execute sync block-{calls} in `{name}` plugin").into_lua_err() - })?)) + }) } } diff --git a/yazi-proxy/src/app.rs b/yazi-proxy/src/app.rs index 9b67dfeb3..add883278 100644 --- a/yazi-proxy/src/app.rs +++ b/yazi-proxy/src/app.rs @@ -11,7 +11,7 @@ impl AppProxy { #[inline] pub async fn stop() { let (tx, rx) = oneshot::channel::<()>(); - emit!(Call(Cmd::new("stop").with_data(tx), Layer::App)); + emit!(Call(Cmd::new("stop").with_any("tx", tx), Layer::App)); rx.await.ok(); } @@ -22,13 +22,13 @@ impl AppProxy { #[inline] pub fn notify(opt: NotifyOpt) { - emit!(Call(Cmd::new("notify").with_data(opt), Layer::App)); + emit!(Call(Cmd::new("notify").with_any("option", opt), Layer::App)); } #[inline] pub fn notify_warn(title: &str, content: &str) { emit!(Call( - Cmd::new("notify").with_data(NotifyOpt { + Cmd::new("notify").with_any("option", NotifyOpt { title: title.to_owned(), content: content.to_owned(), level: NotifyLevel::Warn, diff --git a/yazi-proxy/src/input.rs b/yazi-proxy/src/input.rs index 66a7491db..5db825511 100644 --- a/yazi-proxy/src/input.rs +++ b/yazi-proxy/src/input.rs @@ -2,15 +2,13 @@ use tokio::sync::mpsc; use yazi_config::popup::InputCfg; use yazi_shared::{emit, event::Cmd, InputError, Layer}; -use crate::options::InputOpt; - pub struct InputProxy; impl InputProxy { #[inline] pub fn show(cfg: InputCfg) -> mpsc::UnboundedReceiver> { let (tx, rx) = mpsc::unbounded_channel(); - emit!(Call(Cmd::new("show").with_data(InputOpt { cfg, tx }), Layer::Input)); + emit!(Call(Cmd::new("show").with_any("tx", tx).with_any("cfg", cfg), Layer::Input)); rx } diff --git a/yazi-proxy/src/manager.rs b/yazi-proxy/src/manager.rs index f690ed6a6..60088df3f 100644 --- a/yazi-proxy/src/manager.rs +++ b/yazi-proxy/src/manager.rs @@ -25,13 +25,13 @@ impl ManagerProxy { #[inline] pub fn open_do(opt: OpenDoOpt) { - emit!(Call(Cmd::new("open_do").with_data(opt), Layer::Manager)); + emit!(Call(Cmd::new("open_do").with_any("option", opt), Layer::Manager)); } #[inline] pub fn remove_do(targets: Vec, permanently: bool) { emit!(Call( - Cmd::new("remove_do").with_bool("permanently", permanently).with_data(targets), + Cmd::new("remove_do").with_bool("permanently", permanently).with_any("targets", targets), Layer::Manager )); } diff --git a/yazi-proxy/src/options/input.rs b/yazi-proxy/src/options/input.rs deleted file mode 100644 index b524a33c3..000000000 --- a/yazi-proxy/src/options/input.rs +++ /dev/null @@ -1,14 +0,0 @@ -use tokio::sync::mpsc; -use yazi_config::popup::InputCfg; -use yazi_shared::{event::Cmd, InputError}; - -pub struct InputOpt { - pub cfg: InputCfg, - pub tx: mpsc::UnboundedSender>, -} - -impl TryFrom for InputOpt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} diff --git a/yazi-proxy/src/options/mod.rs b/yazi-proxy/src/options/mod.rs index d8b2feb19..ec0de4f47 100644 --- a/yazi-proxy/src/options/mod.rs +++ b/yazi-proxy/src/options/mod.rs @@ -1,11 +1,7 @@ -mod input; mod notify; mod open; mod process; -mod select; -pub use input::*; pub use notify::*; pub use open::*; pub use process::*; -pub use select::*; diff --git a/yazi-proxy/src/options/notify.rs b/yazi-proxy/src/options/notify.rs index a8884d668..d4b109626 100644 --- a/yazi-proxy/src/options/notify.rs +++ b/yazi-proxy/src/options/notify.rs @@ -14,7 +14,7 @@ pub struct NotifyOpt { impl TryFrom for NotifyOpt { type Error = (); - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } + fn try_from(mut c: Cmd) -> Result { c.take_any("option").ok_or(()) } } impl<'a> TryFrom> for NotifyOpt { diff --git a/yazi-proxy/src/options/open.rs b/yazi-proxy/src/options/open.rs index 77ff707db..3e8101b6a 100644 --- a/yazi-proxy/src/options/open.rs +++ b/yazi-proxy/src/options/open.rs @@ -12,7 +12,7 @@ pub struct OpenDoOpt { } impl From for OpenDoOpt { - fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() } + fn from(mut c: Cmd) -> Self { c.take_any("option").unwrap_or_default() } } // --- Open with @@ -24,5 +24,5 @@ pub struct OpenWithOpt { impl TryFrom for OpenWithOpt { type Error = (); - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } + fn try_from(mut c: Cmd) -> Result { c.take_any("option").ok_or(()) } } diff --git a/yazi-proxy/src/options/process.rs b/yazi-proxy/src/options/process.rs index 00daf667a..28b3b8ece 100644 --- a/yazi-proxy/src/options/process.rs +++ b/yazi-proxy/src/options/process.rs @@ -14,5 +14,5 @@ pub struct ProcessExecOpt { impl TryFrom for ProcessExecOpt { type Error = (); - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } + fn try_from(mut c: Cmd) -> Result { c.take_any("option").ok_or(()) } } diff --git a/yazi-proxy/src/options/select.rs b/yazi-proxy/src/options/select.rs deleted file mode 100644 index 0478f4a34..000000000 --- a/yazi-proxy/src/options/select.rs +++ /dev/null @@ -1,14 +0,0 @@ -use tokio::sync::oneshot; -use yazi_config::popup::SelectCfg; -use yazi_shared::event::Cmd; - -pub struct SelectOpt { - pub cfg: SelectCfg, - pub tx: oneshot::Sender>, -} - -impl TryFrom for SelectOpt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} diff --git a/yazi-proxy/src/select.rs b/yazi-proxy/src/select.rs index fd00aca93..76ab61b7c 100644 --- a/yazi-proxy/src/select.rs +++ b/yazi-proxy/src/select.rs @@ -2,15 +2,13 @@ use tokio::sync::oneshot; use yazi_config::popup::SelectCfg; use yazi_shared::{emit, event::Cmd, Layer}; -use crate::options::SelectOpt; - pub struct SelectProxy; impl SelectProxy { #[inline] pub async fn show(cfg: SelectCfg) -> anyhow::Result { let (tx, rx) = oneshot::channel(); - emit!(Call(Cmd::new("show").with_data(SelectOpt { cfg, tx }), Layer::Select)); + emit!(Call(Cmd::new("show").with_any("tx", tx).with_any("cfg", cfg), Layer::Select)); rx.await? } } diff --git a/yazi-proxy/src/tasks.rs b/yazi-proxy/src/tasks.rs index b07bdf2c1..10f0f9cad 100644 --- a/yazi-proxy/src/tasks.rs +++ b/yazi-proxy/src/tasks.rs @@ -11,14 +11,17 @@ pub struct TasksProxy; impl TasksProxy { #[inline] pub fn open_with(targets: Vec, opener: Cow<'static, Opener>) { - emit!(Call(Cmd::new("open_with").with_data(OpenWithOpt { targets, opener }), Layer::Tasks)); + emit!(Call( + Cmd::new("open_with").with_any("option", OpenWithOpt { targets, opener }), + Layer::Tasks + )); } #[inline] pub async fn process_exec(args: Vec, opener: Cow<'static, Opener>) { let (tx, rx) = oneshot::channel(); emit!(Call( - Cmd::new("process_exec").with_data(ProcessExecOpt { args, opener, done: tx }), + Cmd::new("process_exec").with_any("option", ProcessExecOpt { args, opener, done: tx }), Layer::Tasks )); rx.await.ok(); diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs index 4a9fb53cd..64f9d3f04 100644 --- a/yazi-scheduler/src/file/file.rs +++ b/yazi-scheduler/src/file/file.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, collections::VecDeque, fs::Metadata, path::{Path, PathBuf}}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use futures::{future::BoxFuture, FutureExt}; use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc}; use tracing::warn; @@ -51,9 +51,10 @@ impl File { if task.retry < TASKS.bizarre_retry && matches!(e.raw_os_error(), Some(1) | Some(93)) => { - self.log(task.id, format!("Paste task retry: {:?}", task))?; task.retry += 1; - return Ok(self.macro_.send(FileOp::Paste(task).into(), LOW).await?); + self.log(task.id, format!("Paste task retry: {:?}", task))?; + self.queue(FileOp::Paste(task), LOW).await?; + return Ok(()); } Err(e) => Err(e)?, } @@ -147,9 +148,9 @@ impl File { self.prog.send(TaskProg::New(id, meta.len()))?; if meta.is_file() { - self.macro_.send(FileOp::Paste(task).into(), LOW).await?; + self.queue(FileOp::Paste(task), LOW).await?; } else if meta.is_symlink() { - self.macro_.send(FileOp::Link(task.to_link(meta)).into(), NORMAL).await?; + self.queue(FileOp::Link(task.to_link(meta)), NORMAL).await?; } return self.succ(id); } @@ -193,9 +194,9 @@ impl File { self.prog.send(TaskProg::New(task.id, meta.len()))?; if meta.is_file() { - self.macro_.send(FileOp::Paste(task.clone()).into(), LOW).await?; + self.queue(FileOp::Paste(task.clone()), LOW).await?; } else if meta.is_symlink() { - self.macro_.send(FileOp::Link(task.to_link(meta)).into(), NORMAL).await?; + self.queue(FileOp::Link(task.to_link(meta)), NORMAL).await?; } } } @@ -209,7 +210,7 @@ impl File { } self.prog.send(TaskProg::New(id, task.meta.as_ref().unwrap().len()))?; - self.macro_.send(FileOp::Link(task).into(), NORMAL).await?; + self.queue(FileOp::Link(task), NORMAL).await?; self.succ(id) } @@ -219,7 +220,7 @@ impl File { let id = task.id; task.length = meta.len(); self.prog.send(TaskProg::New(id, meta.len()))?; - self.macro_.send(FileOp::Delete(task).into(), NORMAL).await?; + self.queue(FileOp::Delete(task), NORMAL).await?; return self.succ(id); } @@ -238,7 +239,7 @@ impl File { task.target = Url::from(entry.path()); task.length = meta.len(); self.prog.send(TaskProg::New(task.id, meta.len()))?; - self.macro_.send(FileOp::Delete(task.clone()).into(), NORMAL).await?; + self.queue(FileOp::Delete(task.clone()), NORMAL).await?; } } self.succ(task.id) @@ -249,7 +250,7 @@ impl File { task.length = calculate_size(&task.target).await; self.prog.send(TaskProg::New(id, task.length))?; - self.macro_.send(FileOp::Trash(task).into(), LOW).await?; + self.queue(FileOp::Trash(task), LOW).await?; self.succ(id) } @@ -296,6 +297,11 @@ impl File { fn log(&self, id: usize, line: String) -> Result<()> { Ok(self.prog.send(TaskProg::Log(id, line))?) } + + #[inline] + async fn queue(&self, op: impl Into, priority: u8) -> Result<()> { + self.macro_.send(op.into(), priority).await.map_err(|_| anyhow!("Failed to send task")) + } } impl FileOpPaste { diff --git a/yazi-scheduler/src/plugin/op.rs b/yazi-scheduler/src/plugin/op.rs index ef6c32146..bac6d530d 100644 --- a/yazi-scheduler/src/plugin/op.rs +++ b/yazi-scheduler/src/plugin/op.rs @@ -1,4 +1,4 @@ -use yazi_dds::ValueSendable; +use yazi_shared::event::Data; #[derive(Debug)] pub enum PluginOp { @@ -17,5 +17,5 @@ impl PluginOp { pub struct PluginOpEntry { pub id: usize, pub name: String, - pub args: Vec, + pub args: Vec, } diff --git a/yazi-scheduler/src/plugin/plugin.rs b/yazi-scheduler/src/plugin/plugin.rs index 2d7f66bd1..f037dd06a 100644 --- a/yazi-scheduler/src/plugin/plugin.rs +++ b/yazi-scheduler/src/plugin/plugin.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; use tokio::sync::mpsc; use yazi_plugin::isolate; @@ -43,7 +43,7 @@ impl Plugin { let id = task.id; self.prog.send(TaskProg::New(id, 0))?; - self.macro_.try_send(PluginOp::Entry(task).into(), HIGH)?; + self.queue(PluginOp::Entry(task), HIGH)?; self.succ(id) } } @@ -56,4 +56,9 @@ impl Plugin { fn fail(&self, id: usize, reason: String) -> Result<()> { Ok(self.prog.send(TaskProg::Fail(id, reason))?) } + + #[inline] + fn queue(&self, op: impl Into, priority: u8) -> Result<()> { + self.macro_.try_send(op.into(), priority).map_err(|_| anyhow!("Failed to send task")) + } } diff --git a/yazi-scheduler/src/preload/preload.rs b/yazi-scheduler/src/preload/preload.rs index 5c73a8fc2..554dd29f0 100644 --- a/yazi-scheduler/src/preload/preload.rs +++ b/yazi-scheduler/src/preload/preload.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use parking_lot::RwLock; use tokio::sync::mpsc; use tracing::error; @@ -73,8 +73,8 @@ impl Preload { self.prog.send(TaskProg::New(id, 0))?; match task.plugin.prio { - Priority::Low => self.macro_.send(PreloadOp::Rule(task).into(), NORMAL).await?, - Priority::Normal => self.macro_.send(PreloadOp::Rule(task).into(), HIGH).await?, + Priority::Low => self.queue(PreloadOp::Rule(task), NORMAL).await?, + Priority::Normal => self.queue(PreloadOp::Rule(task), HIGH).await?, Priority::High => self.work(PreloadOp::Rule(task)).await?, } self.succ(id) @@ -97,4 +97,9 @@ impl Preload { fn fail(&self, id: usize, reason: String) -> Result<()> { Ok(self.prog.send(TaskProg::Fail(id, reason))?) } + + #[inline] + async fn queue(&self, op: impl Into, priority: u8) -> Result<()> { + self.macro_.send(op.into(), priority).await.map_err(|_| anyhow!("Failed to send task")) + } } diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index 8b66556fd..a8390e566 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -4,8 +4,8 @@ use futures::{future::BoxFuture, FutureExt}; use parking_lot::Mutex; use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::JoinHandle}; use yazi_config::{open::Opener, plugin::PluginRule, TASKS}; -use yazi_dds::{Pump, ValueSendable}; -use yazi_shared::{fs::{unique_path, Url}, Throttle}; +use yazi_dds::Pump; +use yazi_shared::{event::Data, fs::{unique_path, Url}, Throttle}; use super::{Ongoing, TaskProg, TaskStage}; use crate::{file::{File, FileOpDelete, FileOpLink, FileOpPaste, FileOpTrash}, plugin::{Plugin, PluginOpEntry}, preload::{Preload, PreloadOpRule, PreloadOpSize}, process::{Process, ProcessOpBg, ProcessOpBlock, ProcessOpOrphan}, TaskKind, TaskOp, HIGH, LOW, NORMAL}; @@ -182,7 +182,7 @@ impl Scheduler { ); } - pub fn plugin_micro(&self, name: String, args: Vec) { + pub fn plugin_micro(&self, name: String, args: Vec) { let id = self.ongoing.lock().add(TaskKind::User, format!("Run micro plugin `{name}`")); let plugin = self.plugin.clone(); @@ -195,7 +195,7 @@ impl Scheduler { ); } - pub fn plugin_macro(&self, name: String, args: Vec) { + pub fn plugin_macro(&self, name: String, args: Vec) { let id = self.ongoing.lock().add(TaskKind::User, format!("Run macro plugin `{name}`")); self.plugin.macro_(PluginOpEntry { id, name, args }).ok(); diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index f37c19418..2ccb08902 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -1,11 +1,11 @@ -use std::{any::Any, collections::HashMap, fmt::{self, Display}, mem}; +use std::{any::Any, collections::HashMap, fmt::{self, Display}}; + +use super::Data; #[derive(Debug, Default)] pub struct Cmd { - pub name: String, - pub args: Vec, - pub named: HashMap, - pub data: Option>, + pub name: String, + pub args: HashMap, } impl Cmd { @@ -14,49 +14,70 @@ impl Cmd { #[inline] pub fn args(name: &str, args: Vec) -> Self { - Self { name: name.to_owned(), args, ..Default::default() } + Self { + name: name.to_owned(), + args: args.into_iter().enumerate().map(|(i, s)| (i.to_string(), Data::String(s))).collect(), + } } #[inline] pub fn with(mut self, name: impl ToString, value: impl ToString) -> Self { - self.named.insert(name.to_string(), value.to_string()); + self.args.insert(name.to_string(), Data::String(value.to_string())); self } #[inline] pub fn with_bool(mut self, name: impl ToString, state: bool) -> Self { - if state { - self.named.insert(name.to_string(), Default::default()); - } + self.args.insert(name.to_string(), Data::Boolean(state)); + self + } + + #[inline] + pub fn with_any(mut self, name: impl ToString, data: impl Any + Send) -> Self { + self.args.insert(name.to_string(), Data::Any(Box::new(data))); self } #[inline] - pub fn with_data(mut self, data: impl Any + Send) -> Self { - self.data = Some(Box::new(data)); + pub fn with_name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); self } #[inline] - pub fn take_data(&mut self) -> Option { - self.data.take().and_then(|d| d.downcast::().ok()).map(|d| *d) + pub fn get_str(&self, name: &str) -> Option<&str> { self.args.get(name).and_then(Data::as_str) } + + #[inline] + pub fn get_bool(&self, name: &str) -> bool { + self.args.get(name).and_then(Data::as_bool).unwrap_or(false) } #[inline] - pub fn take_first(&mut self) -> Option { - if self.args.is_empty() { None } else { Some(mem::take(&mut self.args[0])) } + pub fn take_data(&mut self, name: &str) -> Option { self.args.remove(name) } + + #[inline] + pub fn take_str(&mut self, name: &str) -> Option { + if let Some(Data::String(s)) = self.args.remove(name) { Some(s) } else { None } } #[inline] - pub fn take_name(&mut self, name: &str) -> Option { self.named.remove(name) } + pub fn take_first_str(&mut self) -> Option { + if let Some(Data::String(s)) = self.args.remove("0") { Some(s) } else { None } + } #[inline] - pub fn clone_without_data(&self) -> Self { + pub fn take_any(&mut self, name: &str) -> Option { + self.args.remove(name).and_then(|d| d.into_any()) + } + + pub fn shallow_clone(&self) -> Self { Self { - name: self.name.clone(), - args: self.args.clone(), - named: self.named.clone(), - data: None, + name: self.name.clone(), + args: self + .args + .iter() + .filter_map(|(k, v)| v.shallow_clone().map(|v| (k.clone(), v))) + .collect(), } } } @@ -64,13 +85,15 @@ impl Cmd { impl Display for Cmd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name)?; - if !self.args.is_empty() { - write!(f, " {}", self.args.join(" "))?; - } - for (k, v) in &self.named { - write!(f, " --{k}")?; - if !v.is_empty() { - write!(f, "={v}")?; + for (k, v) in &self.args { + if k.as_bytes().first().is_some_and(|b| b.is_ascii_digit()) { + if let Some(s) = v.as_str() { + write!(f, " {s}")?; + } + } else if v.as_bool().is_some_and(|b| b) { + write!(f, " --{k}")?; + } else if let Some(s) = v.as_str() { + write!(f, " --{k}={s}")?; } } Ok(()) diff --git a/yazi-shared/src/event/data.rs b/yazi-shared/src/event/data.rs new file mode 100644 index 000000000..f545f24e9 --- /dev/null +++ b/yazi-shared/src/event/data.rs @@ -0,0 +1,96 @@ +use std::{any::Any, collections::HashMap}; + +use serde::{Deserialize, Serialize}; + +use crate::{fs::Url, OrderedFloat}; + +// --- Data +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum Data { + Nil, + Boolean(bool), + Integer(i64), + Number(f64), + String(String), + Table(HashMap), + #[serde(skip)] + Url(Url), + #[serde(skip)] + Any(Box), +} + +impl Data { + #[inline] + pub fn as_bool(&self) -> Option { + match self { + Self::Boolean(b) => Some(*b), + _ => None, + } + } + + #[inline] + pub fn as_str(&self) -> Option<&str> { + match self { + Self::String(s) => Some(s), + _ => None, + } + } + + #[inline] + pub fn as_any(&self) -> Option<&T> { + match self { + Self::Any(b) => b.downcast_ref::(), + _ => None, + } + } + + #[inline] + pub fn into_any(self) -> Option { + match self { + Self::Any(b) => b.downcast::().ok().map(|b| *b), + _ => None, + } + } + + pub fn into_table_string(self) -> HashMap { + let Self::Table(table) = self else { + return Default::default(); + }; + + let mut map = HashMap::with_capacity(table.len()); + for pair in table { + if let (DataKey::String(k), Self::String(v)) = pair { + map.insert(k, v); + } + } + map + } + + #[inline] + pub fn shallow_clone(&self) -> Option { + match self { + Self::Boolean(b) => Some(Self::Boolean(*b)), + Self::String(s) => Some(Self::String(s.clone())), + _ => None, + } + } +} + +// --- Key +#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DataKey { + Nil, + Boolean(bool), + Integer(i64), + Number(OrderedFloat), + String(String), + #[serde(skip)] + Url(Url), +} + +impl DataKey { + #[inline] + pub fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) } +} diff --git a/yazi-shared/src/event/mod.rs b/yazi-shared/src/event/mod.rs index 2e32f12fc..4c090ffbe 100644 --- a/yazi-shared/src/event/mod.rs +++ b/yazi-shared/src/event/mod.rs @@ -1,9 +1,11 @@ #![allow(clippy::module_inception)] mod cmd; +mod data; mod event; mod render; pub use cmd::*; +pub use data::*; pub use event::*; pub use render::*; diff --git a/yazi-shared/src/fs/op.rs b/yazi-shared/src/fs/op.rs index 9db7972b9..43c6c6c96 100644 --- a/yazi-shared/src/fs/op.rs +++ b/yazi-shared/src/fs/op.rs @@ -38,7 +38,7 @@ impl FilesOp { #[inline] pub fn emit(self) { - emit!(Call(Cmd::new("update_files").with_data(self), Layer::Manager)); + emit!(Call(Cmd::new("update_files").with_any("op", self), Layer::Manager)); } pub fn prepare(url: &Url) -> u64 {