diff --git a/yazi-config/src/keymap/run.rs b/yazi-config/src/keymap/run.rs index 5bc7acbc..65307a9c 100644 --- a/yazi-config/src/keymap/run.rs +++ b/yazi-config/src/keymap/run.rs @@ -10,21 +10,24 @@ where { struct RunVisitor; + #[allow(clippy::explicit_counter_loop)] fn parse(s: &str) -> Result { let mut args = shell_words::split(s)?; - if args.is_empty() { - bail!("`run` cannot be empty"); - } - let mut cmd = Cmd { name: mem::take(&mut args[0]), ..Default::default() }; - for (i, arg) in args.into_iter().skip(1).enumerate() { - if !arg.starts_with("--") { + + 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 key = parts.next().unwrap().trim_start_matches('-').to_owned(); + let Some(key) = parts.next().map(|s| s.to_owned()) else { + bail!("invalid argument: {arg}"); + }; + if let Some(val) = parts.next() { cmd.args.insert(key, Data::String(val.to_owned())); } else { diff --git a/yazi-core/src/completion/commands/show.rs b/yazi-core/src/completion/commands/show.rs index 60c49918..b5b69ebd 100644 --- a/yazi-core/src/completion/commands/show.rs +++ b/yazi-core/src/completion/commands/show.rs @@ -16,9 +16,7 @@ pub struct Opt { impl From for Opt { fn from(mut c: Cmd) -> Self { Self { - // cache: mem::take(&mut c.args), - // TODO: Fix this - cache: vec![], + 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), @@ -65,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 d64bc0fc..7b4a5241 100644 --- a/yazi-core/src/completion/commands/trigger.rs +++ b/yazi-core/src/completion/commands/trigger.rs @@ -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/input/commands/show.rs b/yazi-core/src/input/commands/show.rs index 0e09f77f..1601ca19 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/select/commands/show.rs b/yazi-core/src/select/commands/show.rs index 1b6d6d1f..c273e7dc 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-dds/src/sendable.rs b/yazi-dds/src/sendable.rs index 7f464776..d9957420 100644 --- a/yazi-dds/src/sendable.rs +++ b/yazi-dds/src/sendable.rs @@ -15,7 +15,7 @@ impl Sendable { 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::value_to_key(k)?, Self::value_to_data(v)?); @@ -98,7 +98,13 @@ impl Sendable { 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(_) => Err("userdata 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())?, }) } @@ -110,6 +116,7 @@ impl Sendable { 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-plugin/src/opt.rs b/yazi-plugin/src/opt.rs index 898b1450..87cee4f4 100644 --- a/yazi-plugin/src/opt.rs +++ b/yazi-plugin/src/opt.rs @@ -26,7 +26,7 @@ impl TryFrom for Opt { c.take_any::>("args").unwrap_or_default() }; - Ok(Self { name, sync: c.get_bool("sync"), args, cb: c.take_any::("callback") }) + Ok(Self { name, sync: c.get_bool("sync"), args, cb: c.take_any("callback") }) } } diff --git a/yazi-plugin/src/utils/call.rs b/yazi-plugin/src/utils/call.rs index 3fe96a40..c788aea7 100644 --- a/yazi-plugin/src/utils/call.rs +++ b/yazi-plugin/src/utils/call.rs @@ -1,54 +1,27 @@ use std::collections::HashMap; use mlua::{ExternalError, Lua, Table, Value}; -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, args: Value) -> mlua::Result { - // TODO: Fix this - return Ok(Cmd { name, args: Default::default() }); - - // 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<()> { @@ -62,16 +35,16 @@ impl Utils { ya.raw_set( "app_emit", - lua.create_function(|_, (name, args): (String, Value)| { - emit!(Call(Self::create_cmd(name, args)?, 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, args): (String, Value)| { - emit!(Call(Self::create_cmd(name, args)?, 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 75a720af..0ed0335d 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -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_any("candidates", cands), + .with_any("candidates", cands) + .with_bool("silent", t.raw_get("silent").unwrap_or_default()), Layer::Which )); diff --git a/yazi-proxy/src/input.rs b/yazi-proxy/src/input.rs index 76e23c88..5db82551 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_any("option", 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/options/input.rs b/yazi-proxy/src/options/input.rs deleted file mode 100644 index 7345e5ec..00000000 --- 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_any("option").ok_or(()) } -} diff --git a/yazi-proxy/src/options/mod.rs b/yazi-proxy/src/options/mod.rs index d8b2feb1..ec0de4f4 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/select.rs b/yazi-proxy/src/options/select.rs deleted file mode 100644 index df010c79..00000000 --- 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_any("option").ok_or(()) } -} diff --git a/yazi-proxy/src/select.rs b/yazi-proxy/src/select.rs index e56f8386..76ab61b7 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_any("option", 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-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index e1fc3fb6..2ccb0890 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -71,13 +71,14 @@ impl Cmd { } pub fn shallow_clone(&self) -> Self { - let args = self - .args - .iter() - .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), Data::String(s.to_owned())))) - .collect(); - - Self { name: self.name.clone(), args } + Self { + name: self.name.clone(), + args: self + .args + .iter() + .filter_map(|(k, v)| v.shallow_clone().map(|v| (k.clone(), v))) + .collect(), + } } } diff --git a/yazi-shared/src/event/data.rs b/yazi-shared/src/event/data.rs index 14732efc..f545f24e 100644 --- a/yazi-shared/src/event/data.rs +++ b/yazi-shared/src/event/data.rs @@ -48,7 +48,7 @@ impl Data { #[inline] pub fn into_any(self) -> Option { match self { - Data::Any(b) => b.downcast::().ok().map(|b| *b), + Self::Any(b) => b.downcast::().ok().map(|b| *b), _ => None, } } @@ -66,6 +66,15 @@ impl Data { } 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 @@ -77,6 +86,8 @@ pub enum DataKey { Integer(i64), Number(OrderedFloat), String(String), + #[serde(skip)] + Url(Url), } impl DataKey {