This commit is contained in:
sxyazi 2024-04-17 19:34:55 +08:00
parent 8ed0def9c6
commit fd5cf1aad7
No known key found for this signature in database
15 changed files with 133 additions and 174 deletions

View file

@ -2,7 +2,7 @@ use std::{fmt, mem};
use anyhow::{bail, Result};
use serde::{de::{self, Visitor}, Deserializer};
use yazi_shared::event::{Arg, Cmd};
use yazi_shared::event::{Cmd, Data};
pub(super) fn run_deserialize<'de, D>(deserializer: D) -> Result<Vec<Cmd>, D::Error>
where
@ -19,16 +19,16 @@ where
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("--") {
cmd.args.insert(i.to_string(), Arg::String(arg));
cmd.args.insert(i.to_string(), Data::String(arg));
continue;
}
let mut parts = arg.splitn(2, '=');
let key = parts.next().unwrap().trim_start_matches('-').to_owned();
if let Some(val) = parts.next() {
cmd.args.insert(key, Arg::String(val.to_owned()));
cmd.args.insert(key, Data::String(val.to_owned()));
} else {
cmd.args.insert(key, Arg::Boolean(true));
cmd.args.insert(key, Data::Boolean(true));
}
}
Ok(cmd)

View file

@ -1,12 +1,11 @@
use std::collections::HashMap;
use yazi_dds::ValueSendable;
use yazi_shared::{event::Cmd, fs::Url, render};
use yazi_shared::{event::{Cmd, Data}, fs::Url, render};
use crate::{manager::{Manager, LINKED}, tasks::Tasks};
pub struct Opt {
data: ValueSendable,
data: Data,
}
impl TryFrom<Cmd> for Opt {

View file

@ -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<ValueSendable>) {
pub fn plugin_micro(&self, name: String, args: Vec<Data>) {
self.scheduler.plugin_micro(name, args);
}
#[inline]
pub fn plugin_macro(&self, name: String, args: Vec<ValueSendable>) {
pub fn plugin_macro(&self, name: String, args: Vec<Data>) {
self.scheduler.plugin_macro(name, args);
}
}

View file

@ -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<Body<'static>> {
Ok(Self { kind: kind.to_owned(), value: serde_json::from_str(value)? }.into())
pub fn from_str(kind: &str, data: &str) -> anyhow::Result<Body<'static>> {
Ok(Self { kind: kind.to_owned(), data: serde_json::from_str(data)? }.into())
}
#[inline]
pub fn from_lua(kind: &str, value: Value) -> mlua::Result<Body<'static>> {
Ok(Self { kind: kind.to_owned(), value: value.try_into()? }.into())
pub fn from_lua(kind: &str, data: Value) -> mlua::Result<Body<'static>> {
Ok(Self { kind: kind.to_owned(), data: Sendable::value_to_data(data)? }.into())
}
}
@ -27,11 +28,11 @@ impl From<BodyCustom> for Body<'_> {
}
impl IntoLua<'_> for BodyCustom {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { self.value.into_lua(lua) }
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { Sendable::data_to_value(lua, self.data) }
}
impl Serialize for BodyCustom {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serde::Serialize::serialize(&self.value, serializer)
serde::Serialize::serialize(&self.data, serializer)
}
}

View file

@ -1,62 +1,26 @@
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<ValueSendableKey, ValueSendable>),
}
pub struct Sendable;
impl ValueSendable {
pub fn try_from_variadic(values: Variadic<Value>) -> mlua::Result<Vec<Self>> {
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<String, String> {
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<Value<'a>> for ValueSendable {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
impl Sendable {
pub fn value_to_data(value: Value) -> mlua::Result<Data> {
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)?);
for result in t.pairs::<Value, Value>() {
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())?,
@ -64,66 +28,72 @@ impl<'a> TryFrom<Value<'a>> for ValueSendable {
Value::Error(_) => Err("error is not supported".into_lua_err())?,
})
}
}
impl IntoLua<'_> for ValueSendable {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
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) => {
pub fn value_to_key(value: Value) -> mlua::Result<DataKey> {
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(_) => Err("userdata is not supported".into_lua_err())?,
Value::Error(_) => Err("error is not supported".into_lua_err())?,
})
}
pub fn data_to_value(lua: &Lua, data: Data) -> mlua::Result<Value> {
match data {
Data::Nil => Ok(Value::Nil),
Data::Boolean(v) => Ok(Value::Boolean(v)),
Data::Integer(v) => Ok(Value::Integer(v)),
Data::Number(v) => Ok(Value::Number(v)),
Data::String(v) => Ok(Value::String(lua.create_string(v)?)),
Data::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)?;
table.raw_set(Self::key_to_value(lua, k)?, Self::data_to_value(lua, v)?)?;
}
Ok(Value::Table(table))
}
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValueSendableKey {
Nil,
Boolean(bool),
Integer(i64),
Number(OrderedFloat),
String(String),
}
impl ValueSendableKey {
#[inline]
fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) }
}
impl TryInto<ValueSendableKey> for ValueSendable {
type Error = mlua::Error;
fn try_into(self) -> Result<ValueSendableKey, Self::Error> {
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())?,
})
}
}
impl IntoLua<'_> for ValueSendableKey {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
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)?)),
pub fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> {
match key {
DataKey::Nil => Ok(Value::Nil),
DataKey::Boolean(k) => Ok(Value::Boolean(k)),
DataKey::Integer(k) => Ok(Value::Integer(k)),
DataKey::Number(k) => Ok(Value::Number(k.get())),
DataKey::String(k) => Ok(Value::String(lua.create_string(k)?)),
}
}
pub fn vec_to_table(lua: &Lua, data: Vec<Data>) -> mlua::Result<Table> {
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)
}
pub fn vec_to_variadic(lua: &Lua, data: Vec<Data>) -> mlua::Result<Variadic<Value>> {
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))
}
pub fn variadic_to_vec(values: Variadic<Value>) -> mlua::Result<Vec<Data>> {
let mut vec = Vec::with_capacity(values.len());
for value in values {
vec.push(Self::value_to_data(value)?);
}
Ok(vec)
}
}

View file

@ -3,6 +3,7 @@ use std::fmt::Display;
use mlua::TableExt;
use scopeguard::defer;
use tracing::warn;
use yazi_dds::Sendable;
use yazi_plugin::{loader::LOADER, OptData, RtRef, LUA};
use yazi_shared::{emit, event::Cmd, Layer};
@ -56,7 +57,7 @@ impl App {
if let Some(cb) = opt.data.cb {
cb(&LUA, plugin)
} else {
plugin.call_method("entry", opt.data.args)
plugin.call_method("entry", Sendable::vec_to_table(&LUA, opt.data.args)?)
}
});
}

View file

@ -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<ValueSendable>) -> mlua::Result<()> {
pub async fn entry(name: String, args: Vec<Data>) -> 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<ValueSendable>) -> 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()?

View file

@ -1,7 +1,6 @@
use anyhow::bail;
use mlua::{Lua, Table};
use yazi_dds::ValueSendable;
use yazi_shared::event::Cmd;
use yazi_shared::event::{Cmd, Data};
pub struct Opt {
pub name: String,
@ -11,7 +10,7 @@ pub struct Opt {
#[derive(Default)]
pub struct OptData {
pub args: Vec<ValueSendable>,
pub args: Vec<Data>,
pub cb: Option<Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send>>,
}
@ -26,7 +25,7 @@ impl TryFrom<Cmd> for Opt {
let mut data: OptData = c.take_data().unwrap_or_default();
if let Some(args) = c.get_str("args") {
data.args = shell_words::split(args)?.into_iter().map(ValueSendable::String).collect();
data.args = shell_words::split(args)?.into_iter().map(Data::String).collect();
}
Ok(Self { name, sync: c.get_bool("sync"), data })

View file

@ -1,7 +1,6 @@
use std::collections::HashMap;
use mlua::{ExternalError, Lua, Table, Value};
use yazi_dds::ValueSendable;
use yazi_shared::{emit, event::Cmd, render, Layer};
use super::Utils;

View file

@ -1,7 +1,7 @@
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};
@ -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,9 +49,9 @@ impl Utils {
name: String,
calls: usize,
args: Variadic<Value<'_>>,
) -> mlua::Result<mlua::Variadic<ValueSendable>> {
let args = ValueSendable::try_from_variadic(args)?;
let (tx, rx) = oneshot::channel::<Vec<ValueSendable>>();
) -> mlua::Result<Vec<Data>> {
let args = Sendable::variadic_to_vec(args)?;
let (tx, rx) = oneshot::channel::<Vec<Data>>();
let data = OptData {
cb: Some({
@ -64,11 +64,10 @@ impl Utils {
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)?);
self_args.push(Sendable::data_to_value(lua, arg)?);
}
let values =
ValueSendable::try_from_variadic(block.call(Variadic::from_iter(self_args))?)?;
let values = Sendable::variadic_to_vec(block.call(Variadic::from_iter(self_args))?)?;
tx.send(values).map_err(|_| "send failed".into_lua_err())
})
}),
@ -80,8 +79,8 @@ impl Utils {
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()
})?))
})
}
}

View file

@ -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<ValueSendable>,
pub args: Vec<Data>,
}

View file

@ -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<ValueSendable>) {
pub fn plugin_micro(&self, name: String, args: Vec<Data>) {
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<ValueSendable>) {
pub fn plugin_macro(&self, name: String, args: Vec<Data>) {
let id = self.ongoing.lock().add(TaskKind::User, format!("Run macro plugin `{name}`"));
self.plugin.macro_(PluginOpEntry { id, name, args }).ok();

View file

@ -1,11 +1,11 @@
use std::{any::Any, collections::HashMap, fmt::{self, Display}};
use super::Arg;
use super::Data;
#[derive(Debug, Default)]
pub struct Cmd {
pub name: String,
pub args: HashMap<String, Arg>,
pub args: HashMap<String, Data>,
pub data: Option<Box<dyn Any + Send>>,
}
@ -17,20 +17,20 @@ impl Cmd {
pub fn args(name: &str, args: Vec<String>) -> Self {
Self {
name: name.to_owned(),
args: args.into_iter().enumerate().map(|(i, s)| (i.to_string(), Arg::String(s))).collect(),
args: args.into_iter().enumerate().map(|(i, s)| (i.to_string(), Data::String(s))).collect(),
..Default::default()
}
}
#[inline]
pub fn with(mut self, name: impl ToString, value: impl ToString) -> Self {
self.args.insert(name.to_string(), Arg::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 {
self.args.insert(name.to_string(), Arg::Boolean(state));
self.args.insert(name.to_string(), Data::Boolean(state));
self
}
@ -41,11 +41,11 @@ impl Cmd {
}
#[inline]
pub fn get_str(&self, name: &str) -> Option<&str> { self.args.get(name).and_then(Arg::as_str) }
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(Arg::as_bool).unwrap_or(false)
self.args.get(name).and_then(Data::as_bool).unwrap_or(false)
}
#[inline]
@ -55,19 +55,19 @@ impl Cmd {
#[inline]
pub fn take_first_str(&mut self) -> Option<String> {
if let Some(Arg::String(s)) = self.args.remove("0") { Some(s) } else { None }
if let Some(Data::String(s)) = self.args.remove("0") { Some(s) } else { None }
}
#[inline]
pub fn take_name_str(&mut self, name: &str) -> Option<String> {
if let Some(Arg::String(s)) = self.args.remove(name) { Some(s) } else { None }
if let Some(Data::String(s)) = self.args.remove(name) { Some(s) } else { None }
}
pub fn shallow_clone(&self) -> Self {
let args = self
.args
.iter()
.filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), Arg::String(s.to_owned()))))
.filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), Data::String(s.to_owned()))))
.collect();
Self { name: self.name.clone(), args, data: None }

View file

@ -1,6 +1,5 @@
use std::collections::HashMap;
use anyhow::bail;
use serde::{Deserialize, Serialize};
use crate::OrderedFloat;
@ -8,16 +7,16 @@ use crate::OrderedFloat;
// --- Arg
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Arg {
pub enum Data {
Nil,
Boolean(bool),
Integer(i64),
Number(f64),
String(String),
Table(HashMap<ArgKey, Arg>),
Table(HashMap<DataKey, Data>),
}
impl Arg {
impl Data {
#[inline]
pub fn as_bool(&self) -> Option<bool> {
match self {
@ -41,7 +40,7 @@ impl Arg {
let mut map = HashMap::with_capacity(table.len());
for pair in table {
if let (ArgKey::String(k), Self::String(v)) = pair {
if let (DataKey::String(k), Self::String(v)) = pair {
map.insert(k, v);
}
}
@ -52,7 +51,7 @@ impl Arg {
// --- Key
#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ArgKey {
pub enum DataKey {
Nil,
Boolean(bool),
Integer(i64),
@ -60,17 +59,7 @@ pub enum ArgKey {
String(String),
}
impl TryInto<ArgKey> for Arg {
type Error = anyhow::Error;
fn try_into(self) -> Result<ArgKey, Self::Error> {
Ok(match self {
Self::Nil => ArgKey::Nil,
Self::Boolean(v) => ArgKey::Boolean(v),
Self::Integer(v) => ArgKey::Integer(v),
Self::Number(v) => ArgKey::Number(OrderedFloat::new(v)),
Self::String(v) => ArgKey::String(v),
Self::Table(_) => bail!("table is not supported"),
})
}
impl DataKey {
#[inline]
pub fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) }
}

View file

@ -1,11 +1,11 @@
#![allow(clippy::module_inception)]
mod arg;
mod cmd;
mod data;
mod event;
mod render;
pub use arg::*;
pub use cmd::*;
pub use data::*;
pub use event::*;
pub use render::*;