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 {