mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat!: deprecate --sync option for the plugin command (#1891)
This commit is contained in:
parent
6001f3c619
commit
baf062f3b1
21 changed files with 258 additions and 156 deletions
|
|
@ -4,56 +4,63 @@ use mlua::TableExt;
|
|||
use scopeguard::defer;
|
||||
use tracing::warn;
|
||||
use yazi_dds::Sendable;
|
||||
use yazi_macro::emit;
|
||||
use yazi_plugin::{LUA, RtRef, loader::LOADER};
|
||||
use yazi_shared::{Layer, event::Cmd};
|
||||
use yazi_proxy::{AppProxy, options::{PluginMode, PluginOpt}};
|
||||
|
||||
use crate::{app::App, lives::Lives};
|
||||
|
||||
impl App {
|
||||
pub(crate) fn plugin(&mut self, opt: impl TryInto<yazi_plugin::Opt, Error = impl Display>) {
|
||||
let opt = match opt.try_into() {
|
||||
Ok(opt) => opt as yazi_plugin::Opt,
|
||||
pub(crate) fn plugin(&mut self, opt: impl TryInto<PluginOpt, Error = impl Display>) {
|
||||
let mut opt = match opt.try_into() {
|
||||
Ok(opt) => opt as PluginOpt,
|
||||
Err(e) => return warn!("{e}"),
|
||||
};
|
||||
|
||||
if !opt.sync {
|
||||
return self.cx.tasks.plugin_micro(opt.id, opt.args);
|
||||
let mut hits = false;
|
||||
if let Some(chunk) = LOADER.read().get(&opt.id) {
|
||||
hits = true;
|
||||
opt.mode = opt.mode.auto_then(chunk.sync_entry);
|
||||
}
|
||||
|
||||
if LOADER.read().contains_key(&opt.id) {
|
||||
if opt.mode == PluginMode::Async {
|
||||
return self.cx.tasks.plugin_micro(opt.id, opt.args);
|
||||
} else if opt.mode == PluginMode::Sync && hits {
|
||||
return self.plugin_do(opt);
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
if LOADER.ensure(&opt.id).await.is_ok() {
|
||||
Self::_plugin_do(opt);
|
||||
AppProxy::plugin_do(opt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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<yazi_plugin::Opt, Error = impl Display>) {
|
||||
pub(crate) fn plugin_do(&mut self, opt: impl TryInto<PluginOpt, Error = impl Display>) {
|
||||
let opt = match opt.try_into() {
|
||||
Ok(opt) => opt as yazi_plugin::Opt,
|
||||
Ok(opt) => opt as PluginOpt,
|
||||
Err(e) => return warn!("{e}"),
|
||||
};
|
||||
|
||||
let loader = LOADER.read();
|
||||
let Some(chunk) = loader.get(&opt.id) else {
|
||||
return warn!("plugin `{}` not found", opt.id);
|
||||
};
|
||||
|
||||
if opt.mode.auto_then(chunk.sync_entry) != PluginMode::Sync {
|
||||
return self.cx.tasks.plugin_micro(opt.id, opt.args);
|
||||
}
|
||||
|
||||
match LUA.named_registry_value::<RtRef>("rt") {
|
||||
Ok(mut r) => r.push(&opt.id),
|
||||
Err(e) => return warn!("{e}"),
|
||||
}
|
||||
defer! { _ = LUA.named_registry_value::<RtRef>("rt").map(|mut r| r.pop()) }
|
||||
|
||||
let plugin = match LOADER.load(&LUA, &opt.id) {
|
||||
let plugin = match LOADER.load_with(&LUA, &opt.id, chunk) {
|
||||
Ok(plugin) => plugin,
|
||||
Err(e) => return warn!("{e}"),
|
||||
};
|
||||
drop(loader);
|
||||
|
||||
_ = Lives::scope(&self.cx, |_| {
|
||||
if let Some(cb) = opt.cb {
|
||||
|
|
|
|||
|
|
@ -141,13 +141,13 @@ impl<'a> Executor<'a> {
|
|||
on!(TABS, switch);
|
||||
on!(TABS, swap);
|
||||
|
||||
match cmd.name.as_bytes() {
|
||||
match cmd.name.as_str() {
|
||||
// Tasks
|
||||
b"tasks_show" => self.app.cx.tasks.toggle(()),
|
||||
"tasks_show" => self.app.cx.tasks.toggle(()),
|
||||
// Help
|
||||
b"help" => self.app.cx.help.toggle(Layer::Manager),
|
||||
"help" => self.app.cx.help.toggle(Layer::Manager),
|
||||
// Plugin
|
||||
b"plugin" => self.app.plugin(cmd),
|
||||
"plugin" => self.app.plugin(cmd),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
yazi-plugin/src/external/highlighter.rs
vendored
2
yazi-plugin/src/external/highlighter.rs
vendored
|
|
@ -35,7 +35,7 @@ impl Highlighter {
|
|||
};
|
||||
|
||||
let (theme, syntaxes) = SYNTECT.get_or_init(|| fut).await;
|
||||
(&theme, &syntaxes)
|
||||
(theme, syntaxes)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub async fn entry(name: String, args: Vec<Data>) -> mlua::Result<()> {
|
|||
tokio::task::spawn_blocking(move || {
|
||||
let lua = slim_lua(&name)?;
|
||||
let plugin: Table = if let Some(b) = LOADER.read().get(&name) {
|
||||
lua.load(b.as_ref()).set_name(name).call(())?
|
||||
lua.load(b.as_bytes()).set_name(name).call(())?
|
||||
} else {
|
||||
return Err("unloaded plugin".into_lua_err());
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub async fn fetch(name: &str, files: Vec<yazi_shared::fs::File>) -> mlua::Resul
|
|||
tokio::task::spawn_blocking(move || {
|
||||
let lua = slim_lua(&name)?;
|
||||
let plugin: Table = if let Some(b) = LOADER.read().get(&name) {
|
||||
lua.load(b.as_ref()).set_name(name).call(())?
|
||||
lua.load(b.as_bytes()).set_name(name).call(())?
|
||||
} else {
|
||||
return Err("unloaded plugin".into_lua_err());
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use tokio::{runtime::Handle, select};
|
|||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::error;
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_macro::emit;
|
||||
use yazi_shared::{Layer, event::Cmd};
|
||||
use yazi_proxy::{AppProxy, options::{PluginCallback, PluginOpt}};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use super::slim_lua;
|
||||
use crate::{LUA, Opt, OptCallback, bindings::{Cast, Window}, elements::Rect, file::File, loader::LOADER};
|
||||
use crate::{LUA, bindings::{Cast, Window}, elements::Rect, file::File, loader::LOADER};
|
||||
|
||||
pub fn peek(
|
||||
cmd: &Cmd,
|
||||
|
|
@ -34,7 +34,7 @@ pub fn peek(
|
|||
);
|
||||
|
||||
let plugin: Table = if let Some(b) = LOADER.read().get(&name) {
|
||||
lua.load(b.as_ref()).set_name(name).call(())?
|
||||
lua.load(b.as_bytes()).set_name(name).call(())?
|
||||
} else {
|
||||
return Err("unloaded plugin".into_lua_err());
|
||||
};
|
||||
|
|
@ -65,7 +65,7 @@ pub fn peek(
|
|||
}
|
||||
|
||||
pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, mime: Cow<'static, str>, skip: usize) {
|
||||
let cb: OptCallback = Box::new(move |_, plugin| {
|
||||
let cb: PluginCallback = Box::new(move |_, plugin| {
|
||||
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
||||
plugin.raw_set("_mime", mime)?;
|
||||
plugin.raw_set("skip", skip)?;
|
||||
|
|
@ -74,8 +74,5 @@ pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, mime: Cow<'static, str>
|
|||
plugin.call_method("peek", ())
|
||||
});
|
||||
|
||||
let cmd: Cmd =
|
||||
Opt { id: cmd.name.to_owned(), sync: true, cb: Some(cb), ..Default::default() }.into();
|
||||
|
||||
emit!(Call(cmd.with_name("plugin"), Layer::App));
|
||||
AppProxy::plugin(PluginOpt::new_callback(&cmd.name, cb));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub async fn preload(name: &str, file: yazi_shared::fs::File) -> mlua::Result<u8
|
|||
tokio::task::spawn_blocking(move || {
|
||||
let lua = slim_lua(&name)?;
|
||||
let plugin: Table = if let Some(b) = LOADER.read().get(&name) {
|
||||
lua.load(b.as_ref()).set_name(name).call(())?
|
||||
lua.load(b.as_bytes()).set_name(name).call(())?
|
||||
} else {
|
||||
return Err("unloaded plugin".into_lua_err());
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,16 @@
|
|||
use mlua::TableExt;
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_macro::emit;
|
||||
use yazi_shared::{Layer, event::Cmd};
|
||||
use yazi_proxy::{AppProxy, options::{PluginCallback, PluginOpt}};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::{LUA, Opt, OptCallback, bindings::Cast, elements::Rect, file::File};
|
||||
use crate::{LUA, bindings::Cast, elements::Rect, file::File};
|
||||
|
||||
pub fn seek_sync(cmd: &Cmd, file: yazi_shared::fs::File, units: i16) {
|
||||
let cb: OptCallback = Box::new(move |_, plugin| {
|
||||
let cb: PluginCallback = Box::new(move |_, plugin| {
|
||||
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
||||
plugin.raw_set("area", Rect::from(LAYOUT.get().preview))?;
|
||||
plugin.call_method("seek", units)
|
||||
});
|
||||
|
||||
let cmd: Cmd =
|
||||
Opt { id: cmd.name.to_owned(), sync: true, cb: Some(cb), ..Default::default() }.into();
|
||||
|
||||
emit!(Call(cmd.with_name("plugin"), Layer::App));
|
||||
AppProxy::plugin(PluginOpt::new_callback(&cmd.name, cb));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ yazi_macro::mod_pub!(
|
|||
bindings, cha, elements, external, file, fs, isolate, loader, process, pubsub, url, utils
|
||||
);
|
||||
|
||||
yazi_macro::mod_flat!(cast clipboard config lua opt runtime);
|
||||
yazi_macro::mod_flat!(cast clipboard config lua runtime);
|
||||
|
||||
pub fn init() -> anyhow::Result<()> {
|
||||
CLIPBOARD.with(<_>::default);
|
||||
|
|
|
|||
43
yazi-plugin/src/loader/chunk.rs
Normal file
43
yazi-plugin/src/loader/chunk.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
pub struct Chunk {
|
||||
pub bytes: Cow<'static, [u8]>,
|
||||
pub sync_entry: bool,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] { &self.bytes }
|
||||
|
||||
fn analyze(&mut self) {
|
||||
for line in self.bytes.split(|&b| b == b'\n') {
|
||||
let Some(rest) = line.strip_prefix(b"---") else { break };
|
||||
|
||||
let rest = rest.trim_ascii();
|
||||
let Some(pos) = rest.iter().position(|&b| b == b' ' || b == b'\t') else { break };
|
||||
|
||||
match (rest[..pos].trim_ascii(), rest[pos..].trim_ascii()) {
|
||||
(b"@sync", b"entry") => self.sync_entry = true,
|
||||
(_, []) => break,
|
||||
(b, _) if b.strip_prefix(b"@").unwrap_or(b"").is_empty() => break,
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cow<'static, [u8]>> for Chunk {
|
||||
fn from(b: Cow<'static, [u8]>) -> Self {
|
||||
let mut chunk = Self { bytes: b, sync_entry: false };
|
||||
chunk.analyze();
|
||||
chunk
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static [u8]> for Chunk {
|
||||
fn from(b: &'static [u8]) -> Self { Self::from(Cow::Borrowed(b)) }
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for Chunk {
|
||||
fn from(b: Vec<u8>) -> Self { Self::from(Cow::Owned(b)) }
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, collections::HashMap, ops::Deref};
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use mlua::{ExternalError, Lua, Table};
|
||||
|
|
@ -8,11 +8,45 @@ use yazi_boot::BOOT;
|
|||
use yazi_macro::plugin_preset as preset;
|
||||
use yazi_shared::RoCell;
|
||||
|
||||
use super::Chunk;
|
||||
|
||||
pub static LOADER: RoCell<Loader> = RoCell::new();
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Loader {
|
||||
cache: RwLock<HashMap<String, Cow<'static, [u8]>>>,
|
||||
cache: RwLock<HashMap<String, Chunk>>,
|
||||
}
|
||||
|
||||
impl Deref for Loader {
|
||||
type Target = RwLock<HashMap<String, Chunk>>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { &self.cache }
|
||||
}
|
||||
|
||||
impl Default for Loader {
|
||||
fn default() -> Self {
|
||||
let cache = HashMap::from_iter([
|
||||
("archive".to_owned(), preset!("plugins/archive").into()),
|
||||
("code".to_owned(), preset!("plugins/code").into()),
|
||||
("dds".to_owned(), preset!("plugins/dds").into()),
|
||||
("empty".to_owned(), preset!("plugins/empty").into()),
|
||||
("extract".to_owned(), preset!("plugins/extract").into()),
|
||||
("file".to_owned(), preset!("plugins/file").into()),
|
||||
("folder".to_owned(), preset!("plugins/folder").into()),
|
||||
("font".to_owned(), preset!("plugins/font").into()),
|
||||
("fzf".to_owned(), preset!("plugins/fzf").into()),
|
||||
("image".to_owned(), preset!("plugins/image").into()),
|
||||
("json".to_owned(), preset!("plugins/json").into()),
|
||||
("magick".to_owned(), preset!("plugins/magick").into()),
|
||||
("mime".to_owned(), preset!("plugins/mime").into()),
|
||||
("noop".to_owned(), preset!("plugins/noop").into()),
|
||||
("pdf".to_owned(), preset!("plugins/pdf").into()),
|
||||
("session".to_owned(), preset!("plugins/session").into()),
|
||||
("video".to_owned(), preset!("plugins/video").into()),
|
||||
("zoxide".to_owned(), preset!("plugins/zoxide").into()),
|
||||
]);
|
||||
Self { cache: RwLock::new(cache) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Loader {
|
||||
|
|
@ -21,36 +55,11 @@ impl Loader {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let preset = match name {
|
||||
"archive" => preset!("plugins/archive"),
|
||||
"code" => preset!("plugins/code"),
|
||||
"dds" => preset!("plugins/dds"),
|
||||
"empty" => preset!("plugins/empty"),
|
||||
"extract" => preset!("plugins/extract"),
|
||||
"file" => preset!("plugins/file"),
|
||||
"folder" => preset!("plugins/folder"),
|
||||
"font" => preset!("plugins/font"),
|
||||
"fzf" => preset!("plugins/fzf"),
|
||||
"image" => preset!("plugins/image"),
|
||||
"json" => preset!("plugins/json"),
|
||||
"magick" => preset!("plugins/magick"),
|
||||
"mime" => preset!("plugins/mime"),
|
||||
"noop" => preset!("plugins/noop"),
|
||||
"pdf" => preset!("plugins/pdf"),
|
||||
"session" => preset!("plugins/session"),
|
||||
"video" => preset!("plugins/video"),
|
||||
"zoxide" => preset!("plugins/zoxide"),
|
||||
_ => Default::default(),
|
||||
};
|
||||
let p = BOOT.plugin_dir.join(format!("{name}.yazi/init.lua"));
|
||||
let chunk =
|
||||
fs::read(&p).await.with_context(|| format!("failed to load plugin from {p:?}"))?.into();
|
||||
|
||||
let b = if preset.is_empty() {
|
||||
let p = BOOT.plugin_dir.join(format!("{name}.yazi/init.lua"));
|
||||
Cow::Owned(fs::read(&p).await.with_context(|| format!("failed to load plugin from {p:?}"))?)
|
||||
} else {
|
||||
preset.into()
|
||||
};
|
||||
|
||||
self.cache.write().insert(name.to_owned(), b);
|
||||
self.cache.write().insert(name.to_owned(), chunk);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +70,7 @@ impl Loader {
|
|||
}
|
||||
|
||||
let t: Table = match self.read().get(id) {
|
||||
Some(b) => lua.load(b.as_ref()).set_name(id).call(())?,
|
||||
Some(c) => lua.load(c.as_bytes()).set_name(id).call(())?,
|
||||
None => Err(format!("plugin `{id}` not found").into_lua_err())?,
|
||||
};
|
||||
|
||||
|
|
@ -69,11 +78,22 @@ impl Loader {
|
|||
loaded.raw_set(id, t.clone())?;
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Loader {
|
||||
type Target = RwLock<HashMap<String, Cow<'static, [u8]>>>;
|
||||
pub fn try_load<'a>(&self, lua: &'a Lua, id: &str) -> mlua::Result<Table<'a>> {
|
||||
let loaded: Table = lua.globals().raw_get::<_, Table>("package")?.raw_get("loaded")?;
|
||||
loaded.raw_get(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { &self.cache }
|
||||
pub fn load_with<'a>(&self, lua: &'a Lua, id: &str, chunk: &Chunk) -> mlua::Result<Table<'a>> {
|
||||
let loaded: Table = lua.globals().raw_get::<_, Table>("package")?.raw_get("loaded")?;
|
||||
if let Ok(t) = loaded.raw_get::<_, Table>(id) {
|
||||
return Ok(t);
|
||||
}
|
||||
|
||||
let t: Table = lua.load(chunk.as_bytes()).set_name(id).call(())?;
|
||||
t.raw_set("_id", lua.create_string(id)?)?;
|
||||
|
||||
loaded.raw_set(id, t.clone())?;
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::module_inception)]
|
||||
|
||||
yazi_macro::mod_flat!(loader require);
|
||||
yazi_macro::mod_flat!(chunk loader require);
|
||||
|
||||
pub(super) fn init() { LOADER.with(<_>::default); }
|
||||
|
||||
|
|
|
|||
|
|
@ -103,18 +103,18 @@ impl Require {
|
|||
mut args: MultiValue<'a>,
|
||||
) -> mlua::Result<(Table<'a>, MultiValue<'a>)> {
|
||||
let Some(front) = args.pop_front() else {
|
||||
return Ok((LOADER.load(lua, id)?, args));
|
||||
return Ok((LOADER.try_load(lua, id)?, args));
|
||||
};
|
||||
let Value::Table(tbl) = front else {
|
||||
args.push_front(front);
|
||||
return Ok((LOADER.load(lua, id)?, args));
|
||||
return Ok((LOADER.try_load(lua, id)?, args));
|
||||
};
|
||||
Ok(if let Ok(mod_) = tbl.raw_get::<_, Table>("__mod") {
|
||||
args.push_front(Value::Table(mod_.clone()));
|
||||
(mod_, args)
|
||||
} else {
|
||||
args.push_front(Value::Table(tbl));
|
||||
(LOADER.load(lua, id)?, args)
|
||||
(LOADER.try_load(lua, id)?, args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{Lua, Table};
|
||||
use yazi_shared::event::{Cmd, Data};
|
||||
|
||||
pub(super) type OptCallback = Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Opt {
|
||||
pub id: String,
|
||||
pub sync: bool,
|
||||
pub args: Vec<Data>,
|
||||
pub cb: Option<OptCallback>,
|
||||
}
|
||||
|
||||
impl TryFrom<Cmd> for Opt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||
let Some(id) = c.take_first_str().filter(|s| !s.is_empty()) else {
|
||||
bail!("plugin id cannot be empty");
|
||||
};
|
||||
|
||||
let args = if let Some(s) = c.str("args") {
|
||||
shell_words::split(s)?.into_iter().map(Data::String).collect()
|
||||
} else {
|
||||
c.take_any::<Vec<Data>>("args").unwrap_or_default()
|
||||
};
|
||||
|
||||
Ok(Self { id, sync: c.bool("sync"), args, cb: c.take_any("callback") })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Opt> for Cmd {
|
||||
fn from(value: Opt) -> Self {
|
||||
let mut cmd =
|
||||
Cmd::args("", &[value.id]).with_bool("sync", value.sync).with_any("args", value.args);
|
||||
|
||||
if let Some(cb) = value.cb {
|
||||
cmd = cmd.with_any("callback", cb);
|
||||
}
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use mlua::{ExternalError, ExternalResult, Function, Lua, MultiValue, Table, Value};
|
||||
use tokio::sync::oneshot;
|
||||
use yazi_dds::Sendable;
|
||||
use yazi_macro::emit;
|
||||
use yazi_shared::{Layer, event::{Cmd, Data}};
|
||||
use yazi_proxy::{AppProxy, options::{PluginCallback, PluginOpt}};
|
||||
use yazi_shared::event::Data;
|
||||
|
||||
use super::Utils;
|
||||
use crate::{OptCallback, loader::LOADER, runtime::RtRef};
|
||||
use crate::{loader::LOADER, runtime::RtRef};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn sync(lua: &'static Lua, ya: &Table) -> mlua::Result<()> {
|
||||
|
|
@ -19,7 +19,7 @@ impl Utils {
|
|||
|
||||
let cur = rt.current().unwrap().to_owned();
|
||||
lua.create_function(move |lua, mut args: MultiValue| {
|
||||
args.push_front(Value::Table(LOADER.load(lua, &cur)?));
|
||||
args.push_front(Value::Table(LOADER.try_load(lua, &cur)?));
|
||||
f.call::<_, MultiValue>(args)
|
||||
})
|
||||
})?,
|
||||
|
|
@ -49,14 +49,14 @@ impl Utils {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn retrieve(name: &str, calls: usize, args: MultiValue<'_>) -> mlua::Result<Vec<Data>> {
|
||||
async fn retrieve(id: &str, calls: usize, args: MultiValue<'_>) -> mlua::Result<Vec<Data>> {
|
||||
let args = Sendable::values_to_vec(args)?;
|
||||
let (tx, rx) = oneshot::channel::<Vec<Data>>();
|
||||
|
||||
let callback: OptCallback = {
|
||||
let name = name.to_owned();
|
||||
let callback: PluginCallback = {
|
||||
let id = id.to_owned();
|
||||
Box::new(move |lua, plugin| {
|
||||
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&name, calls) else {
|
||||
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&id, calls) else {
|
||||
return Err("sync block not found".into_lua_err());
|
||||
};
|
||||
|
||||
|
|
@ -70,13 +70,9 @@ impl Utils {
|
|||
})
|
||||
};
|
||||
|
||||
emit!(Call(
|
||||
Cmd::args("plugin", &[name]).with_bool("sync", true).with_any("callback", callback),
|
||||
Layer::App
|
||||
));
|
||||
AppProxy::plugin(PluginOpt::new_callback(id, callback));
|
||||
|
||||
rx.await.map_err(|_| {
|
||||
format!("Failed to execute sync block-{calls} in `{name}` plugin").into_lua_err()
|
||||
})
|
||||
rx.await
|
||||
.map_err(|_| format!("Failed to execute sync block-{calls} in `{id}` plugin").into_lua_err())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use tokio::sync::oneshot;
|
|||
use yazi_macro::emit;
|
||||
use yazi_shared::{Layer, event::Cmd};
|
||||
|
||||
use crate::options::{NotifyLevel, NotifyOpt};
|
||||
use crate::options::{NotifyLevel, NotifyOpt, PluginOpt};
|
||||
|
||||
pub struct AppProxy;
|
||||
|
||||
|
|
@ -45,4 +45,14 @@ impl AppProxy {
|
|||
timeout: Duration::from_secs(10),
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn plugin(opt: PluginOpt) {
|
||||
emit!(Call(Cmd::new("plugin").with_any("opt", opt), Layer::App));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn plugin_do(opt: PluginOpt) {
|
||||
emit!(Call(Cmd::new("plugin_do").with_any("opt", opt), Layer::App));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(notify open process search);
|
||||
yazi_macro::mod_flat!(notify open plugin process search);
|
||||
|
|
|
|||
83
yazi-proxy/src/options/plugin.rs
Normal file
83
yazi-proxy/src/options/plugin.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{Lua, Table};
|
||||
use yazi_shared::event::{Cmd, Data};
|
||||
|
||||
pub type PluginCallback = Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PluginOpt {
|
||||
pub id: String,
|
||||
pub mode: PluginMode,
|
||||
pub args: Vec<Data>,
|
||||
pub cb: Option<PluginCallback>,
|
||||
}
|
||||
|
||||
impl TryFrom<Cmd> for PluginOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||
if let Some(opt) = c.take_any("opt") {
|
||||
return Ok(opt);
|
||||
}
|
||||
|
||||
let Some(id) = c.take_first_str().filter(|s| !s.is_empty()) else {
|
||||
bail!("plugin id cannot be empty");
|
||||
};
|
||||
|
||||
let args = if let Some(s) = c.str("args") {
|
||||
shell_words::split(s)?.into_iter().map(Data::String).collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let mut mode = c.str("mode").map(Into::into).unwrap_or_default();
|
||||
if c.bool("sync") {
|
||||
mode = PluginMode::Sync;
|
||||
let s = "The `--sync` option for the `plugin` command has been deprecated in Yazi v0.4.
|
||||
|
||||
Please add `--- @sync entry` metadata at the head of your `{id}` plugin instead. See #1891 for details: https://github.com/sxyazi/yazi/pull/1891";
|
||||
crate::AppProxy::notify(crate::options::NotifyOpt {
|
||||
title: "Deprecated API".to_owned(),
|
||||
content: s.replace("{id}", &id),
|
||||
level: crate::options::NotifyLevel::Warn,
|
||||
timeout: std::time::Duration::from_secs(20),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Self { id, mode, args, cb: c.take_any("callback") })
|
||||
}
|
||||
}
|
||||
|
||||
impl PluginOpt {
|
||||
pub fn new_callback(id: &str, cb: PluginCallback) -> Self {
|
||||
Self { id: id.to_owned(), mode: PluginMode::Sync, cb: Some(cb), ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
// --- Mode
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PluginMode {
|
||||
#[default]
|
||||
Auto,
|
||||
Sync,
|
||||
Async,
|
||||
}
|
||||
|
||||
impl From<&str> for PluginMode {
|
||||
fn from(s: &str) -> Self {
|
||||
match s {
|
||||
"sync" => Self::Sync,
|
||||
"async" => Self::Async,
|
||||
_ => Self::Auto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PluginMode {
|
||||
pub fn auto_then(self, sync: bool) -> Self {
|
||||
if self != Self::Auto {
|
||||
return self;
|
||||
}
|
||||
if sync { Self::Sync } else { Self::Async }
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ impl Plugin {
|
|||
|
||||
if let Err(e) = isolate::entry(task.name, task.args).await {
|
||||
self.fail(task.id, format!("Micro plugin failed:\n{e}"))?;
|
||||
return Err(e.into());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ pub fn replace_to_printable(s: &[String], tab_size: u8) -> String {
|
|||
match b {
|
||||
b'\n' => buf.push(b'\n'),
|
||||
b'\t' => {
|
||||
for _ in 0..tab_size {
|
||||
buf.push(b' ');
|
||||
}
|
||||
buf.extend((0..tab_size).map(|_| b' '));
|
||||
}
|
||||
b'\0'..=b'\x1F' => {
|
||||
buf.push(b'^');
|
||||
|
|
|
|||
|
|
@ -46,12 +46,6 @@ impl Cmd {
|
|||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// --- Get
|
||||
#[inline]
|
||||
pub fn get(&self, name: &str) -> Option<&Data> { self.args.get(name) }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue