Skip to content

Commit

Permalink
feat!: deprecate --sync option for the plugin command (#1891)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxyazi authored Nov 7, 2024
1 parent 6001f3c commit baf062f
Show file tree
Hide file tree
Showing 21 changed files with 258 additions and 156 deletions.
43 changes: 25 additions & 18 deletions yazi-fm/src/app/commands/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions yazi-fm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
_ => {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion yazi-plugin/src/external/highlighter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Highlighter {
};

let (theme, syntaxes) = SYNTECT.get_or_init(|| fut).await;
(&theme, &syntaxes)
(theme, syntaxes)
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion yazi-plugin/src/isolate/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
};
Expand Down
2 changes: 1 addition & 1 deletion yazi-plugin/src/isolate/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
};
Expand Down
15 changes: 6 additions & 9 deletions yazi-plugin/src/isolate/peek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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());
};
Expand Down Expand Up @@ -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)?;
Expand All @@ -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));
}
2 changes: 1 addition & 1 deletion yazi-plugin/src/isolate/preload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
};
Expand Down
13 changes: 5 additions & 8 deletions yazi-plugin/src/isolate/seek.rs
Original file line number Diff line number Diff line change
@@ -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));
}
2 changes: 1 addition & 1 deletion yazi-plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
43 changes: 43 additions & 0 deletions yazi-plugin/src/loader/chunk.rs
Original file line number Diff line number Diff line change
@@ -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)) }
}
96 changes: 58 additions & 38 deletions yazi-plugin/src/loader/loader.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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 {
Expand All @@ -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(())
}

Expand All @@ -61,19 +70,30 @@ 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())?,
};

t.raw_set("_id", lua.create_string(id)?)?;
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)
}
}
2 changes: 1 addition & 1 deletion yazi-plugin/src/loader/mod.rs
Original file line number Diff line number Diff line change
@@ -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); }

Expand Down
Loading

0 comments on commit baf062f

Please sign in to comment.