mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
perf: port require() and ya.sync() to Rust to avoid plugin information initialization process (#853)
This commit is contained in:
parent
903f3da7e5
commit
c240602046
23 changed files with 310 additions and 152 deletions
|
|
@ -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":[]}
|
||||||
|
|
@ -48,11 +48,11 @@ pub struct BodyBulkIter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserData for 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));
|
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_method(MetaMethod::Len, |_, me, ()| Ok(me.inner.len()));
|
||||||
|
|
||||||
methods.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {
|
methods.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ pub struct BodyTabsItem<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserData for BodyTabsItem<'static> {
|
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()));
|
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 {
|
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));
|
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::Len, |_, me, ()| Ok(me.items.len()));
|
||||||
|
|
||||||
methods.add_meta_method(MetaMethod::Index, |_, me, idx: usize| {
|
methods.add_meta_method(MetaMethod::Index, |_, me, idx: usize| {
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,11 @@ impl From<BodyYank<'static>> for BodyYankIter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserData 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));
|
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::Len, |_, me, ()| Ok(me.urls.len()));
|
||||||
|
|
||||||
methods.add_meta_method(MetaMethod::Index, |lua, me, idx: usize| {
|
methods.add_meta_method(MetaMethod::Index, |lua, me, idx: usize| {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use mlua::TableExt;
|
use mlua::TableExt;
|
||||||
use tracing::warn;
|
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 yazi_shared::{emit, event::Cmd, Defer, Layer};
|
||||||
|
|
||||||
use crate::{app::App, lives::Lives};
|
use crate::{app::App, lives::Lives};
|
||||||
|
|
@ -40,9 +40,12 @@ impl App {
|
||||||
Err(e) => return warn!("{e}"),
|
Err(e) => return warn!("{e}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
LOADER.set_running(Some(&opt.name));
|
match LUA.named_registry_value::<RtRef>("rt") {
|
||||||
let _defer = Defer::new(|| LOADER.set_running(None));
|
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) {
|
let plugin = match LOADER.load(&opt.name) {
|
||||||
Ok(plugin) => plugin,
|
Ok(plugin) => plugin,
|
||||||
Err(e) => return warn!("{e}"),
|
Err(e) => return warn!("{e}"),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1 @@
|
||||||
package.path = BOOT.plugin_dir .. "/?.yazi/init.lua;" .. package.path
|
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 = {}
|
|
||||||
|
|
|
||||||
|
|
@ -28,19 +28,6 @@ function ya.flat(t)
|
||||||
return r
|
return r
|
||||||
end
|
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.basename(str) return string.gsub(str, "(.*[/\\])(.*)", "%2") end
|
||||||
|
|
||||||
function ya.readable_size(size)
|
function ya.readable_size(size)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use tokio::runtime::Handle;
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_dds::ValueSendable;
|
||||||
|
|
||||||
use super::slim_lua;
|
use super::slim_lua;
|
||||||
use crate::LOADER;
|
use crate::loader::LOADER;
|
||||||
|
|
||||||
pub async fn entry(name: String, args: Vec<ValueSendable>) -> mlua::Result<()> {
|
pub async fn entry(name: String, args: Vec<ValueSendable>) -> mlua::Result<()> {
|
||||||
LOADER.ensure(&name).await.into_lua_err()?;
|
LOADER.ensure(&name).await.into_lua_err()?;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use mlua::Lua;
|
use mlua::Lua;
|
||||||
|
|
||||||
use crate::{bindings, elements};
|
use crate::{bindings, elements, runtime::Runtime};
|
||||||
|
|
||||||
pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
|
pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
|
lua.set_named_registry_value("rt", Runtime::new(name))?;
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
bindings::Cha::register(&lua)?;
|
bindings::Cha::register(&lua)?;
|
||||||
|
|
@ -12,7 +13,7 @@ pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
|
||||||
|
|
||||||
crate::fs::install(&lua)?;
|
crate::fs::install(&lua)?;
|
||||||
crate::process::install(&lua)?;
|
crate::process::install(&lua)?;
|
||||||
crate::utils::install(&lua)?;
|
crate::utils::install_isolate(&lua)?;
|
||||||
crate::Config::new(&lua).install_preview()?;
|
crate::Config::new(&lua).install_preview()?;
|
||||||
lua.load(include_str!("../../preset/ya.lua")).exec()?;
|
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::Rect::install(&lua, &ui)?;
|
||||||
elements::Span::install(&lua, &ui)?;
|
elements::Span::install(&lua, &ui)?;
|
||||||
|
|
||||||
{
|
lua.globals().raw_set("ui", 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)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(lua)
|
Ok(lua)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use yazi_config::LAYOUT;
|
||||||
use yazi_shared::{emit, event::Cmd, Layer};
|
use yazi_shared::{emit, event::Cmd, Layer};
|
||||||
|
|
||||||
use super::slim_lua;
|
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 {
|
pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> CancellationToken {
|
||||||
let ct = CancellationToken::new();
|
let ct = CancellationToken::new();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use tokio::runtime::Handle;
|
||||||
use yazi_config::LAYOUT;
|
use yazi_config::LAYOUT;
|
||||||
|
|
||||||
use super::slim_lua;
|
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(
|
pub async fn preload(
|
||||||
name: &str,
|
name: &str,
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,22 @@ pub mod elements;
|
||||||
pub mod external;
|
pub mod external;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod isolate;
|
pub mod isolate;
|
||||||
mod loader;
|
pub mod loader;
|
||||||
mod lua;
|
mod lua;
|
||||||
mod opt;
|
mod opt;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod pubsub;
|
pub mod pubsub;
|
||||||
|
mod runtime;
|
||||||
pub mod url;
|
pub mod url;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub use cast::*;
|
pub use cast::*;
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
pub use loader::*;
|
|
||||||
pub use lua::*;
|
pub use lua::*;
|
||||||
pub use opt::*;
|
pub use opt::*;
|
||||||
|
pub use runtime::*;
|
||||||
|
|
||||||
pub fn init() { crate::init_lua(); }
|
pub fn init() {
|
||||||
|
crate::init_lua();
|
||||||
|
crate::loader::init();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 anyhow::{bail, Result};
|
||||||
use mlua::{ExternalError, Table};
|
use mlua::{ExternalError, Table};
|
||||||
|
|
@ -11,20 +11,12 @@ use crate::LUA;
|
||||||
|
|
||||||
pub static LOADER: RoCell<Loader> = RoCell::new();
|
pub static LOADER: RoCell<Loader> = RoCell::new();
|
||||||
|
|
||||||
pub(super) static RUNNING: RoCell<arc_swap::ArcSwapOption<String>> = RoCell::new();
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Loader {
|
pub struct Loader {
|
||||||
cache: RwLock<HashMap<String, Vec<u8>>>,
|
cache: RwLock<HashMap<String, Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Loader {
|
impl Loader {
|
||||||
#[inline]
|
|
||||||
pub(super) fn init() {
|
|
||||||
LOADER.with(Default::default);
|
|
||||||
RUNNING.with(Default::default);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn ensure(&self, name: &str) -> Result<()> {
|
pub async fn ensure(&self, name: &str) -> Result<()> {
|
||||||
if self.cache.read().contains_key(name) {
|
if self.cache.read().contains_key(name) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -33,16 +25,16 @@ impl Loader {
|
||||||
let path = BOOT.plugin_dir.join(format!("{name}.yazi/init.lua"));
|
let path = BOOT.plugin_dir.join(format!("{name}.yazi/init.lua"));
|
||||||
let b = fs::read(path).await.map(|v| v.into()).or_else(|_| {
|
let b = fs::read(path).await.map(|v| v.into()).or_else(|_| {
|
||||||
Ok(Cow::from(match name {
|
Ok(Cow::from(match name {
|
||||||
"archive" => include_bytes!("../preset/plugins/archive.lua") as &[u8],
|
"archive" => include_bytes!("../../preset/plugins/archive.lua") as &[_],
|
||||||
"code" => include_bytes!("../preset/plugins/code.lua"),
|
"code" => include_bytes!("../../preset/plugins/code.lua"),
|
||||||
"file" => include_bytes!("../preset/plugins/file.lua"),
|
"file" => include_bytes!("../../preset/plugins/file.lua"),
|
||||||
"folder" => include_bytes!("../preset/plugins/folder.lua"),
|
"folder" => include_bytes!("../../preset/plugins/folder.lua"),
|
||||||
"image" => include_bytes!("../preset/plugins/image.lua"),
|
"image" => include_bytes!("../../preset/plugins/image.lua"),
|
||||||
"json" => include_bytes!("../preset/plugins/json.lua"),
|
"json" => include_bytes!("../../preset/plugins/json.lua"),
|
||||||
"mime" => include_bytes!("../preset/plugins/mime.lua"),
|
"mime" => include_bytes!("../../preset/plugins/mime.lua"),
|
||||||
"noop" => include_bytes!("../preset/plugins/noop.lua"),
|
"noop" => include_bytes!("../../preset/plugins/noop.lua"),
|
||||||
"pdf" => include_bytes!("../preset/plugins/pdf.lua"),
|
"pdf" => include_bytes!("../../preset/plugins/pdf.lua"),
|
||||||
"video" => include_bytes!("../preset/plugins/video.lua"),
|
"video" => include_bytes!("../../preset/plugins/video.lua"),
|
||||||
_ => bail!("plugin not found: {name}"),
|
_ => bail!("plugin not found: {name}"),
|
||||||
}))
|
}))
|
||||||
})?;
|
})?;
|
||||||
|
|
@ -58,8 +50,6 @@ impl Loader {
|
||||||
return Ok(t);
|
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) {
|
let t: Table = match self.read().get(name) {
|
||||||
Some(b) => LUA.load(b).call(())?,
|
Some(b) => LUA.load(b).call(())?,
|
||||||
None => Err(format!("plugin `{name}` not found").into_lua_err())?,
|
None => Err(format!("plugin `{name}` not found").into_lua_err())?,
|
||||||
|
|
@ -69,14 +59,6 @@ impl Loader {
|
||||||
loaded.raw_set(name, t.clone())?;
|
loaded.raw_set(name, t.clone())?;
|
||||||
Ok(t)
|
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 {
|
impl Deref for Loader {
|
||||||
15
yazi-plugin/src/loader/mod.rs
Normal file
15
yazi-plugin/src/loader/mod.rs
Normal 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(())
|
||||||
|
}
|
||||||
66
yazi-plugin/src/loader/require.rs
Normal file
66
yazi-plugin/src/loader/require.rs
Normal 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,28 +3,31 @@ use mlua::Lua;
|
||||||
use yazi_boot::BOOT;
|
use yazi_boot::BOOT;
|
||||||
use yazi_shared::RoCell;
|
use yazi_shared::RoCell;
|
||||||
|
|
||||||
|
use crate::runtime::Runtime;
|
||||||
|
|
||||||
pub static LUA: RoCell<Lua> = RoCell::new();
|
pub static LUA: RoCell<Lua> = RoCell::new();
|
||||||
|
|
||||||
pub(super) fn init_lua() {
|
pub(super) fn init_lua() {
|
||||||
LUA.init(Lua::new());
|
LUA.init(Lua::new());
|
||||||
|
|
||||||
stage_1(&LUA).expect("failed to initialize Lua");
|
stage_1(&LUA).expect("Lua setup failed");
|
||||||
stage_2(&LUA);
|
stage_2(&LUA).expect("Lua runtime failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stage_1(lua: &'static Lua) -> Result<()> {
|
fn stage_1(lua: &'static Lua) -> Result<()> {
|
||||||
crate::Loader::init();
|
|
||||||
crate::Config::new(lua).install_boot()?.install_manager()?.install_theme()?;
|
crate::Config::new(lua).install_boot()?.install_manager()?.install_theme()?;
|
||||||
crate::utils::init();
|
crate::utils::init();
|
||||||
crate::utils::install(lua)?;
|
crate::utils::install(lua)?;
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
|
lua.set_named_registry_value("rt", Runtime::default())?;
|
||||||
lua.load(include_str!("../preset/ya.lua")).exec()?;
|
lua.load(include_str!("../preset/ya.lua")).exec()?;
|
||||||
crate::bindings::Cha::register(lua)?;
|
crate::bindings::Cha::register(lua)?;
|
||||||
crate::bindings::File::register(lua)?;
|
crate::bindings::File::register(lua)?;
|
||||||
crate::bindings::Icon::register(lua)?;
|
crate::bindings::Icon::register(lua)?;
|
||||||
crate::elements::pour(lua)?;
|
crate::elements::pour(lua)?;
|
||||||
crate::pubsub::Pubsub::install(lua)?;
|
crate::loader::install(lua)?;
|
||||||
|
crate::pubsub::install(lua)?;
|
||||||
crate::url::pour(lua)?;
|
crate::url::pour(lua)?;
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
|
|
@ -41,10 +44,12 @@ fn stage_1(lua: &'static Lua) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stage_2(lua: &'static Lua) {
|
fn stage_2(lua: &'static Lua) -> mlua::Result<()> {
|
||||||
lua.load(include_str!("../preset/setup.lua")).exec().unwrap();
|
lua.load(include_str!("../preset/setup.lua")).exec()?;
|
||||||
|
|
||||||
if let Ok(b) = std::fs::read(BOOT.config_dir.join("init.lua")) {
|
if let Ok(b) = std::fs::read(BOOT.config_dir.join("init.lua")) {
|
||||||
lua.load(b).exec().unwrap();
|
lua.load(b).exec()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,9 @@
|
||||||
mod pubsub;
|
mod pubsub;
|
||||||
|
|
||||||
pub use pubsub::*;
|
pub use pubsub::*;
|
||||||
|
|
||||||
|
pub(super) fn install(lua: &'static mlua::Lua) -> mlua::Result<()> {
|
||||||
|
Pubsub::install(lua)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use mlua::{ExternalResult, Function, Lua, Value};
|
use mlua::{ExternalResult, Function, Lua, Value};
|
||||||
use yazi_dds::body::Body;
|
use yazi_dds::body::Body;
|
||||||
|
|
||||||
use crate::RUNNING;
|
use crate::runtime::RtRef;
|
||||||
|
|
||||||
pub struct Pubsub;
|
pub struct Pubsub;
|
||||||
|
|
||||||
impl 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()?;
|
let ps = lua.create_table()?;
|
||||||
|
|
||||||
ps.raw_set(
|
ps.raw_set(
|
||||||
|
|
@ -42,11 +42,11 @@ impl Pubsub {
|
||||||
|
|
||||||
ps.raw_set(
|
ps.raw_set(
|
||||||
"sub",
|
"sub",
|
||||||
lua.create_function(|_, (kind, f): (mlua::String, Function)| {
|
lua.create_function(|lua, (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()` must be called in a sync plugin").into_lua_err();
|
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();
|
return Err("`sub()` called twice").into_lua_err();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -56,10 +56,10 @@ impl Pubsub {
|
||||||
ps.raw_set(
|
ps.raw_set(
|
||||||
"sub_remote",
|
"sub_remote",
|
||||||
lua.create_function(|_, (kind, f): (mlua::String, Function)| {
|
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();
|
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();
|
return Err("`sub_remote()` called twice").into_lua_err();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -69,8 +69,8 @@ impl Pubsub {
|
||||||
ps.raw_set(
|
ps.raw_set(
|
||||||
"unsub",
|
"unsub",
|
||||||
lua.create_function(|_, kind: mlua::String| {
|
lua.create_function(|_, kind: mlua::String| {
|
||||||
if let Some(name) = &*RUNNING.load() {
|
if let Some(ref cur) = lua.named_registry_value::<RtRef>("rt")?.current {
|
||||||
Ok(yazi_dds::Pubsub::unsub(name, kind.to_str()?))
|
Ok(yazi_dds::Pubsub::unsub(cur, kind.to_str()?))
|
||||||
} else {
|
} else {
|
||||||
Err("`unsub()` must be called in a sync plugin").into_lua_err()
|
Err("`unsub()` must be called in a sync plugin").into_lua_err()
|
||||||
}
|
}
|
||||||
|
|
@ -80,8 +80,8 @@ impl Pubsub {
|
||||||
ps.raw_set(
|
ps.raw_set(
|
||||||
"unsub_remote",
|
"unsub_remote",
|
||||||
lua.create_function(|_, kind: mlua::String| {
|
lua.create_function(|_, kind: mlua::String| {
|
||||||
if let Some(name) = &*RUNNING.load() {
|
if let Some(ref cur) = lua.named_registry_value::<RtRef>("rt")?.current {
|
||||||
Ok(yazi_dds::Pubsub::unsub_remote(name, kind.to_str()?))
|
Ok(yazi_dds::Pubsub::unsub_remote(cur, kind.to_str()?))
|
||||||
} else {
|
} else {
|
||||||
Err("`unsub_remote()` must be called in a sync plugin").into_lua_err()
|
Err("`unsub_remote()` must be called in a sync plugin").into_lua_err()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
52
yazi-plugin/src/runtime.rs
Normal file
52
yazi-plugin/src/runtime.rs
Normal 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 {}
|
||||||
|
|
@ -6,8 +6,8 @@ mod call;
|
||||||
mod image;
|
mod image;
|
||||||
mod layer;
|
mod layer;
|
||||||
mod log;
|
mod log;
|
||||||
mod plugin;
|
|
||||||
mod preview;
|
mod preview;
|
||||||
|
mod sync;
|
||||||
mod target;
|
mod target;
|
||||||
mod text;
|
mod text;
|
||||||
mod time;
|
mod time;
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
87
yazi-plugin/src/utils/sync.rs
Normal file
87
yazi-plugin/src/utils/sync.rs
Normal 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()
|
||||||
|
})?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ pub(super) static HOSTNAME_CACHE: std::sync::OnceLock<Option<String>> = std::syn
|
||||||
|
|
||||||
pub(super) struct Utils;
|
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()?;
|
let ya = lua.create_table()?;
|
||||||
|
|
||||||
Utils::app(lua, &ya)?;
|
Utils::app(lua, &ya)?;
|
||||||
|
|
@ -15,8 +15,27 @@ pub fn install(lua: &mlua::Lua) -> mlua::Result<()> {
|
||||||
Utils::image(lua, &ya)?;
|
Utils::image(lua, &ya)?;
|
||||||
Utils::layer(lua, &ya)?;
|
Utils::layer(lua, &ya)?;
|
||||||
Utils::log(lua, &ya)?;
|
Utils::log(lua, &ya)?;
|
||||||
Utils::plugin(lua, &ya)?;
|
|
||||||
Utils::preview(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::target(lua, &ya)?;
|
||||||
Utils::text(lua, &ya)?;
|
Utils::text(lua, &ya)?;
|
||||||
Utils::time(lua, &ya)?;
|
Utils::time(lua, &ya)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue