This commit is contained in:
sxyazi 2023-10-03 17:26:13 +08:00
parent 2c2e1668fc
commit e6a4c0e7ab
No known key found for this signature in database
9 changed files with 97 additions and 93 deletions

View file

@ -76,7 +76,9 @@ impl App {
fn dispatch_render(&mut self) { fn dispatch_render(&mut self) {
if let Some(term) = &mut self.term { if let Some(term) = &mut self.term {
let _ = term.draw(|f| { let _ = term.draw(|f| {
f.render_widget(Root::new(&self.cx), f.size()); plugin::scope(&self.cx, || {
f.render_widget(Root::new(&self.cx), f.size());
});
if let Some((x, y)) = self.cx.cursor() { if let Some((x, y)) = self.cx.cursor() {
f.set_cursor(x, y); f.set_cursor(x, y);

View file

@ -41,7 +41,7 @@ impl<'a> Folder<'a> {
impl<'a> Widget for Folder<'a> { impl<'a> Widget for Folder<'a> {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let x = plugin::Folder { kind: self.kind as u8 }.render(self.cx, area); let x = plugin::Folder { kind: self.kind as u8 }.render(area);
if x.is_err() { if x.is_err() {
info!("{:?}", x); info!("{:?}", x);
return; return;

View file

@ -13,7 +13,7 @@ impl<'a> Layout<'a> {
impl<'a> Widget for Layout<'a> { impl<'a> Widget for Layout<'a> {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let x = plugin::Status::render(self.cx, area); let x = plugin::Status::render(area);
if x.is_err() { if x.is_err() {
info!("{:?}", x); info!("{:?}", x);
return; return;

View file

@ -1 +1 @@
{"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"],"version":"0.2"} {"language":"en","version":"0.2","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"]}

View file

@ -16,17 +16,9 @@ function Folder:by_kind(kind)
end end
end end
function Folder:window(kind) function Folder:window(kind) return (self:by_kind(kind) or {}).window end
local folder = self:by_kind(kind)
if folder ~= nil then
return folder.files:slice(folder.offset, MANAGER.layout.folder_height())
end
end
function Folder:hovered(kind) function Folder:hovered(kind) return (self:by_kind(kind) or {}).hovered end
local folder = self:by_kind(kind)
return folder and folder.hovered
end
function Folder:parent(area) function Folder:parent(area)
local window = self:window(self.Kind.Parent) local window = self:window(self.Kind.Parent)

View file

@ -1,12 +1,31 @@
use config::THEME; use config::{MANAGER, THEME};
use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserDataFields, UserDataMethods, Value}; use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value};
use super::Url; use super::Url;
use crate::{layout::Style, LUA}; use crate::{layout::Style, LUA};
pub struct Manager; struct File(core::files::File);
impl Manager { impl From<&core::files::File> for File {
fn from(value: &core::files::File) -> Self { Self(value.clone()) }
}
impl UserData for File {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("url", |_, me| Ok(Url::from(me.0.url())));
fields.add_field_method_get("length", |_, me| Ok(me.0.length()));
fields.add_field_method_get("link_to", |_, me| Ok(me.0.link_to().map(Url::from)));
fields.add_field_method_get("is_link", |_, me| Ok(me.0.is_link()));
fields.add_field_method_get("is_hidden", |_, me| Ok(me.0.is_hidden()));
}
}
pub struct Manager<'a, 'b> {
scope: &'b mlua::Scope<'a, 'a>,
inner: &'a core::manager::Manager,
}
impl<'a, 'b> Manager<'a, 'b> {
pub(crate) fn init() -> mlua::Result<()> { pub(crate) fn init() -> mlua::Result<()> {
LUA.register_userdata_type::<core::manager::Manager>(|reg| { LUA.register_userdata_type::<core::manager::Manager>(|reg| {
reg.add_field_function_get("mode", |_, me| me.named_user_value::<AnyUserData>("mode")); reg.add_field_function_get("mode", |_, me| me.named_user_value::<AnyUserData>("mode"));
@ -29,6 +48,7 @@ impl Manager {
reg.add_field_method_get("offset", |_, me| Ok(me.offset())); reg.add_field_method_get("offset", |_, me| Ok(me.offset()));
reg.add_field_method_get("cursor", |_, me| Ok(me.cursor())); 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("files", |_, me| me.named_user_value::<AnyUserData>("files"));
reg.add_field_function_get("hovered", |_, me| me.named_user_value::<Value>("hovered")); reg.add_field_function_get("hovered", |_, me| me.named_user_value::<Value>("hovered"));
})?; })?;
@ -38,22 +58,20 @@ impl Manager {
reg.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| { reg.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {
let iter = lua.create_function(|lua, (me, i): (AnyUserData, usize)| { let iter = lua.create_function(|lua, (me, i): (AnyUserData, usize)| {
let items: Vec<AnyUserData> = me.named_user_value("items")?; let files = me.borrow::<core::files::Files>()?;
let i = i + 1; let i = i + 1;
Ok(if i > items.len() { Ok(if i > files.len() {
mlua::Variadic::new() mlua::Variadic::new()
} else { } else {
let item = items[i - 1].clone().into_lua(lua)?; mlua::Variadic::from_iter([i.into_lua(lua)?, File::from(&files[i - 1]).into_lua(lua)?])
mlua::Variadic::from_iter([i.into_lua(lua)?, item])
}) })
})?; })?;
Ok((iter, me, 0)) Ok((iter, me, 0))
}); });
reg.add_function("slice", |_, (me, skip, take): (AnyUserData, usize, usize)| { reg.add_function("slice", |_, (me, skip, take): (AnyUserData, usize, usize)| {
let items = me.named_user_value::<Vec<AnyUserData>>("items")?; let files = me.borrow::<core::files::Files>()?;
Ok(items.iter().skip(skip).take(take).cloned().collect::<Vec<_>>()) Ok(files.iter().skip(skip).take(take).map(File::from).collect::<Vec<_>>())
}); });
})?; })?;
@ -87,61 +105,56 @@ impl Manager {
Ok(()) Ok(())
} }
pub(crate) fn make<'a>( pub(crate) fn new(scope: &'b mlua::Scope<'a, 'a>, inner: &'a core::manager::Manager) -> Self {
scope: &mlua::Scope<'a, 'a>, Self { scope, inner }
inner: &'a core::manager::Manager, }
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?; pub(crate) fn make(&self) -> mlua::Result<AnyUserData<'a>> {
ud.set_named_user_value("mode", scope.create_any_userdata_ref(inner.active().mode())?)?; let ud = self.scope.create_any_userdata_ref(self.inner)?;
ud.set_named_user_value( ud.set_named_user_value(
"parent", "mode",
inner.parent().and_then(|p| Self::folder(scope, inner, p).ok()), self.scope.create_any_userdata_ref(self.inner.active().mode())?,
)?; )?;
ud.set_named_user_value("current", Self::folder(scope, inner, inner.current())?)?; ud.set_named_user_value("parent", self.inner.parent().and_then(|p| self.folder(p, None).ok()))?;
ud.set_named_user_value("preview", Self::preview(scope, inner, inner.active())?)?; ud.set_named_user_value("current", self.folder(self.inner.current(), None)?)?;
ud.set_named_user_value("preview", self.preview(self.inner.active())?)?;
Ok(ud) Ok(ud)
} }
pub(crate) fn folder<'a>( pub(crate) fn folder(
scope: &mlua::Scope<'a, 'a>, &self,
manager: &'a core::manager::Manager,
inner: &'a core::manager::Folder, inner: &'a core::manager::Folder,
window: Option<(usize, usize)>,
) -> mlua::Result<AnyUserData<'a>> { ) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?; let window = window.unwrap_or_else(|| (inner.offset(), MANAGER.layout.folder_height()));
ud.set_named_user_value("files", Self::files(scope, manager, &inner.files)?)?;
let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value( ud.set_named_user_value(
"hovered", "window",
inner.hovered.as_ref().and_then(|h| Self::file(scope, manager, h).ok()), inner
.files
.iter()
.skip(window.0)
.take(window.1)
.filter_map(|f| self.file(f).ok())
.collect::<Vec<_>>(),
)?; )?;
ud.set_named_user_value("files", self.files(&inner.files)?)?;
ud.set_named_user_value("hovered", inner.hovered.as_ref().and_then(|h| self.file(h).ok()))?;
Ok(ud) Ok(ud)
} }
fn files<'a>( fn files(&self, inner: &'a core::files::Files) -> mlua::Result<AnyUserData<'a>> {
scope: &mlua::Scope<'a, 'a>, self.scope.create_any_userdata_ref(inner)
manager: &'a core::manager::Manager,
inner: &'a core::files::Files,
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value(
"items",
inner.iter().filter_map(|f| Self::file(scope, manager, f).ok()).collect::<Vec<_>>(),
)?;
Ok(ud)
} }
fn file<'a>( fn file(&self, inner: &'a core::files::File) -> mlua::Result<AnyUserData<'a>> {
scope: &mlua::Scope<'a, 'a>, let ud = self.scope.create_any_userdata_ref(inner)?;
manager: &'a core::manager::Manager,
inner: &'a core::files::File,
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value( ud.set_named_user_value(
"icon", "icon",
scope.create_function(|_, ()| { self.scope.create_function(|_, ()| {
Ok( Ok(
THEME THEME
.icons .icons
@ -154,8 +167,8 @@ impl Manager {
ud.set_named_user_value( ud.set_named_user_value(
"style", "style",
scope.create_function(|_, ()| { self.scope.create_function(|_, ()| {
let mime = manager.mimetype.get(inner.url()); let mime = self.inner.mimetype.get(inner.url());
Ok( Ok(
THEME THEME
.filetypes .filetypes
@ -169,14 +182,10 @@ impl Manager {
Ok(ud) Ok(ud)
} }
fn preview<'a>( fn preview(&self, tab: &'a core::manager::Tab) -> mlua::Result<AnyUserData<'a>> {
scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
tab: &'a core::manager::Tab,
) -> mlua::Result<AnyUserData<'a>> {
let inner = tab.preview(); let inner = tab.preview();
let ud = scope.create_any_userdata_ref(inner)?; let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value( ud.set_named_user_value(
"folder", "folder",
inner inner
@ -184,7 +193,7 @@ impl Manager {
.as_ref() .as_ref()
.filter(|l| l.is_folder()) .filter(|l| l.is_folder())
.and_then(|l| tab.history(&l.url)) .and_then(|l| tab.history(&l.url))
.and_then(|f| Self::folder(scope, manager, f).ok()), .and_then(|f| self.folder(f, Some((f.offset(), MANAGER.layout.preview_height()))).ok()),
)?; )?;
Ok(ud) Ok(ud)

View file

@ -1,23 +1,14 @@
use core::Ctx;
use mlua::{Result, Table, TableExt}; use mlua::{Result, Table, TableExt};
use ratatui::layout; use ratatui::layout;
use crate::{bindings, layout::{Paragraph, Rect}, GLOBALS, LUA}; use crate::{layout::{Paragraph, Rect}, GLOBALS, LUA};
pub struct Status; pub struct Status;
impl Status { impl Status {
pub fn render(cx: &Ctx, area: layout::Rect) -> Result<Vec<Paragraph>> { pub fn render(area: layout::Rect) -> Result<Vec<Paragraph>> {
LUA.scope(|scope| { let comp: Table = GLOBALS.get("Status")?;
let tbl = LUA.create_table()?; comp.call_method::<_, _>("render", Rect(area))
tbl.set("manager", bindings::Manager::make(scope, &cx.manager)?)?;
tbl.set("tasks", bindings::Tasks::make(scope, &cx.tasks)?)?;
GLOBALS.set("cx", tbl)?;
let comp: Table = GLOBALS.get("Status")?;
comp.call_method::<_, _>("render", Rect(area))
})
} }
} }
@ -32,14 +23,8 @@ impl Folder {
Ok(tbl) Ok(tbl)
} }
pub fn render(self, cx: &Ctx, area: layout::Rect) -> Result<Vec<Paragraph>> { pub fn render(self, area: layout::Rect) -> Result<Vec<Paragraph>> {
LUA.scope(|scope| { let comp: Table = GLOBALS.get("Folder")?;
let tbl = LUA.create_table()?; comp.call_method::<_, _>("render", (Rect(area), self.args()?))
tbl.set("manager", bindings::Manager::make(scope, &cx.manager)?)?;
GLOBALS.set("cx", tbl)?;
let comp: Table = GLOBALS.get("Folder")?;
comp.call_method::<_, _>("render", (Rect(area), self.args()?))
})
} }
} }

View file

@ -5,7 +5,9 @@ mod components;
mod config; mod config;
mod layout; mod layout;
mod plugin; mod plugin;
mod scope;
pub use components::*; pub use components::*;
use config::*; use config::*;
pub use plugin::*; pub use plugin::*;
pub use scope::*;

14
plugin/src/scope.rs Normal file
View file

@ -0,0 +1,14 @@
use core::Ctx;
use crate::{bindings, GLOBALS, LUA};
pub fn scope<F: FnOnce()>(cx: &Ctx, f: F) {
let _ = LUA.scope(|scope| {
let tbl = LUA.create_table()?;
tbl.set("manager", bindings::Manager::new(scope, &cx.manager).make()?)?;
tbl.set("tasks", bindings::Tasks::make(scope, &cx.tasks)?)?;
GLOBALS.set("cx", tbl)?;
Ok(f())
});
}