This commit is contained in:
sxyazi 2024-04-19 13:40:10 +08:00
parent 79d61248dd
commit 0ebba0f628
No known key found for this signature in database
16 changed files with 97 additions and 111 deletions

View file

@ -10,21 +10,24 @@ where
{ {
struct RunVisitor; struct RunVisitor;
#[allow(clippy::explicit_counter_loop)]
fn parse(s: &str) -> Result<Cmd> { fn parse(s: &str) -> Result<Cmd> {
let mut args = shell_words::split(s)?; 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() }; 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)); cmd.args.insert(i.to_string(), Data::String(arg));
i += 1;
continue; continue;
} };
let mut parts = arg.splitn(2, '='); 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() { if let Some(val) = parts.next() {
cmd.args.insert(key, Data::String(val.to_owned())); cmd.args.insert(key, Data::String(val.to_owned()));
} else { } else {

View file

@ -16,9 +16,7 @@ pub struct Opt {
impl From<Cmd> for Opt { impl From<Cmd> for Opt {
fn from(mut c: Cmd) -> Self { fn from(mut c: Cmd) -> Self {
Self { Self {
// cache: mem::take(&mut c.args), cache: c.take_any("cache").unwrap_or_default(),
// TODO: Fix this
cache: vec![],
cache_name: c.take_str("cache-name").unwrap_or_default(), cache_name: c.take_str("cache-name").unwrap_or_default(),
word: c.take_str("word").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), 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() { 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 { let Some(cache) = self.caches.get(&opt.cache_name) else {
return; return;

View file

@ -57,7 +57,8 @@ impl Completion {
if !cache.is_empty() { if !cache.is_empty() {
emit!(Call( emit!(Call(
Cmd::args("show", cache) Cmd::new("show")
.with_any("cache", cache)
.with("cache-name", parent) .with("cache-name", parent)
.with("word", child) .with("word", child)
.with("ticket", ticket), .with("ticket", ticket),

View file

@ -1,10 +1,24 @@
use yazi_proxy::options::InputOpt; use tokio::sync::mpsc;
use yazi_shared::render; use yazi_config::popup::InputCfg;
use yazi_shared::{event::Cmd, render, InputError};
use crate::input::Input; use crate::input::Input;
pub struct Opt {
cfg: InputCfg,
tx: mpsc::UnboundedSender<Result<String, InputError>>,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self { cfg: c.take_any("cfg").ok_or(())?, tx: c.take_any("tx").ok_or(())? })
}
}
impl Input { impl Input {
pub fn show(&mut self, opt: impl TryInto<InputOpt>) { pub fn show(&mut self, opt: impl TryInto<Opt>) {
let Ok(opt) = opt.try_into() else { return }; let Ok(opt) = opt.try_into() else { return };
self.close(false); self.close(false);

View file

@ -1,10 +1,24 @@
use yazi_proxy::options::SelectOpt; use tokio::sync::oneshot;
use yazi_shared::render; use yazi_config::popup::SelectCfg;
use yazi_shared::{event::Cmd, render};
use crate::select::Select; use crate::select::Select;
pub struct Opt {
cfg: SelectCfg,
tx: oneshot::Sender<anyhow::Result<usize>>,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self { cfg: c.take_any("cfg").ok_or(())?, tx: c.take_any("tx").ok_or(())? })
}
}
impl Select { impl Select {
pub fn show(&mut self, opt: impl TryInto<SelectOpt>) { pub fn show(&mut self, opt: impl TryInto<Opt>) {
let Ok(opt) = opt.try_into() else { let Ok(opt) = opt.try_into() else {
return; return;
}; };

View file

@ -15,7 +15,7 @@ impl Sendable {
Value::Number(n) => Data::Number(n), Value::Number(n) => Data::Number(n),
Value::String(s) => Data::String(s.to_str()?.to_owned()), Value::String(s) => Data::String(s.to_str()?.to_owned()),
Value::Table(t) => { 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::<Value, Value>() { for result in t.pairs::<Value, Value>() {
let (k, v) = result?; let (k, v) = result?;
map.insert(Self::value_to_key(k)?, Self::value_to_data(v)?); 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::Table(_) => Err("table is not supported".into_lua_err())?,
Value::Function(_) => Err("function 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::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::<yazi_shared::fs::Url>() {
DataKey::Url(t)
} else {
Err("unsupported userdata included".into_lua_err())?
}
}
Value::Error(_) => Err("error is not supported".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::Integer(k) => Value::Integer(k),
DataKey::Number(k) => Value::Number(k.get()), DataKey::Number(k) => Value::Number(k.get()),
DataKey::String(k) => Value::String(lua.create_string(k)?), DataKey::String(k) => Value::String(lua.create_string(k)?),
DataKey::Url(k) => Value::UserData(lua.create_any_userdata(k)?),
}) })
} }
} }

View file

@ -26,7 +26,7 @@ impl TryFrom<Cmd> for Opt {
c.take_any::<Vec<Data>>("args").unwrap_or_default() c.take_any::<Vec<Data>>("args").unwrap_or_default()
}; };
Ok(Self { name, sync: c.get_bool("sync"), args, cb: c.take_any::<OptCallback>("callback") }) Ok(Self { name, sync: c.get_bool("sync"), args, cb: c.take_any("callback") })
} }
} }

View file

@ -1,54 +1,27 @@
use std::collections::HashMap; use std::collections::HashMap;
use mlua::{ExternalError, Lua, Table, Value}; 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; use super::Utils;
impl Utils { impl Utils {
fn parse_args(t: Table) -> mlua::Result<(Vec<String>, HashMap<String, String>)> { fn parse_args(t: Table) -> mlua::Result<HashMap<String, Data>> {
let mut args = vec![]; let mut args = HashMap::with_capacity(t.raw_len());
let mut named = HashMap::new(); for pair in t.pairs::<Value, Value>() {
for result in t.pairs::<Value, Value>() { let (k, v) = pair?;
let (k, v) = result?;
match k { match k {
Value::Integer(_) => { Value::Integer(i) if i > 0 => {
args.push(match v { args.insert((i - 1).to_string(), Sendable::value_to_data(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::String(s) => { Value::String(s) => {
let v = match v { args.insert(s.to_str()?.replace('_', "-"), Sendable::value_to_data(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);
} }
_ => return Err("invalid key in cmd".into_lua_err()), _ => return Err("invalid key in cmd".into_lua_err()),
} }
} }
Ok((args, named)) Ok(args)
}
#[inline]
fn create_cmd(name: String, args: Value) -> mlua::Result<Cmd> {
// 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)
} }
pub(super) fn call(lua: &Lua, ya: &Table) -> mlua::Result<()> { pub(super) fn call(lua: &Lua, ya: &Table) -> mlua::Result<()> {
@ -62,16 +35,16 @@ impl Utils {
ya.raw_set( ya.raw_set(
"app_emit", "app_emit",
lua.create_function(|_, (name, args): (String, Value)| { lua.create_function(|_, (name, args): (String, Table)| {
emit!(Call(Self::create_cmd(name, args)?, Layer::App)); emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::App));
Ok(()) Ok(())
})?, })?,
)?; )?;
ya.raw_set( ya.raw_set(
"manager_emit", "manager_emit",
lua.create_function(|_, (name, args): (String, Value)| { lua.create_function(|_, (name, args): (String, Table)| {
emit!(Call(Self::create_cmd(name, args)?, Layer::Manager)); emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Manager));
Ok(()) Ok(())
})?, })?,
)?; )?;

View file

@ -46,8 +46,8 @@ impl Utils {
emit!(Call( emit!(Call(
Cmd::new("show") Cmd::new("show")
.with("layer", Layer::Which) .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 Layer::Which
)); ));

View file

@ -2,15 +2,13 @@ use tokio::sync::mpsc;
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_shared::{emit, event::Cmd, InputError, Layer}; use yazi_shared::{emit, event::Cmd, InputError, Layer};
use crate::options::InputOpt;
pub struct InputProxy; pub struct InputProxy;
impl InputProxy { impl InputProxy {
#[inline] #[inline]
pub fn show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> { pub fn show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> {
let (tx, rx) = mpsc::unbounded_channel(); 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 rx
} }

View file

@ -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<Result<String, InputError>>,
}
impl TryFrom<Cmd> for InputOpt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_any("option").ok_or(()) }
}

View file

@ -1,11 +1,7 @@
mod input;
mod notify; mod notify;
mod open; mod open;
mod process; mod process;
mod select;
pub use input::*;
pub use notify::*; pub use notify::*;
pub use open::*; pub use open::*;
pub use process::*; pub use process::*;
pub use select::*;

View file

@ -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<anyhow::Result<usize>>,
}
impl TryFrom<Cmd> for SelectOpt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_any("option").ok_or(()) }
}

View file

@ -2,15 +2,13 @@ use tokio::sync::oneshot;
use yazi_config::popup::SelectCfg; use yazi_config::popup::SelectCfg;
use yazi_shared::{emit, event::Cmd, Layer}; use yazi_shared::{emit, event::Cmd, Layer};
use crate::options::SelectOpt;
pub struct SelectProxy; pub struct SelectProxy;
impl SelectProxy { impl SelectProxy {
#[inline] #[inline]
pub async fn show(cfg: SelectCfg) -> anyhow::Result<usize> { pub async fn show(cfg: SelectCfg) -> anyhow::Result<usize> {
let (tx, rx) = oneshot::channel(); 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? rx.await?
} }
} }

View file

@ -71,13 +71,14 @@ impl Cmd {
} }
pub fn shallow_clone(&self) -> Self { pub fn shallow_clone(&self) -> Self {
let args = self Self {
.args name: self.name.clone(),
.iter() args: self
.filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), Data::String(s.to_owned())))) .args
.collect(); .iter()
.filter_map(|(k, v)| v.shallow_clone().map(|v| (k.clone(), v)))
Self { name: self.name.clone(), args } .collect(),
}
} }
} }

View file

@ -48,7 +48,7 @@ impl Data {
#[inline] #[inline]
pub fn into_any<T: 'static>(self) -> Option<T> { pub fn into_any<T: 'static>(self) -> Option<T> {
match self { match self {
Data::Any(b) => b.downcast::<T>().ok().map(|b| *b), Self::Any(b) => b.downcast::<T>().ok().map(|b| *b),
_ => None, _ => None,
} }
} }
@ -66,6 +66,15 @@ impl Data {
} }
map map
} }
#[inline]
pub fn shallow_clone(&self) -> Option<Self> {
match self {
Self::Boolean(b) => Some(Self::Boolean(*b)),
Self::String(s) => Some(Self::String(s.clone())),
_ => None,
}
}
} }
// --- Key // --- Key
@ -77,6 +86,8 @@ pub enum DataKey {
Integer(i64), Integer(i64),
Number(OrderedFloat), Number(OrderedFloat),
String(String), String(String),
#[serde(skip)]
Url(Url),
} }
impl DataKey { impl DataKey {