perf: port require() and ya.sync() to Rust to avoid plugin information initialization process (#853)

This commit is contained in:
三咲雅 · Misaki Masa 2024-03-30 22:15:05 +08:00 committed by GitHub
parent 903f3da7e5
commit c240602046
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 310 additions and 152 deletions

View file

@ -1 +1 @@
{"version":"0.2","language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub"]}
{"version":"0.2","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers"],"language":"en","flagWords":[]}

View file

@ -48,11 +48,11 @@ pub struct BodyBulkIter {
}
impl UserData for BodyBulkIter {
fn add_fields<'a, F: mlua::UserDataFields<'a, Self>>(fields: &mut F) {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("tab", |_, me| Ok(me.tab));
}
fn add_methods<'a, M: mlua::UserDataMethods<'a, Self>>(methods: &mut M) {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.inner.len()));
methods.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {

View file

@ -53,7 +53,7 @@ pub struct BodyTabsItem<'a> {
}
impl UserData for BodyTabsItem<'static> {
fn add_fields<'a, F: mlua::UserDataFields<'a, Self>>(fields: &mut F) {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("url", |lua, me| lua.create_any_userdata(me.url.clone()));
}
}
@ -69,11 +69,11 @@ impl From<BodyTabs<'static>> for BodyTabsIter {
}
impl UserData for BodyTabsIter {
fn add_fields<'a, F: mlua::UserDataFields<'a, Self>>(fields: &mut F) {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("cursor", |_, me| Ok(me.cursor));
}
fn add_methods<'a, M: mlua::UserDataMethods<'a, Self>>(methods: &mut M) {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.items.len()));
methods.add_meta_method(MetaMethod::Index, |_, me, idx: usize| {

View file

@ -54,11 +54,11 @@ impl From<BodyYank<'static>> for BodyYankIter {
}
impl UserData for BodyYankIter {
fn add_fields<'a, F: mlua::UserDataFields<'a, Self>>(fields: &mut F) {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("is_cut", |_, me| Ok(me.cut));
}
fn add_methods<'a, M: mlua::UserDataMethods<'a, Self>>(methods: &mut M) {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.urls.len()));
methods.add_meta_method(MetaMethod::Index, |lua, me, idx: usize| {

View file

@ -2,7 +2,7 @@ use std::fmt::Display;
use mlua::TableExt;
use tracing::warn;
use yazi_plugin::{OptData, LOADER, LUA};
use yazi_plugin::{loader::LOADER, OptData, RtRef, LUA};
use yazi_shared::{emit, event::Cmd, Defer, Layer};
use crate::{app::App, lives::Lives};
@ -40,9 +40,12 @@ impl App {
Err(e) => return warn!("{e}"),
};
LOADER.set_running(Some(&opt.name));
let _defer = Defer::new(|| LOADER.set_running(None));
match LUA.named_registry_value::<RtRef>("rt") {
Ok(mut r) => r.swap(&opt.name),
Err(e) => return warn!("{e}"),
}
let _defer = Defer::new(|| LUA.named_registry_value::<RtRef>("rt").map(|mut r| r.reset()));
let plugin = match LOADER.load(&opt.name) {
Ok(plugin) => plugin,
Err(e) => return warn!("{e}"),

View file

@ -1,11 +1 @@
package.path = BOOT.plugin_dir .. "/?.yazi/init.lua;" .. package.path
local _require = require
require = function(name)
YAZI_PLUGIN_NAME, YAZI_SYNC_CALLS = name, 0
local mod = _require(name)
mod._name = name
return mod
end
YAZI_SYNC_BLOCKS = {}

View file

@ -28,19 +28,6 @@ function ya.flat(t)
return r
end
function ya.sync(f)
YAZI_SYNC_CALLS = YAZI_SYNC_CALLS + 1
local name, calls = YAZI_PLUGIN_NAME, YAZI_SYNC_CALLS
if not YAZI_SYNC_BLOCKS then
return function(...) return ya.plugin_retrieve(name, calls, ...) end
end
YAZI_SYNC_BLOCKS[name] = YAZI_SYNC_BLOCKS[name] or {}
YAZI_SYNC_BLOCKS[name][calls] = f
return function(...) return f(package.loaded[name], ...) end
end
function ya.basename(str) return string.gsub(str, "(.*[/\\])(.*)", "%2") end
function ya.readable_size(size)

View file

@ -3,7 +3,7 @@ use tokio::runtime::Handle;
use yazi_dds::ValueSendable;
use super::slim_lua;
use crate::LOADER;
use crate::loader::LOADER;
pub async fn entry(name: String, args: Vec<ValueSendable>) -> mlua::Result<()> {
LOADER.ensure(&name).await.into_lua_err()?;

View file

@ -1,9 +1,10 @@
use mlua::Lua;
use crate::{bindings, elements};
use crate::{bindings, elements, runtime::Runtime};
pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
let lua = Lua::new();
lua.set_named_registry_value("rt", Runtime::new(name))?;
// Base
bindings::Cha::register(&lua)?;
@ -12,7 +13,7 @@ pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
crate::fs::install(&lua)?;
crate::process::install(&lua)?;
crate::utils::install(&lua)?;
crate::utils::install_isolate(&lua)?;
crate::Config::new(&lua).install_preview()?;
lua.load(include_str!("../../preset/ya.lua")).exec()?;
@ -24,12 +25,6 @@ pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
elements::Rect::install(&lua, &ui)?;
elements::Span::install(&lua, &ui)?;
{
let globals = lua.globals();
globals.raw_set("ui", ui)?;
globals.raw_set("YAZI_PLUGIN_NAME", lua.create_string(name)?)?;
globals.raw_set("YAZI_SYNC_CALLS", 0)?;
}
lua.globals().raw_set("ui", ui)?;
Ok(lua)
}

View file

@ -6,7 +6,7 @@ use yazi_config::LAYOUT;
use yazi_shared::{emit, event::Cmd, Layer};
use super::slim_lua;
use crate::{bindings::{Cast, File, Window}, elements::Rect, OptData, LOADER, LUA};
use crate::{bindings::{Cast, File, Window}, elements::Rect, loader::LOADER, OptData, LUA};
pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> CancellationToken {
let ct = CancellationToken::new();

View file

@ -3,7 +3,7 @@ use tokio::runtime::Handle;
use yazi_config::LAYOUT;
use super::slim_lua;
use crate::{bindings::{Cast, File}, elements::Rect, LOADER};
use crate::{bindings::{Cast, File}, elements::Rect, loader::LOADER};
pub async fn preload(
name: &str,

View file

@ -7,18 +7,22 @@ pub mod elements;
pub mod external;
pub mod fs;
pub mod isolate;
mod loader;
pub mod loader;
mod lua;
mod opt;
pub mod process;
pub mod pubsub;
mod runtime;
pub mod url;
pub mod utils;
pub use cast::*;
pub use config::*;
pub use loader::*;
pub use lua::*;
pub use opt::*;
pub use runtime::*;
pub fn init() { crate::init_lua(); }
pub fn init() {
crate::init_lua();
crate::loader::init();
}

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, collections::HashMap, ops::Deref, sync::Arc};
use std::{borrow::Cow, collections::HashMap, ops::Deref};
use anyhow::{bail, Result};
use mlua::{ExternalError, Table};
@ -11,20 +11,12 @@ use crate::LUA;
pub static LOADER: RoCell<Loader> = RoCell::new();
pub(super) static RUNNING: RoCell<arc_swap::ArcSwapOption<String>> = RoCell::new();
#[derive(Default)]
pub struct Loader {
cache: RwLock<HashMap<String, Vec<u8>>>,
}
impl Loader {
#[inline]
pub(super) fn init() {
LOADER.with(Default::default);
RUNNING.with(Default::default);
}
pub async fn ensure(&self, name: &str) -> Result<()> {
if self.cache.read().contains_key(name) {
return Ok(());
@ -33,16 +25,16 @@ impl Loader {
let path = BOOT.plugin_dir.join(format!("{name}.yazi/init.lua"));
let b = fs::read(path).await.map(|v| v.into()).or_else(|_| {
Ok(Cow::from(match name {
"archive" => include_bytes!("../preset/plugins/archive.lua") as &[u8],
"code" => include_bytes!("../preset/plugins/code.lua"),
"file" => include_bytes!("../preset/plugins/file.lua"),
"folder" => include_bytes!("../preset/plugins/folder.lua"),
"image" => include_bytes!("../preset/plugins/image.lua"),
"json" => include_bytes!("../preset/plugins/json.lua"),
"mime" => include_bytes!("../preset/plugins/mime.lua"),
"noop" => include_bytes!("../preset/plugins/noop.lua"),
"pdf" => include_bytes!("../preset/plugins/pdf.lua"),
"video" => include_bytes!("../preset/plugins/video.lua"),
"archive" => include_bytes!("../../preset/plugins/archive.lua") as &[_],
"code" => include_bytes!("../../preset/plugins/code.lua"),
"file" => include_bytes!("../../preset/plugins/file.lua"),
"folder" => include_bytes!("../../preset/plugins/folder.lua"),
"image" => include_bytes!("../../preset/plugins/image.lua"),
"json" => include_bytes!("../../preset/plugins/json.lua"),
"mime" => include_bytes!("../../preset/plugins/mime.lua"),
"noop" => include_bytes!("../../preset/plugins/noop.lua"),
"pdf" => include_bytes!("../../preset/plugins/pdf.lua"),
"video" => include_bytes!("../../preset/plugins/video.lua"),
_ => bail!("plugin not found: {name}"),
}))
})?;
@ -58,8 +50,6 @@ impl Loader {
return Ok(t);
}
globals.raw_set("YAZI_PLUGIN_NAME", LUA.create_string(name)?)?;
globals.raw_set("YAZI_SYNC_CALLS", 0)?;
let t: Table = match self.read().get(name) {
Some(b) => LUA.load(b).call(())?,
None => Err(format!("plugin `{name}` not found").into_lua_err())?,
@ -69,14 +59,6 @@ impl Loader {
loaded.raw_set(name, t.clone())?;
Ok(t)
}
pub fn set_running(&self, name: Option<&str>) {
if let Some(s) = name {
RUNNING.store(Some(Arc::new(s.to_owned())));
} else {
RUNNING.store(None);
}
}
}
impl Deref for Loader {

View file

@ -0,0 +1,15 @@
#![allow(clippy::module_inception)]
mod loader;
mod require;
pub use loader::*;
use require::*;
pub(super) fn init() { LOADER.with(Default::default); }
pub(super) fn install(lua: &'static mlua::Lua) -> mlua::Result<()> {
Require::install(lua)?;
Ok(())
}

View file

@ -0,0 +1,66 @@
use mlua::{ExternalResult, Function, IntoLua, Lua, MetaMethod, Table, TableExt, UserData, Value, Variadic};
use crate::RtRef;
pub(super) struct Require;
impl Require {
pub(super) fn install(lua: &'static Lua) -> mlua::Result<()> {
let globals = lua.globals();
let require = globals.raw_get::<_, Function>("require")?;
globals.raw_set(
"require",
lua.create_function(move |lua, name: mlua::String| {
lua.named_registry_value::<RtRef>("rt")?.swap(name.to_str()?);
let module: Table = require.call(&name)?;
lua.named_registry_value::<RtRef>("rt")?.reset();
module.raw_set("_name", &name)?;
Self::create_mt(lua, name, module)
})?,
)?;
Ok(())
}
fn create_mt(
lua: &'static Lua,
name: mlua::String<'static>,
module: Table<'static>,
) -> mlua::Result<Table<'static>> {
let ts =
lua.create_table_from([("name", name.into_lua(lua)?), ("module", module.into_lua(lua)?)])?;
let mt = lua.create_table()?;
mt.raw_set(
"__index",
lua.create_function(|_, (ts, key): (Table, mlua::String)| {
if key.to_str()? == "setup" {
Ok(RequireSetup { name: ts.raw_get("name")?, module: ts.raw_get("module")? })
} else {
Err("Only `require():setup()` is supported").into_lua_err()
}
})?,
)?;
ts.set_metatable(Some(mt));
Ok(ts)
}
}
pub(super) struct RequireSetup {
name: mlua::String<'static>,
module: Table<'static>,
}
impl UserData for RequireSetup {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Call, |lua, me, args: Variadic<Value>| {
lua.named_registry_value::<RtRef>("rt")?.swap(me.name.to_str()?);
let result = me.module.call_method::<_, Variadic<Value>>("setup", args);
lua.named_registry_value::<RtRef>("rt")?.reset();
result
});
}
}

View file

@ -3,28 +3,31 @@ use mlua::Lua;
use yazi_boot::BOOT;
use yazi_shared::RoCell;
use crate::runtime::Runtime;
pub static LUA: RoCell<Lua> = RoCell::new();
pub(super) fn init_lua() {
LUA.init(Lua::new());
stage_1(&LUA).expect("failed to initialize Lua");
stage_2(&LUA);
stage_1(&LUA).expect("Lua setup failed");
stage_2(&LUA).expect("Lua runtime failed");
}
fn stage_1(lua: &'static Lua) -> Result<()> {
crate::Loader::init();
crate::Config::new(lua).install_boot()?.install_manager()?.install_theme()?;
crate::utils::init();
crate::utils::install(lua)?;
// Base
lua.set_named_registry_value("rt", Runtime::default())?;
lua.load(include_str!("../preset/ya.lua")).exec()?;
crate::bindings::Cha::register(lua)?;
crate::bindings::File::register(lua)?;
crate::bindings::Icon::register(lua)?;
crate::elements::pour(lua)?;
crate::pubsub::Pubsub::install(lua)?;
crate::loader::install(lua)?;
crate::pubsub::install(lua)?;
crate::url::pour(lua)?;
// Components
@ -41,10 +44,12 @@ fn stage_1(lua: &'static Lua) -> Result<()> {
Ok(())
}
fn stage_2(lua: &'static Lua) {
lua.load(include_str!("../preset/setup.lua")).exec().unwrap();
fn stage_2(lua: &'static Lua) -> mlua::Result<()> {
lua.load(include_str!("../preset/setup.lua")).exec()?;
if let Ok(b) = std::fs::read(BOOT.config_dir.join("init.lua")) {
lua.load(b).exec().unwrap();
lua.load(b).exec()?;
}
Ok(())
}

View file

@ -3,3 +3,9 @@
mod pubsub;
pub use pubsub::*;
pub(super) fn install(lua: &'static mlua::Lua) -> mlua::Result<()> {
Pubsub::install(lua)?;
Ok(())
}

View file

@ -1,12 +1,12 @@
use mlua::{ExternalResult, Function, Lua, Value};
use yazi_dds::body::Body;
use crate::RUNNING;
use crate::runtime::RtRef;
pub struct Pubsub;
impl Pubsub {
pub fn install(lua: &'static Lua) -> mlua::Result<()> {
pub(super) fn install(lua: &'static Lua) -> mlua::Result<()> {
let ps = lua.create_table()?;
ps.raw_set(
@ -42,11 +42,11 @@ impl Pubsub {
ps.raw_set(
"sub",
lua.create_function(|_, (kind, f): (mlua::String, Function)| {
let Some(name) = &*RUNNING.load() else {
lua.create_function(|lua, (kind, f): (mlua::String, Function)| {
let Some(ref cur) = lua.named_registry_value::<RtRef>("rt")?.current else {
return Err("`sub()` must be called in a sync plugin").into_lua_err();
};
if !yazi_dds::Pubsub::sub(name, kind.to_str()?, f) {
if !yazi_dds::Pubsub::sub(cur, kind.to_str()?, f) {
return Err("`sub()` called twice").into_lua_err();
}
Ok(())
@ -56,10 +56,10 @@ impl Pubsub {
ps.raw_set(
"sub_remote",
lua.create_function(|_, (kind, f): (mlua::String, Function)| {
let Some(name) = &*RUNNING.load() else {
let Some(ref cur) = lua.named_registry_value::<RtRef>("rt")?.current else {
return Err("`sub_remote()` must be called in a sync plugin").into_lua_err();
};
if !yazi_dds::Pubsub::sub_remote(name, kind.to_str()?, f) {
if !yazi_dds::Pubsub::sub_remote(cur, kind.to_str()?, f) {
return Err("`sub_remote()` called twice").into_lua_err();
}
Ok(())
@ -69,8 +69,8 @@ impl Pubsub {
ps.raw_set(
"unsub",
lua.create_function(|_, kind: mlua::String| {
if let Some(name) = &*RUNNING.load() {
Ok(yazi_dds::Pubsub::unsub(name, kind.to_str()?))
if let Some(ref cur) = lua.named_registry_value::<RtRef>("rt")?.current {
Ok(yazi_dds::Pubsub::unsub(cur, kind.to_str()?))
} else {
Err("`unsub()` must be called in a sync plugin").into_lua_err()
}
@ -80,8 +80,8 @@ impl Pubsub {
ps.raw_set(
"unsub_remote",
lua.create_function(|_, kind: mlua::String| {
if let Some(name) = &*RUNNING.load() {
Ok(yazi_dds::Pubsub::unsub_remote(name, kind.to_str()?))
if let Some(ref cur) = lua.named_registry_value::<RtRef>("rt")?.current {
Ok(yazi_dds::Pubsub::unsub_remote(cur, kind.to_str()?))
} else {
Err("`unsub_remote()` must be called in a sync plugin").into_lua_err()
}

View file

@ -0,0 +1,52 @@
use std::collections::HashMap;
use mlua::{Function, UserData};
#[derive(Default)]
pub struct Runtime {
pub current: Option<String>,
pub calls: usize,
pub blocks: HashMap<String, Vec<Function<'static>>>,
}
pub type RtRef<'lua> = mlua::UserDataRefMut<'lua, Runtime>;
impl Runtime {
pub fn new(current: &str) -> Self {
Self { current: Some(current.to_owned()), ..Default::default() }
}
pub fn swap(&mut self, name: &str) {
self.current = Some(name.to_owned());
self.calls = 0;
}
pub fn reset(&mut self) {
self.current = None;
self.calls = 0;
}
pub fn next_block(&mut self) -> usize {
self.calls += 1;
self.calls - 1
}
pub fn get_block(&self, name: &str, calls: usize) -> Option<Function<'static>> {
self.blocks.get(name).and_then(|v| v.get(calls)).cloned()
}
pub fn push_block(&mut self, f: Function<'static>) -> bool {
let Some(ref cur) = self.current else {
return false;
};
if let Some(vec) = self.blocks.get_mut(cur) {
vec.push(f);
} else {
self.blocks.insert(cur.clone(), vec![f]);
}
true
}
}
impl UserData for Runtime {}

View file

@ -6,8 +6,8 @@ mod call;
mod image;
mod layer;
mod log;
mod plugin;
mod preview;
mod sync;
mod target;
mod text;
mod time;

View file

@ -1,53 +0,0 @@
use mlua::{ExternalError, Function, IntoLua, Lua, Table, Value, Variadic};
use tokio::sync::oneshot;
use yazi_dds::ValueSendable;
use yazi_shared::{emit, event::Cmd, Layer};
use super::Utils;
use crate::OptData;
impl Utils {
pub(super) fn plugin(lua: &Lua, ya: &Table) -> mlua::Result<()> {
ya.raw_set(
"plugin_retrieve",
lua.create_async_function(
|_, (name, calls, args): (String, usize, Variadic<Value>)| async move {
let args = ValueSendable::try_from_variadic(args)?;
let (tx, rx) = oneshot::channel::<Vec<ValueSendable>>();
let data = OptData {
cb: Some({
let name = name.clone();
Box::new(move |lua, plugin| {
let blocks = lua.globals().raw_get::<_, Table>("YAZI_SYNC_BLOCKS")?;
let block = blocks.raw_get::<_, Table>(name)?.raw_get::<_, Function>(calls)?;
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)?);
}
let values =
ValueSendable::try_from_variadic(block.call(Variadic::from_iter(self_args))?)?;
tx.send(values).map_err(|_| "send failed".into_lua_err())
})
}),
..Default::default()
};
emit!(Call(
Cmd::args("plugin", vec![name.clone()]).with_bool("sync", true).with_data(data),
Layer::App
));
Ok(Variadic::from_iter(rx.await.map_err(|_| {
format!("Failed to execute sync block-{calls} in `{name}` plugin").into_lua_err()
})?))
},
)?,
)?;
Ok(())
}
}

View file

@ -0,0 +1,87 @@
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 super::Utils;
use crate::{loader::LOADER, runtime::RtRef, OptData};
impl Utils {
pub(super) fn sync(lua: &'static Lua, ya: &Table) -> mlua::Result<()> {
ya.raw_set(
"sync",
lua.create_function(|lua, f: Function<'static>| {
let mut rt = lua.named_registry_value::<RtRef>("rt")?;
if !rt.push_block(f.clone()) {
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
}
let cur = rt.current.clone().unwrap();
lua.create_function(move |lua, mut args: Variadic<Value>| {
args.insert(0, LOADER.load(&cur)?.into_lua(lua)?);
f.call::<_, Variadic<Value>>(args)
})
})?,
)?;
Ok(())
}
pub(super) fn sync_isolate(lua: &Lua, ya: &Table) -> mlua::Result<()> {
ya.raw_set(
"sync",
lua.create_function(|lua, ()| {
let block = lua.named_registry_value::<RtRef>("rt")?.next_block();
lua.create_async_function(move |lua, args: Variadic<Value>| async move {
let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current.clone() else {
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
};
Self::retrieve(cur, block, args).await
})
})?,
)?;
Ok(())
}
async fn retrieve(
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>>();
let data = OptData {
cb: Some({
let name = name.clone();
Box::new(move |lua, plugin| {
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&name, calls) else {
return Err("sync block not found".into_lua_err());
};
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)?);
}
let values =
ValueSendable::try_from_variadic(block.call(Variadic::from_iter(self_args))?)?;
tx.send(values).map_err(|_| "send failed".into_lua_err())
})
}),
..Default::default()
};
emit!(Call(
Cmd::args("plugin", vec![name.clone()]).with_bool("sync", true).with_data(data),
Layer::App
));
Ok(Variadic::from_iter(rx.await.map_err(|_| {
format!("Failed to execute sync block-{calls} in `{name}` plugin").into_lua_err()
})?))
}
}

View file

@ -6,7 +6,7 @@ pub(super) static HOSTNAME_CACHE: std::sync::OnceLock<Option<String>> = std::syn
pub(super) struct Utils;
pub fn install(lua: &mlua::Lua) -> mlua::Result<()> {
pub fn install(lua: &'static mlua::Lua) -> mlua::Result<()> {
let ya = lua.create_table()?;
Utils::app(lua, &ya)?;
@ -15,8 +15,27 @@ pub fn install(lua: &mlua::Lua) -> mlua::Result<()> {
Utils::image(lua, &ya)?;
Utils::layer(lua, &ya)?;
Utils::log(lua, &ya)?;
Utils::plugin(lua, &ya)?;
Utils::preview(lua, &ya)?;
Utils::sync(lua, &ya)?;
Utils::target(lua, &ya)?;
Utils::text(lua, &ya)?;
Utils::time(lua, &ya)?;
Utils::user(lua, &ya)?;
lua.globals().raw_set("ya", ya)
}
pub fn install_isolate(lua: &mlua::Lua) -> mlua::Result<()> {
let ya = lua.create_table()?;
Utils::app(lua, &ya)?;
Utils::cache(lua, &ya)?;
Utils::call(lua, &ya)?;
Utils::image(lua, &ya)?;
Utils::layer(lua, &ya)?;
Utils::log(lua, &ya)?;
Utils::preview(lua, &ya)?;
Utils::sync_isolate(lua, &ya)?;
Utils::target(lua, &ya)?;
Utils::text(lua, &ya)?;
Utils::time(lua, &ya)?;