use std::{collections::HashMap, ops::Deref}; use anyhow::{Context, Result}; use mlua::{ExternalError, Lua, Table}; use parking_lot::RwLock; use tokio::fs; use yazi_boot::BOOT; use yazi_macro::plugin_preset as preset; use yazi_shared::RoCell; use super::Chunk; pub static LOADER: RoCell = RoCell::new(); pub struct Loader { 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 { pub async fn ensure(&self, name: &str) -> Result<()> { if self.cache.read().contains_key(name) { return Ok(()); } 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(); self.cache.write().insert(name.to_owned(), chunk); Ok(()) } pub fn load(&self, lua: &Lua, id: &str) -> mlua::Result { let loaded: Table = lua.globals().raw_get::
("package")?.raw_get("loaded")?; if let Ok(t) = loaded.raw_get::
(id) { return Ok(t); } let t: Table = match self.read().get(id) { 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) } pub fn try_load(&self, lua: &Lua, id: &str) -> mlua::Result
{ let loaded: Table = lua.globals().raw_get::
("package")?.raw_get("loaded")?; loaded.raw_get(id) } pub fn load_with(&self, lua: &Lua, id: &str, chunk: &Chunk) -> mlua::Result
{ let loaded: Table = lua.globals().raw_get::
("package")?.raw_get("loaded")?; if let Ok(t) = loaded.raw_get::
(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) } }