diff --git a/cspell.json b/cspell.json index 41af766c..99144de9 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1 @@ -{"version":"0.2","language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","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","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","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","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm","mimetypes","Mimelist"]} \ No newline at end of file +{"words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","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","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","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","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm","mimetypes","Mimelist","renderables","redrawer"],"language":"en","version":"0.2","flagWords":[]} \ No newline at end of file diff --git a/yazi-actor/src/app/accept_payload.rs b/yazi-actor/src/app/accept_payload.rs index e9de9bed..151e83b6 100644 --- a/yazi-actor/src/app/accept_payload.rs +++ b/yazi-actor/src/app/accept_payload.rs @@ -29,7 +29,7 @@ impl Actor for AcceptPayload { drop(lock); let kind = kind.to_owned(); - succ!(Lives::scope(cx.core, || { + succ!(Lives::scope(cx.core, |_| { let body = payload.body.into_lua(&LUA)?; for (id, cb) in handlers { if let Err(e) = runtime_scope!(LUA, &id, cb.call::<()>(body.clone())) { diff --git a/yazi-actor/src/app/dnd.rs b/yazi-actor/src/app/dnd.rs index 10f357a5..014aa552 100644 --- a/yazi-actor/src/app/dnd.rs +++ b/yazi-actor/src/app/dnd.rs @@ -23,7 +23,7 @@ impl Actor for Dnd { let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() }; let area = yazi_binding::elements::Rect::from(size); - let result = Lives::scope(cx.core, move || { + let result = Lives::scope(cx.core, move |_| { runtime_scope!(LUA, "root", { let root = LUA.globals().raw_get::("Root")?.call_method::
("new", area)?; diff --git a/yazi-actor/src/app/lua.rs b/yazi-actor/src/app/lua.rs index a2c793b1..73e4e181 100644 --- a/yazi-actor/src/app/lua.rs +++ b/yazi-actor/src/app/lua.rs @@ -16,7 +16,7 @@ impl Actor for Lua { fn act(cx: &mut Ctx, form: Self::Form) -> Result { let chunk = LUA.load(&*form.code).set_name("anonymous"); - let result = Lives::scope(cx.core, || { + let result = Lives::scope(cx.core, |_| { runtime_scope!(LUA, "inline", Sendable::value_to_data(&LUA, chunk.eval()?)) }); succ!(result?); diff --git a/yazi-actor/src/app/mouse.rs b/yazi-actor/src/app/mouse.rs index 3692cf00..8ecdbf10 100644 --- a/yazi-actor/src/app/mouse.rs +++ b/yazi-actor/src/app/mouse.rs @@ -24,7 +24,7 @@ impl Actor for Mouse { let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() }; let area = yazi_binding::elements::Rect::from(size); - let result = Lives::scope(cx.core, move || { + let result = Lives::scope(cx.core, move |_| { runtime_scope!(LUA, "root", { let root = LUA.globals().raw_get::
("Root")?.call_method::
("new", area)?; diff --git a/yazi-actor/src/app/plugin_do.rs b/yazi-actor/src/app/plugin_do.rs index c62a390a..dc647bab 100644 --- a/yazi-actor/src/app/plugin_do.rs +++ b/yazi-actor/src/app/plugin_do.rs @@ -43,7 +43,7 @@ impl Actor for PluginDo { }; drop(loader); - let result = Lives::scope(cx.core, || { + let result = Lives::scope(cx.core, |_| { if let Some(cb) = opt.callback { cb(&LUA, plugin) } else { diff --git a/yazi-actor/src/app/reflow.rs b/yazi-actor/src/app/reflow.rs index cd4390a1..958a1a51 100644 --- a/yazi-actor/src/app/reflow.rs +++ b/yazi-actor/src/app/reflow.rs @@ -21,7 +21,7 @@ impl Actor for Reflow { let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() }; let mut layout = LAYOUT.get(); - let result = Lives::scope(cx.core, || { + let result = Lives::scope(cx.core, |_| { let comps = (form.reflow)((Position::ORIGIN, size).into())?; for v in comps.sequence_values::() { diff --git a/yazi-actor/src/core/preflight.rs b/yazi-actor/src/core/preflight.rs index 56f6e4d0..92e8d0c9 100644 --- a/yazi-actor/src/core/preflight.rs +++ b/yazi-actor/src/core/preflight.rs @@ -16,7 +16,7 @@ impl Preflight { return Ok(opt.1); }; - Ok(Lives::scope(cx.core, || { + Ok(Lives::scope(cx.core, |_| { let mut body = opt.1.into_lua(&LUA)?; for (id, cb) in handlers { match runtime_scope!(LUA, &id, cb.call::(&body)) { diff --git a/yazi-actor/src/lib.rs b/yazi-actor/src/lib.rs index 6706a76c..15eb9f27 100644 --- a/yazi-actor/src/lib.rs +++ b/yazi-actor/src/lib.rs @@ -3,3 +3,5 @@ extern crate self as yazi_actor; yazi_macro::mod_pub!(app cmp confirm core help input lives mgr notify pick spot tasks which); yazi_macro::mod_flat!(actor context); + +pub fn init() { lives::init(); } diff --git a/yazi-actor/src/lives/core.rs b/yazi-actor/src/lives/core.rs index a32022c9..f7f6acdc 100644 --- a/yazi-actor/src/lives/core.rs +++ b/yazi-actor/src/lives/core.rs @@ -1,10 +1,12 @@ use std::ops::Deref; -use mlua::{AnyUserData, IntoLua, MetaMethod, UserData, UserDataMethods, Value}; +use mlua::{AnyUserData, IntoLua, MetaMethod, UserData, UserDataMethods, UserDataRef, Value}; use paste::paste; use super::{Lives, PtrCell}; +pub(super) type CoreRef = UserDataRef; + pub(super) struct Core { inner: PtrCell, diff --git a/yazi-actor/src/lives/file.rs b/yazi-actor/src/lives/file.rs index 1aebfff2..bc802aa9 100644 --- a/yazi-actor/src/lives/file.rs +++ b/yazi-actor/src/lives/file.rs @@ -5,8 +5,8 @@ use yazi_binding::{Range, Style}; use yazi_config::THEME; use yazi_shared::{path::AsPath, url::UrlLike}; -use super::Lives; -use crate::lives::PtrCell; +use super::{FILE_CACHE, Lives}; +use crate::lives::{CoreRef, PtrCell}; pub(super) struct File { idx: usize, @@ -32,7 +32,7 @@ impl File { ) -> mlua::Result { use hashbrown::hash_map::Entry; - Ok(match super::FILE_CACHE.borrow_mut().entry(PtrCell(&folder.files[idx])) { + Ok(match unsafe { (*FILE_CACHE.get()).assume_init_mut() }.entry(PtrCell(&folder.files[idx])) { Entry::Occupied(oe) => oe.into_mut().clone(), Entry::Vacant(ve) => { let ud = Lives::scoped_userdata(Self { idx, folder: folder.into(), tab: tab.into() })?; @@ -71,9 +71,8 @@ impl UserData for File { Ok(if me.is_dir() { me.folder.files.sizes.get(&me.urn()).copied() } else { Some(me.len) }) }); methods.add_method("mime", |lua, me, ()| { - lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose() - })? + let core: CoreRef = lua.named_registry_value("cx")?; + core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose() }); methods.add_method("prefix", |lua, me, ()| { if !me.url.has_trail() { @@ -85,20 +84,18 @@ impl UserData for File { Some(lua.create_string(comp.as_path().encoded_bytes())).transpose() }); methods.add_method("style", |lua, me, ()| { - lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default(); - THEME.filetype.match_style(me, mime).map(Style::from) - }) + let core: CoreRef = lua.named_registry_value("cx")?; + let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default(); + Ok(THEME.filetype.match_style(me, mime).map(Style::from)) }); methods.add_method("is_yanked", |lua, me, ()| { - lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - if !core.mgr.yanked.contains(&me.url) { - 0u8 - } else if core.mgr.yanked.cut { - 2u8 - } else { - 1u8 - } + let core: CoreRef = lua.named_registry_value("cx")?; + Ok(if !core.mgr.yanked.contains(&me.url) { + 0u8 + } else if core.mgr.yanked.cut { + 2u8 + } else { + 1u8 }) }); methods.add_method("is_marked", |_, me, ()| { @@ -115,31 +112,30 @@ impl UserData for File { }); methods.add_method("is_selected", |_, me, ()| Ok(me.tab.selected.contains(&me.url))); methods.add_method("found", |lua, me, ()| { - lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - let Some(finder) = &core.active().finder else { - return Ok(None); - }; + let core: CoreRef = lua.named_registry_value("cx")?; + let Some(finder) = &core.active().finder else { + return Ok(None); + }; - let Some(idx) = finder.matched_idx(&me.folder, me.urn()) else { - return Ok(None); - }; + let Some(idx) = finder.matched_idx(&me.folder, me.urn()) else { + return Ok(None); + }; - Some(lua.create_sequence_from([idx.into_lua(lua)?, finder.matched.len().into_lua(lua)?])) - .transpose() - }) + lua.create_sequence_from([idx.into_lua(lua)?, finder.matched.len().into_lua(lua)?]).map(Some) }); methods.add_method("highlights", |lua, me, ()| { - lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - let Some(finder) = &core.active().finder else { - return None; - }; - if me.folder.url != me.tab.current.url { - return None; - } + let core: CoreRef = lua.named_registry_value("cx")?; + let Some(finder) = &core.active().finder else { + return Ok(None); + }; + if me.folder.url != me.tab.current.url { + return Ok(None); + } + let Some(Some(h)) = me.url.name().map(|s| finder.filter.highlighted(s)) else { + return Ok(None); + }; - let h = finder.filter.highlighted(me.url.name()?)?; - Some(h.into_iter().map(Range::from).collect::>()) - }) + lua.create_sequence_from(h.into_iter().map(Range::from)).map(Some) }); } } diff --git a/yazi-actor/src/lives/lives.rs b/yazi-actor/src/lives/lives.rs index 1b969cd4..91db36c0 100644 --- a/yazi-actor/src/lives/lives.rs +++ b/yazi-actor/src/lives/lives.rs @@ -1,39 +1,37 @@ -use std::cell::RefCell; +use std::mem::MaybeUninit; use hashbrown::HashMap; use mlua::{AnyUserData, UserData}; use scopeguard::defer; use tracing::error; use yazi_plugin::LUA; -use yazi_shim::cell::RoCell; use super::{Core, PtrCell}; +use crate::lives::MutCell; -static TO_DESTROY: RoCell>> = RoCell::new_const(RefCell::new(Vec::new())); -pub(super) static FILE_CACHE: RoCell, AnyUserData>>> = - RoCell::new(); +pub(super) static TO_DESTROY: MutCell> = MutCell::new(Vec::new()); +pub(super) static FILE_CACHE: MutCell, AnyUserData>>> = + MutCell::new(MaybeUninit::uninit()); pub struct Lives; impl Lives { - pub fn scope(core: &yazi_core::Core, f: F) -> mlua::Result + pub fn scope(core: &mut yazi_core::Core, f: F) -> mlua::Result where - F: FnOnce() -> mlua::Result, + F: FnOnce(&mut yazi_core::Core) -> mlua::Result, { - FILE_CACHE.init(Default::default()); - defer! { FILE_CACHE.drop(); } - - let result = LUA.scope(|scope| { - scope.add_destructor(|| { - for ud in TO_DESTROY.borrow_mut().drain(..) { + defer! { + unsafe { + (*FILE_CACHE.get()).assume_init_mut().clear(); + for ud in (*TO_DESTROY.get()).drain(..) { ud.destroy().expect("failed to destruct scoped userdata"); } - }); + } + } - LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(core)?)?; - LUA.globals().raw_set("cx", Core::make(core)?)?; - f() - }); + LUA.set_named_registry_value("cx", Core::make(core)?)?; + LUA.globals().raw_set("cx", Core::make(core)?)?; + let result = f(core); if let Err(ref e) = result { error!("{e}"); @@ -46,7 +44,7 @@ impl Lives { T: UserData + 'static, { let ud = LUA.create_userdata(data)?; - TO_DESTROY.borrow_mut().push(ud.clone()); + unsafe { &mut *TO_DESTROY.get() }.push(ud.clone()); Ok(ud) } } diff --git a/yazi-actor/src/lives/mod.rs b/yazi-actor/src/lives/mod.rs index 594dc7fd..d804327b 100644 --- a/yazi-actor/src/lives/mod.rs +++ b/yazi-actor/src/lives/mod.rs @@ -1 +1,5 @@ -yazi_macro::mod_flat!(behavior core file files filter finder folder lives mode preference preview ptr selected tab tabs task tasks which yanked); +yazi_macro::mod_flat!(behavior core file files filter finder folder lives mode mut_cell preference preview ptr selected tab tabs task tasks which yanked); + +pub(super) fn init() { + unsafe { FILE_CACHE.get().write(std::mem::MaybeUninit::new(<_>::default())) }; +} diff --git a/yazi-actor/src/lives/mut_cell.rs b/yazi-actor/src/lives/mut_cell.rs new file mode 100644 index 00000000..25b27c8d --- /dev/null +++ b/yazi-actor/src/lives/mut_cell.rs @@ -0,0 +1,11 @@ +use std::cell::UnsafeCell; + +pub(super) struct MutCell(UnsafeCell); + +unsafe impl Sync for MutCell {} + +impl MutCell { + pub(super) const fn new(value: T) -> Self { Self(UnsafeCell::new(value)) } + + pub(super) fn get(&self) -> *mut T { self.0.get() } +} diff --git a/yazi-binding/src/elements/elements.rs b/yazi-binding/src/elements/elements.rs index f6b26c96..7d73a134 100644 --- a/yazi-binding/src/elements/elements.rs +++ b/yazi-binding/src/elements/elements.rs @@ -1,7 +1,5 @@ use mlua::{IntoLua, Lua, Value}; -use tracing::error; -use super::Renderable; use crate::{Composer, ComposerGet, ComposerSet}; pub fn compose(p_get: ComposerGet, p_set: ComposerSet) -> Composer { @@ -37,24 +35,3 @@ pub fn compose(p_get: ComposerGet, p_set: ComposerSet) -> Composer(value: Value, buf: &mut ratatui::buffer::Buffer, trans: F) -where - F: FnOnce(yazi_config::popup::Position) -> ratatui::layout::Rect + Copy, -{ - match value { - Value::Table(tbl) => { - for widget in tbl.sequence_values::() { - match widget { - Ok(w) => w.render_with(buf, trans), - Err(e) => error!("Failed to convert to renderable elements: {e}"), - } - } - } - Value::UserData(ud) => match Renderable::try_from(&ud) { - Ok(w) => w.render_with(buf, trans), - Err(e) => error!("Failed to convert to renderable element: {e}"), - }, - _ => error!("Expected a renderable element, or a table of them, got: {value:?}"), - } -} diff --git a/yazi-binding/src/elements/mod.rs b/yazi-binding/src/elements/mod.rs index 49c6da4e..b9c31b3d 100644 --- a/yazi-binding/src/elements/mod.rs +++ b/yazi-binding/src/elements/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(align area bar border cell clear color constraint edge elements fill gauge layout line list pad pos rect renderable row span table text wrap); +yazi_macro::mod_flat!(align area bar border cell clear color constraint edge elements fill gauge layout line list pad pos rect renderable renderables row span table text wrap); diff --git a/yazi-binding/src/elements/renderables.rs b/yazi-binding/src/elements/renderables.rs new file mode 100644 index 00000000..20f7d98b --- /dev/null +++ b/yazi-binding/src/elements/renderables.rs @@ -0,0 +1,29 @@ +use mlua::Value; +use tracing::error; + +use crate::elements::Renderable; + +pub struct Renderables; + +impl Renderables { + pub fn reduce(value: Value, mut reducer: F) + where + F: FnMut(Renderable), + { + match value { + Value::Table(tbl) => { + for element in tbl.sequence_values::() { + match element { + Ok(r) => reducer(r), + Err(e) => error!("Failed to convert to renderable elements: {e}"), + } + } + } + Value::UserData(ud) => match Renderable::try_from(&ud) { + Ok(w) => reducer(w), + Err(e) => error!("Failed to convert to renderable element: {e}"), + }, + _ => error!("Expected a renderable element, or a table of them, got: {value:?}"), + } + } +} diff --git a/yazi-fm/src/app/render.rs b/yazi-fm/src/app/render.rs index 175abe46..a137d3ad 100644 --- a/yazi-fm/src/app/render.rs +++ b/yazi-fm/src/app/render.rs @@ -30,8 +30,8 @@ impl App { let collision = COLLISION.swap(false, Ordering::Relaxed); let preview_rect = LAYOUT.get().preview; term.draw(|f| { - _ = Lives::scope(&self.core, || { - runtime_scope!(LUA, "root", Ok(f.render_widget(Root::new(&self.core), f.area()))) + _ = Lives::scope(&mut self.core, |core| { + runtime_scope!(LUA, "root", Ok(f.render_widget(Root::new(core), f.area()))) }); })?; @@ -58,10 +58,10 @@ impl App { let _guard = scopeguard::guard(self.core.cursor(), |c| Self::routine(false, c)); term.draw_partial(|f| { - _ = Lives::scope(&self.core, || { + _ = Lives::scope(&mut self.core, |core| { runtime_scope!(LUA, "root", { - f.render_widget(crate::tasks::Progress::new(&self.core), f.area()); - f.render_widget(crate::notify::Notify::new(&self.core), f.area()); + f.render_widget(crate::tasks::Progress::new(core), f.area()); + f.render_widget(crate::notify::Notify::new(core), f.area()); Ok(()) }) }); diff --git a/yazi-fm/src/main.rs b/yazi-fm/src/main.rs index e9babc5c..f6710142 100644 --- a/yazi-fm/src/main.rs +++ b/yazi-fm/src/main.rs @@ -4,7 +4,7 @@ static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; yazi_macro::mod_pub!(app cmp confirm help input mgr notify pick spot tasks which); -yazi_macro::mod_flat!(dispatcher executor logs panic root router signals); +yazi_macro::mod_flat!(dispatcher executor logs panic renderer root router signals); #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -40,5 +40,7 @@ async fn main() -> anyhow::Result<()> { yazi_dds::serve(); + yazi_actor::init(); + yazi_shared::LOCAL_SET.run_until(app::App::serve()).await } diff --git a/yazi-fm/src/mgr/modal.rs b/yazi-fm/src/mgr/modal.rs index dd578862..acf77a2a 100644 --- a/yazi-fm/src/mgr/modal.rs +++ b/yazi-fm/src/mgr/modal.rs @@ -1,29 +1,24 @@ -use mlua::{ObjectLike, Table}; use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; use tracing::error; -use yazi_binding::elements::render_once; use yazi_core::Core; -use yazi_plugin::LUA; + +use crate::Renderer; pub(crate) struct Modal<'a> { - core: &'a Core, + core: &'a mut Core, } impl<'a> Modal<'a> { #[inline] - pub(crate) fn new(core: &'a Core) -> Self { Self { core } } + pub(crate) fn new(core: &'a mut Core) -> Self { Self { core } } } impl Widget for Modal<'_> { fn render(self, area: Rect, buf: &mut Buffer) { - let mut f = || { - let area = yazi_binding::elements::Rect::from(area); - let root = LUA.globals().raw_get::
("Modal")?.call_method::
("new", area)?; + let result = + Renderer::new(self.core, "Modal").with_redrawer("children_redraw").render(area, buf); - render_once(root.call_method("children_redraw", ())?, buf, |p| self.core.mgr.area(p)); - Ok::<_, mlua::Error>(()) - }; - if let Err(e) = f() { + if let Err(e) = result { error!("Failed to redraw the `Modal` component:\n{e}"); } } diff --git a/yazi-fm/src/renderer.rs b/yazi-fm/src/renderer.rs new file mode 100644 index 00000000..7c53af05 --- /dev/null +++ b/yazi-fm/src/renderer.rs @@ -0,0 +1,44 @@ +use mlua::{ObjectLike, Table}; +use ratatui::{buffer::Buffer, layout::Rect}; +use yazi_binding::elements::Renderables; +use yazi_core::Core; +use yazi_plugin::LUA; + +pub(super) struct Renderer<'a> { + core: &'a mut Core, + component: &'a str, + constructor: &'a str, + redrawer: &'a str, +} + +impl<'a> Renderer<'a> { + pub(super) fn new(core: &'a mut Core, component: &'a str) -> Self { + Self { core, component, constructor: "new", redrawer: "redraw" } + } + + pub(super) fn with_constructor(mut self, constructor: &'a str) -> Self { + self.constructor = constructor; + self + } + + pub(super) fn with_redrawer(mut self, redrawer: &'a str) -> Self { + self.redrawer = redrawer; + self + } + + pub(super) fn render(self, area: Rect, buf: &mut Buffer) -> mlua::Result<()> { + let area = yazi_binding::elements::Rect::from(area); + + let value = LUA + .globals() + .raw_get::
(self.component)? + .call_method::
(self.constructor, area)? + .call_method("redraw", ())?; + + Renderables::reduce(value, |element| { + element.render_with(buf, |p| self.core.mgr.area(p)); + }); + + Ok::<_, mlua::Error>(()) + } +} diff --git a/yazi-fm/src/root.rs b/yazi-fm/src/root.rs index 77f60683..67d4daf6 100644 --- a/yazi-fm/src/root.rs +++ b/yazi-fm/src/root.rs @@ -1,18 +1,18 @@ use mlua::{ObjectLike, Table}; use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; use tracing::error; -use yazi_binding::elements::render_once; use yazi_core::Core; use yazi_plugin::LUA; use super::{cmp, confirm, help, input, mgr, pick, spot, tasks, which}; +use crate::Renderer; pub(super) struct Root<'a> { - core: &'a Core, + core: &'a mut Core, } impl<'a> Root<'a> { - pub(super) fn new(core: &'a Core) -> Self { Self { core } } + pub(super) fn new(core: &'a mut Core) -> Self { Self { core } } pub(super) fn reflow(area: Rect) -> mlua::Result
{ let area = yazi_binding::elements::Rect::from(area); @@ -23,14 +23,7 @@ impl<'a> Root<'a> { impl Widget for Root<'_> { fn render(self, area: Rect, buf: &mut Buffer) { - let mut f = || { - let area = yazi_binding::elements::Rect::from(area); - let root = LUA.globals().raw_get::
("Root")?.call_method::
("new", area)?; - - render_once(root.call_method("redraw", ())?, buf, |p| self.core.mgr.area(p)); - Ok::<_, mlua::Error>(()) - }; - if let Err(e) = f() { + if let Err(e) = Renderer::new(self.core, "Root").render(area, buf) { error!("Failed to redraw the `Root` component:\n{e}"); } diff --git a/yazi-fm/src/tasks/list.rs b/yazi-fm/src/tasks/list.rs index b09c46be..a75f35f1 100644 --- a/yazi-fm/src/tasks/list.rs +++ b/yazi-fm/src/tasks/list.rs @@ -1,29 +1,21 @@ -use mlua::{ObjectLike, Table}; use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; use tracing::error; -use yazi_binding::elements::render_once; use yazi_core::Core; -use yazi_plugin::LUA; + +use crate::Renderer; pub(crate) struct List<'a> { - core: &'a Core, + core: &'a mut Core, } impl<'a> List<'a> { #[inline] - pub(crate) fn new(core: &'a Core) -> Self { Self { core } } + pub(crate) fn new(core: &'a mut Core) -> Self { Self { core } } } impl Widget for List<'_> { fn render(self, area: Rect, buf: &mut Buffer) { - let mut f = || { - let area = yazi_binding::elements::Rect::from(area); - let root = LUA.globals().raw_get::
("Tasks")?.call_method::
("new", area)?; - - render_once(root.call_method("redraw", ())?, buf, |p| self.core.mgr.area(p)); - Ok::<_, mlua::Error>(()) - }; - if let Err(e) = f() { + if let Err(e) = Renderer::new(self.core, "Tasks").render(area, buf) { error!("Failed to redraw the `Tasks` component:\n{e}"); } } diff --git a/yazi-fm/src/tasks/progress.rs b/yazi-fm/src/tasks/progress.rs index 1040c704..cb500523 100644 --- a/yazi-fm/src/tasks/progress.rs +++ b/yazi-fm/src/tasks/progress.rs @@ -1,30 +1,24 @@ -use mlua::{ObjectLike, Table}; use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; use tracing::error; -use yazi_binding::elements::render_once; use yazi_config::LAYOUT; use yazi_core::Core; -use yazi_plugin::LUA; + +use crate::Renderer; pub(crate) struct Progress<'a> { - core: &'a Core, + core: &'a mut Core, } impl<'a> Progress<'a> { - pub(crate) fn new(core: &'a Core) -> Self { Self { core } } + pub(crate) fn new(core: &'a mut Core) -> Self { Self { core } } } impl Widget for Progress<'_> { fn render(self, _: Rect, buf: &mut Buffer) { - let mut f = || { - let area = yazi_binding::elements::Rect::from(LAYOUT.get().progress); - let progress = - LUA.globals().raw_get::
("Progress")?.call_method::
("use", area)?; + let area = LAYOUT.get().progress; + let result = Renderer::new(self.core, "Progress").with_constructor("use").render(area, buf); - render_once(progress.call_method("redraw", ())?, buf, |p| self.core.mgr.area(p)); - Ok::<_, mlua::Error>(()) - }; - if let Err(e) = f() { + if let Err(e) = result { error!("Failed to redraw the `Progress` component:\n{e}"); } } diff --git a/yazi-fm/src/tasks/tasks.rs b/yazi-fm/src/tasks/tasks.rs index c9e98835..f7fd5193 100644 --- a/yazi-fm/src/tasks/tasks.rs +++ b/yazi-fm/src/tasks/tasks.rs @@ -5,11 +5,11 @@ use yazi_core::{Core, tasks::TASKS_PERCENT}; use crate::tasks::List; pub(crate) struct Tasks<'a> { - core: &'a Core, + core: &'a mut Core, } impl<'a> Tasks<'a> { - pub(crate) fn new(core: &'a Core) -> Self { Self { core } } + pub(crate) fn new(core: &'a mut Core) -> Self { Self { core } } pub(super) fn area(area: Rect) -> Rect { let chunk = layout::Layout::vertical([ diff --git a/yazi-plugin/src/elements/elements.rs b/yazi-plugin/src/elements/elements.rs index 84e06003..a11babc4 100644 --- a/yazi-plugin/src/elements/elements.rs +++ b/yazi-plugin/src/elements/elements.rs @@ -123,7 +123,7 @@ pub(super) fn redraw(lua: &Lua) -> mlua::Result { Value::UserData(ud) => lua.create_sequence_from([ud]), _ => { error!( - "Failed to `redraw()` the `{}` component: expected a table or UserData", + "Failed to `redraw()` the `{}` component: expected an element or a table of them", id.display(), ); lua.create_table() diff --git a/yazi-shim/src/cell/ro_cell.rs b/yazi-shim/src/cell/ro_cell.rs index b5d48f99..fcfa8b87 100644 --- a/yazi-shim/src/cell/ro_cell.rs +++ b/yazi-shim/src/cell/ro_cell.rs @@ -55,6 +55,7 @@ impl RoCell { self.inner.get().replace(MaybeUninit::uninit()).assume_init() } } + } impl Default for RoCell {