From baf062f3b159648d5969dcfb837ea9b48245e153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Thu, 7 Nov 2024 23:08:39 +0800 Subject: [PATCH] feat!: deprecate `--sync` option for the `plugin` command (#1891) --- yazi-fm/src/app/commands/plugin.rs | 43 ++++++----- yazi-fm/src/executor.rs | 8 +-- yazi-plugin/src/external/highlighter.rs | 2 +- yazi-plugin/src/isolate/entry.rs | 2 +- yazi-plugin/src/isolate/fetch.rs | 2 +- yazi-plugin/src/isolate/peek.rs | 15 ++-- yazi-plugin/src/isolate/preload.rs | 2 +- yazi-plugin/src/isolate/seek.rs | 13 ++-- yazi-plugin/src/lib.rs | 2 +- yazi-plugin/src/loader/chunk.rs | 43 +++++++++++ yazi-plugin/src/loader/loader.rs | 96 +++++++++++++++---------- yazi-plugin/src/loader/mod.rs | 2 +- yazi-plugin/src/loader/require.rs | 6 +- yazi-plugin/src/opt.rs | 43 ----------- yazi-plugin/src/utils/sync.rs | 26 +++---- yazi-proxy/src/app.rs | 12 +++- yazi-proxy/src/options/mod.rs | 2 +- yazi-proxy/src/options/plugin.rs | 83 +++++++++++++++++++++ yazi-scheduler/src/plugin/plugin.rs | 2 +- yazi-shared/src/chars.rs | 4 +- yazi-shared/src/event/cmd.rs | 6 -- 21 files changed, 258 insertions(+), 156 deletions(-) create mode 100644 yazi-plugin/src/loader/chunk.rs delete mode 100644 yazi-plugin/src/opt.rs create mode 100644 yazi-proxy/src/options/plugin.rs diff --git a/yazi-fm/src/app/commands/plugin.rs b/yazi-fm/src/app/commands/plugin.rs index 30314420..a1b93d5b 100644 --- a/yazi-fm/src/app/commands/plugin.rs +++ b/yazi-fm/src/app/commands/plugin.rs @@ -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) { - let opt = match opt.try_into() { - Ok(opt) => opt as yazi_plugin::Opt, + pub(crate) fn plugin(&mut self, opt: impl TryInto) { + 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) { + pub(crate) fn plugin_do(&mut self, opt: impl TryInto) { 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::("rt") { Ok(mut r) => r.push(&opt.id), Err(e) => return warn!("{e}"), } defer! { _ = LUA.named_registry_value::("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 { diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 27c27d87..3768a469 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -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), _ => {} } } diff --git a/yazi-plugin/src/external/highlighter.rs b/yazi-plugin/src/external/highlighter.rs index d17e0c15..536bbde0 100644 --- a/yazi-plugin/src/external/highlighter.rs +++ b/yazi-plugin/src/external/highlighter.rs @@ -35,7 +35,7 @@ impl Highlighter { }; let (theme, syntaxes) = SYNTECT.get_or_init(|| fut).await; - (&theme, &syntaxes) + (theme, syntaxes) } #[inline] diff --git a/yazi-plugin/src/isolate/entry.rs b/yazi-plugin/src/isolate/entry.rs index 9fea8604..f4f5ca52 100644 --- a/yazi-plugin/src/isolate/entry.rs +++ b/yazi-plugin/src/isolate/entry.rs @@ -12,7 +12,7 @@ pub async fn entry(name: String, args: Vec) -> 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()); }; diff --git a/yazi-plugin/src/isolate/fetch.rs b/yazi-plugin/src/isolate/fetch.rs index 36863601..e7fa97f2 100644 --- a/yazi-plugin/src/isolate/fetch.rs +++ b/yazi-plugin/src/isolate/fetch.rs @@ -15,7 +15,7 @@ pub async fn fetch(name: &str, files: Vec) -> 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()); }; diff --git a/yazi-plugin/src/isolate/peek.rs b/yazi-plugin/src/isolate/peek.rs index 5d0866d2..afd5204b 100644 --- a/yazi-plugin/src/isolate/peek.rs +++ b/yazi-plugin/src/isolate/peek.rs @@ -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)); } diff --git a/yazi-plugin/src/isolate/preload.rs b/yazi-plugin/src/isolate/preload.rs index cf837367..e7d582bf 100644 --- a/yazi-plugin/src/isolate/preload.rs +++ b/yazi-plugin/src/isolate/preload.rs @@ -12,7 +12,7 @@ pub async fn preload(name: &str, file: yazi_shared::fs::File) -> mlua::Result anyhow::Result<()> { CLIPBOARD.with(<_>::default); diff --git a/yazi-plugin/src/loader/chunk.rs b/yazi-plugin/src/loader/chunk.rs new file mode 100644 index 00000000..4ce71cf7 --- /dev/null +++ b/yazi-plugin/src/loader/chunk.rs @@ -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> 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> for Chunk { + fn from(b: Vec) -> Self { Self::from(Cow::Owned(b)) } +} diff --git a/yazi-plugin/src/loader/loader.rs b/yazi-plugin/src/loader/loader.rs index 030210e3..989dac93 100644 --- a/yazi-plugin/src/loader/loader.rs +++ b/yazi-plugin/src/loader/loader.rs @@ -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 = RoCell::new(); -#[derive(Default)] pub struct Loader { - cache: RwLock>>, + cache: RwLock>, +} + +impl Deref for Loader { + type Target = RwLock>; + + #[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>>; + pub fn try_load<'a>(&self, lua: &'a Lua, id: &str) -> mlua::Result> { + 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> { + 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) + } } diff --git a/yazi-plugin/src/loader/mod.rs b/yazi-plugin/src/loader/mod.rs index e81e9464..0aa7a9ae 100644 --- a/yazi-plugin/src/loader/mod.rs +++ b/yazi-plugin/src/loader/mod.rs @@ -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); } diff --git a/yazi-plugin/src/loader/require.rs b/yazi-plugin/src/loader/require.rs index 5f29f3bf..d3510d12 100644 --- a/yazi-plugin/src/loader/require.rs +++ b/yazi-plugin/src/loader/require.rs @@ -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) }) } } diff --git a/yazi-plugin/src/opt.rs b/yazi-plugin/src/opt.rs deleted file mode 100644 index 38615e6c..00000000 --- a/yazi-plugin/src/opt.rs +++ /dev/null @@ -1,43 +0,0 @@ -use anyhow::bail; -use mlua::{Lua, Table}; -use yazi_shared::event::{Cmd, Data}; - -pub(super) type OptCallback = Box mlua::Result<()> + Send>; - -#[derive(Default)] -pub struct Opt { - pub id: String, - pub sync: bool, - pub args: Vec, - pub cb: Option, -} - -impl TryFrom for Opt { - type Error = anyhow::Error; - - fn try_from(mut c: Cmd) -> Result { - 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::>("args").unwrap_or_default() - }; - - Ok(Self { id, sync: c.bool("sync"), args, cb: c.take_any("callback") }) - } -} - -impl From 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 - } -} diff --git a/yazi-plugin/src/utils/sync.rs b/yazi-plugin/src/utils/sync.rs index 2314e3e0..3bddf3de 100644 --- a/yazi-plugin/src/utils/sync.rs +++ b/yazi-plugin/src/utils/sync.rs @@ -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> { + async fn retrieve(id: &str, calls: usize, args: MultiValue<'_>) -> mlua::Result> { let args = Sendable::values_to_vec(args)?; let (tx, rx) = oneshot::channel::>(); - 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::("rt")?.get_block(&name, calls) else { + let Some(block) = lua.named_registry_value::("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()) } } diff --git a/yazi-proxy/src/app.rs b/yazi-proxy/src/app.rs index 49845904..bef61e18 100644 --- a/yazi-proxy/src/app.rs +++ b/yazi-proxy/src/app.rs @@ -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)); + } } diff --git a/yazi-proxy/src/options/mod.rs b/yazi-proxy/src/options/mod.rs index 8750391f..c97e1a26 100644 --- a/yazi-proxy/src/options/mod.rs +++ b/yazi-proxy/src/options/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(notify open process search); +yazi_macro::mod_flat!(notify open plugin process search); diff --git a/yazi-proxy/src/options/plugin.rs b/yazi-proxy/src/options/plugin.rs new file mode 100644 index 00000000..77a19f2b --- /dev/null +++ b/yazi-proxy/src/options/plugin.rs @@ -0,0 +1,83 @@ +use anyhow::bail; +use mlua::{Lua, Table}; +use yazi_shared::event::{Cmd, Data}; + +pub type PluginCallback = Box mlua::Result<()> + Send>; + +#[derive(Default)] +pub struct PluginOpt { + pub id: String, + pub mode: PluginMode, + pub args: Vec, + pub cb: Option, +} + +impl TryFrom for PluginOpt { + type Error = anyhow::Error; + + fn try_from(mut c: Cmd) -> Result { + 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 } + } +} diff --git a/yazi-scheduler/src/plugin/plugin.rs b/yazi-scheduler/src/plugin/plugin.rs index eb6fdf3d..dd37705e 100644 --- a/yazi-scheduler/src/plugin/plugin.rs +++ b/yazi-scheduler/src/plugin/plugin.rs @@ -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))?; diff --git a/yazi-shared/src/chars.rs b/yazi-shared/src/chars.rs index 08f34dcb..6359540a 100644 --- a/yazi-shared/src/chars.rs +++ b/yazi-shared/src/chars.rs @@ -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'^'); diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index 251adb41..181962c5 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -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) }