perf: cheaper sync context initialization (#643)

This commit is contained in:
三咲雅 · Misaki Masa 2024-02-08 12:14:01 +08:00 committed by GitHub
parent 0d7e977076
commit c12a735f68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 219 additions and 211 deletions

View file

@ -1,9 +1,8 @@
use mlua::{AnyUserData, Lua, MetaMethod, UserDataFields, UserDataMethods, Value};
use yazi_config::LAYOUT;
use super::Folder;
pub struct Active<'a, 'b> {
pub(super) struct Active<'a, 'b> {
scope: &'b mlua::Scope<'a, 'a>,
inner: &'a yazi_core::tab::Tab,
@ -50,9 +49,9 @@ impl<'a, 'b> Active<'a, 'b> {
ud.set_named_user_value("conf", self.scope.create_any_userdata_ref(&self.inner.conf)?)?;
ud.set_named_user_value(
"parent",
self.inner.parent.as_ref().and_then(|p| Folder::new(self.scope, p).make(None).ok()),
self.inner.parent.as_ref().and_then(|p| Folder::make(self.scope, p).ok()),
)?;
ud.set_named_user_value("current", Folder::new(self.scope, &self.inner.current).make(None)?)?;
ud.set_named_user_value("current", Folder::make(self.scope, &self.inner.current)?)?;
ud.set_named_user_value("preview", self.preview(self.inner)?)?;
Ok(ud)
@ -60,7 +59,6 @@ impl<'a, 'b> Active<'a, 'b> {
fn preview(&self, tab: &'a yazi_core::tab::Tab) -> mlua::Result<AnyUserData<'a>> {
let inner = &tab.preview;
let window = Some((inner.skip, LAYOUT.load().preview.height as usize));
let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value(
@ -70,7 +68,7 @@ impl<'a, 'b> Active<'a, 'b> {
.hovered()
.filter(|&f| f.is_dir())
.and_then(|f| tab.history(&f.url))
.and_then(|f| Folder::new(self.scope, f).make(window).ok()),
.and_then(|f| Folder::make(self.scope, f).ok()),
)?;
Ok(ud)

122
yazi-fm/src/lives/file.rs Normal file
View file

@ -0,0 +1,122 @@
use std::ops::Deref;
use mlua::{IntoLua, Lua, UserDataFields, UserDataMethods};
use yazi_config::THEME;
use yazi_plugin::{bindings::{Cast, Cha, Icon, Range}, elements::Style, url::Url};
use yazi_shared::MIME_DIR;
use super::CtxRef;
pub(super) struct File {
idx: usize,
folder: *const yazi_core::folder::Folder,
}
impl Deref for File {
type Target = yazi_shared::fs::File;
fn deref(&self) -> &Self::Target { &self.folder().files[self.idx] }
}
impl File {
#[inline]
pub(super) fn new(idx: usize, folder: &yazi_core::folder::Folder) -> Self { Self { idx, folder } }
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Self>(|reg| {
reg.add_field_method_get("url", |lua, me| Url::cast(lua, me.url.clone()));
reg.add_field_method_get("cha", |lua, me| Cha::cast(lua, me.cha));
reg.add_field_method_get("link_to", |lua, me| {
me.link_to.as_ref().cloned().map(|u| Url::cast(lua, u)).transpose()
});
reg.add_field_method_get("name", |lua, me| {
me.url.file_name().map(|n| lua.create_string(n.as_encoded_bytes())).transpose()
});
reg.add_method("size", |_, me, ()| {
Ok(if me.is_dir() { me.folder().files.sizes.get(&me.url).copied() } else { Some(me.len) })
});
reg.add_method("mime", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
Ok(cx.manager.mimetype.get(&me.url).cloned())
});
reg.add_method("prefix", |lua, me, ()| {
if !me.folder().cwd.is_search() {
return Ok(None);
}
let mut p = me.url.strip_prefix(&me.folder().cwd).unwrap_or(&me.url).components();
p.next_back();
Some(lua.create_string(p.as_path().as_os_str().as_encoded_bytes())).transpose()
});
reg.add_method("icon", |lua, me, ()| {
THEME
.icons
.iter()
.find(|&x| x.name.match_path(&me.url, me.is_dir()))
.map(|x| Icon::cast(lua, x))
.transpose()
});
reg.add_method("style", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let mime =
if me.is_dir() { Some(MIME_DIR) } else { cx.manager.mimetype.get(&me.url).map(|x| &**x) };
Ok(THEME.filetypes.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style)))
});
reg.add_method("is_hovered", |_, me, ()| {
Ok(matches!(me.folder().hovered(), Some(f) if f.url == me.url))
});
reg.add_method("is_yanked", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
Ok(if !cx.manager.yanked.1.contains(&me.url) {
0u8
} else if cx.manager.yanked.0 {
2u8
} else {
1u8
})
});
reg.add_method("is_selected", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let selected = me.folder().files.is_selected(&me.url);
Ok(if !cx.manager.active().mode.is_visual() {
selected
} else {
cx.manager.active().mode.pending(me.idx, selected)
})
});
reg.add_method("found", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let Some(finder) = &cx.manager.active().finder else {
return Ok(None);
};
let Some(idx) = finder.matched_idx(&me.url) else {
return Ok(None);
};
Some(lua.create_sequence_from([idx.into_lua(lua)?, finder.matched().len().into_lua(lua)?]))
.transpose()
});
reg.add_method("highlights", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let Some(finder) = &cx.manager.active().finder else {
return Ok(None);
};
let Some(h) = me.name().and_then(|n| finder.filter.highlighted(n)) else {
return Ok(None);
};
Ok(Some(h.into_iter().map(Range::from).collect::<Vec<_>>()))
});
})?;
Ok(())
}
#[inline]
fn folder(&self) -> &yazi_core::folder::Folder { unsafe { &*self.folder } }
}

View file

@ -0,0 +1,43 @@
use std::ops::{Deref, Range};
use mlua::{Lua, MetaMethod, UserDataMethods};
use super::File;
pub(super) struct Files {
folder: *const yazi_core::folder::Folder,
window: Range<usize>,
}
impl Deref for Files {
type Target = yazi_core::folder::Files;
fn deref(&self) -> &Self::Target { &self.folder().files }
}
impl Files {
#[inline]
pub(super) fn new(folder: &yazi_core::folder::Folder, window: Range<usize>) -> Self {
Self { folder, window }
}
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Self>(|reg| {
reg.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.window.end - me.window.start));
reg.add_meta_method(MetaMethod::Index, |lua, me, mut key: usize| {
key += me.window.start;
if key > me.window.end || key == 0 {
Ok(None)
} else {
Some(lua.create_any_userdata(File::new(key - 1, me.folder()))).transpose()
}
});
})?;
Ok(())
}
#[inline]
fn folder(&self) -> &yazi_core::folder::Folder { unsafe { &*self.folder } }
}

View file

@ -1,150 +1,29 @@
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, UserDataFields, UserDataMethods, Value};
use yazi_config::{LAYOUT, THEME};
use yazi_plugin::{bindings::{Cast, File, Icon, Range}, elements::Style, url::Url};
use yazi_shared::MIME_DIR;
use mlua::{AnyUserData, Lua, UserDataFields};
use yazi_config::LAYOUT;
use yazi_plugin::{bindings::Cast, url::Url};
use super::{CtxRef, FolderRef};
use super::{File, Files};
pub struct Folder<'a, 'b> {
scope: &'b mlua::Scope<'a, 'a>,
pub(super) struct Folder;
inner: &'a yazi_core::folder::Folder,
}
impl<'a, 'b> Folder<'a, 'b> {
impl Folder {
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<yazi_core::folder::Folder>(|reg| {
reg.add_field_method_get("cwd", |lua, me| Url::cast(lua, me.cwd.clone()));
reg.add_field_method_get("files", |lua, me| {
lua.create_any_userdata(Files::new(me, 0..me.files.len()))
});
reg.add_field_method_get("window", |lua, me| {
lua.create_any_userdata(Files::new(
me,
me.offset..me.files.len().min(me.offset + LAYOUT.load().preview.height as usize),
))
});
reg.add_field_method_get("offset", |_, me| Ok(me.offset));
reg.add_field_method_get("cursor", |_, me| Ok(me.cursor));
reg.add_field_function_get("window", |_, me| me.named_user_value::<Value>("window"));
reg.add_field_function_get("files", |_, me| me.named_user_value::<AnyUserData>("files"));
reg.add_field_function_get("hovered", |_, me| me.named_user_value::<Value>("hovered"));
})?;
lua.register_userdata_type::<yazi_core::folder::Files>(|reg| {
reg.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len()));
reg.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {
let iter = lua.create_function(|lua, (me, i): (AnyUserData, usize)| {
let files = me.borrow::<yazi_core::folder::Files>()?;
let i = i + 1;
Ok(if i > files.len() {
mlua::Variadic::new()
} else {
mlua::Variadic::from_iter([
i.into_lua(lua)?,
File::cast(lua, files[i - 1].clone())?.into_lua(lua)?,
])
})
})?;
Ok((iter, me, 0))
});
})?;
File::register(lua, |reg| {
reg.add_function("size", |_, me: AnyUserData| {
let file = me.borrow::<yazi_shared::fs::File>()?;
if !file.is_dir() {
return Ok(Some(file.len));
}
let folder = me.named_user_value::<FolderRef>("folder")?;
Ok(folder.files.sizes.get(&file.url).copied())
});
reg.add_function("mime", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let file = me.borrow::<yazi_shared::fs::File>()?;
Ok(cx.manager.mimetype.get(&file.url).cloned())
});
reg.add_function("prefix", |lua, me: AnyUserData| {
let folder = me.named_user_value::<FolderRef>("folder")?;
if !folder.cwd.is_search() {
return Ok(None);
}
let file = me.borrow::<yazi_shared::fs::File>()?;
let mut p = file.url.strip_prefix(&folder.cwd).unwrap_or(&file.url).components();
p.next_back();
Some(lua.create_string(p.as_path().as_os_str().as_encoded_bytes())).transpose()
});
reg.add_method("icon", |lua, me, ()| {
THEME
.icons
.iter()
.find(|&x| x.name.match_path(&me.url, me.is_dir()))
.map(|x| Icon::cast(lua, x))
.transpose()
});
reg.add_function("style", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let file = me.borrow::<yazi_shared::fs::File>()?;
let mime = if file.is_dir() {
Some(MIME_DIR)
} else {
cx.manager.mimetype.get(&file.url).map(|x| &**x)
};
Ok(THEME.filetypes.iter().find(|&x| x.matches(&file, mime)).map(|x| Style::from(x.style)))
});
reg.add_function("is_hovered", |_, me: AnyUserData| {
let folder = me.named_user_value::<FolderRef>("folder")?;
let file = me.borrow::<yazi_shared::fs::File>()?;
Ok(matches!(folder.hovered(), Some(f) if f.url == file.url))
});
reg.add_function("is_yanked", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let file = me.borrow::<yazi_shared::fs::File>()?;
Ok(if !cx.manager.yanked.1.contains(&file.url) {
0u8
} else if cx.manager.yanked.0 {
2u8
} else {
1u8
})
});
reg.add_function("is_selected", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let folder = me.named_user_value::<FolderRef>("folder")?;
let file = me.borrow::<yazi_shared::fs::File>()?;
let selected = folder.files.is_selected(&file.url);
Ok(if !cx.manager.active().mode.is_visual() {
selected
} else {
let pos: isize = me.named_user_value("pos")?;
cx.manager.active().mode.pending((folder.offset as isize + pos) as usize, selected)
})
});
reg.add_function("found", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let Some(finder) = &cx.manager.active().finder else {
return Ok(None);
};
let file = me.borrow::<yazi_shared::fs::File>()?;
if let Some(idx) = finder.matched_idx(&file.url) {
return Some(
lua.create_sequence_from([idx.into_lua(lua)?, finder.matched().len().into_lua(lua)?]),
)
.transpose();
}
Ok(None)
});
reg.add_function("highlights", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
let Some(finder) = &cx.manager.active().finder else {
return Ok(None);
};
let file = me.borrow::<yazi_shared::fs::File>()?;
let Some(h) = file.name().and_then(|n| finder.filter.highlighted(n)) else {
return Ok(None);
};
Ok(Some(h.into_iter().map(Range::from).collect::<Vec<_>>()))
reg.add_field_method_get("hovered", |lua, me| {
me.hovered().map(|_| lua.create_any_userdata(File::new(me.cursor, me))).transpose()
});
})?;
@ -152,45 +31,12 @@ impl<'a, 'b> Folder<'a, 'b> {
}
}
impl<'a, 'b> Folder<'a, 'b> {
pub(crate) fn new(scope: &'b mlua::Scope<'a, 'a>, inner: &'a yazi_core::folder::Folder) -> Self {
Self { scope, inner }
}
pub(crate) fn make(&self, window: Option<(usize, usize)>) -> mlua::Result<AnyUserData<'a>> {
let window =
window.unwrap_or_else(|| (self.inner.offset, LAYOUT.load().preview.height as usize));
let ud = self.scope.create_any_userdata_ref(self.inner)?;
ud.set_named_user_value(
"window",
self
.inner
.files
.iter()
.skip(window.0)
.take(window.1)
.enumerate()
.filter_map(|(i, f)| self.file(i as isize, f).ok())
.collect::<Vec<_>>(),
)?;
ud.set_named_user_value("files", self.scope.create_any_userdata_ref(&self.inner.files)?)?;
ud.set_named_user_value(
"hovered",
self
.inner
.hovered()
.and_then(|h| self.file(self.inner.cursor as isize - window.0 as isize, h).ok()),
)?;
Ok(ud)
}
fn file(&self, pos: isize, inner: &'a yazi_shared::fs::File) -> mlua::Result<AnyUserData<'a>> {
let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("pos", pos)?;
ud.set_named_user_value("folder", self.scope.create_any_userdata_ref(self.inner)?)?;
Ok(ud)
impl Folder {
#[inline]
pub(crate) fn make<'a>(
scope: &mlua::Scope<'a, 'a>,
inner: &'a yazi_core::folder::Folder,
) -> mlua::Result<AnyUserData<'a>> {
scope.create_any_userdata_ref(inner)
}
}

View file

@ -12,6 +12,8 @@ pub(crate) struct Lives;
impl Lives {
pub(crate) fn register() -> mlua::Result<()> {
super::Active::register(&LUA)?;
super::File::register(&LUA)?;
super::Files::register(&LUA)?;
super::Folder::register(&LUA)?;
super::Tabs::register(&LUA)?;
super::Tasks::register(&LUA)?;

View file

@ -1,16 +1,19 @@
#![allow(clippy::module_inception)]
mod active;
mod file;
mod files;
mod folder;
mod lives;
mod tabs;
mod tasks;
pub(super) use active::*;
pub(super) use folder::*;
use active::*;
use file::*;
use files::*;
use folder::*;
pub(super) use lives::*;
pub(super) use tabs::*;
pub(super) use tasks::*;
use tabs::*;
use tasks::*;
type CtxRef<'lua> = mlua::UserDataRef<'lua, crate::Ctx>;
type FolderRef<'lua> = mlua::UserDataRef<'lua, yazi_core::folder::Folder>;

View file

@ -1,6 +1,10 @@
// TODO: unsafe
use mlua::{AnyUserData, Lua, MetaMethod, UserDataFields, UserDataMethods, Value};
pub struct Tabs<'a, 'b> {
use super::Folder;
pub(super) struct Tabs<'a, 'b> {
scope: &'b mlua::Scope<'a, 'a>,
inner: &'a yazi_core::manager::Tabs,
@ -60,18 +64,12 @@ impl<'a, 'b> Tabs<'a, 'b> {
fn tab(&self, inner: &'a yazi_core::tab::Tab) -> mlua::Result<AnyUserData<'a>> {
let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("parent", inner.parent.as_ref().and_then(|p| self.folder(p).ok()))?;
ud.set_named_user_value("current", self.folder(&inner.current)?)?;
ud.set_named_user_value(
"parent",
inner.parent.as_ref().and_then(|p| Folder::make(self.scope, p).ok()),
)?;
Ok(ud)
}
pub(crate) fn folder(
&self,
inner: &'a yazi_core::folder::Folder,
) -> mlua::Result<AnyUserData<'a>> {
let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("files", self.scope.create_any_userdata_ref(&inner.files)?)?;
ud.set_named_user_value("current", Folder::make(self.scope, &inner.current)?)?;
Ok(ud)
}

View file

@ -1,6 +1,6 @@
use mlua::{AnyUserData, Lua, LuaSerdeExt, UserDataFields};
pub struct Tasks<'a, 'b> {
pub(super) struct Tasks<'a, 'b> {
scope: &'b mlua::Scope<'a, 'a>,
inner: &'a yazi_core::tasks::Tasks,

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, Lua, UserDataFields, UserDataRef, UserDataRegistry};
use mlua::{AnyUserData, Lua, UserDataFields, UserDataRef};
use super::{Cast, Cha};
use crate::url::Url;
@ -8,10 +8,7 @@ pub type FileRef<'lua> = UserDataRef<'lua, yazi_shared::fs::File>;
pub struct File;
impl File {
pub fn register(
lua: &Lua,
f: impl FnOnce(&mut UserDataRegistry<yazi_shared::fs::File>),
) -> mlua::Result<()> {
pub fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<yazi_shared::fs::File>(|reg| {
reg.add_field_method_get("url", |lua, me| Url::cast(lua, me.url.clone()));
reg.add_field_method_get("cha", |lua, me| Cha::cast(lua, me.cha));
@ -23,8 +20,6 @@ impl File {
reg.add_field_method_get("name", |lua, me| {
me.url.file_name().map(|n| lua.create_string(n.as_encoded_bytes())).transpose()
});
f(reg);
})
}
}

View file

@ -7,7 +7,7 @@ pub fn slim_lua() -> mlua::Result<Lua> {
// Base
bindings::Cha::register(&lua)?;
bindings::File::register(&lua, |_| {})?;
bindings::File::register(&lua)?;
crate::url::pour(&lua)?;
crate::fs::install(&lua)?;

View file

@ -17,6 +17,7 @@ pub fn init() {
lua.load(include_str!("../preset/state.lua")).exec()?;
lua.load(include_str!("../preset/ya.lua")).exec()?;
crate::bindings::Cha::register(lua)?;
crate::bindings::File::register(lua)?;
crate::bindings::Icon::register(lua)?;
crate::elements::pour(lua)?;
crate::url::pour(lua)?;