From 77e10053ca1643d221fce4c5731db6fad4a29c6a Mon Sep 17 00:00:00 2001 From: sxyazi Date: Tue, 3 Oct 2023 17:26:13 +0800 Subject: [PATCH] .. --- app/src/app.rs | 4 +- app/src/manager/folder.rs | 2 +- app/src/status/layout.rs | 2 +- cspell.json | 2 +- plugin/preset/components/folder.lua | 12 +-- plugin/src/bindings/manager.rs | 123 +++++++++++++++------------- plugin/src/components.rs | 29 ++----- plugin/src/lib.rs | 2 + plugin/src/scope.rs | 14 ++++ 9 files changed, 97 insertions(+), 93 deletions(-) create mode 100644 plugin/src/scope.rs diff --git a/app/src/app.rs b/app/src/app.rs index b672680f6..be4dff505 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -76,7 +76,9 @@ impl App { fn dispatch_render(&mut self) { if let Some(term) = &mut self.term { 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() { f.set_cursor(x, y); diff --git a/app/src/manager/folder.rs b/app/src/manager/folder.rs index 46f49ea10..bee1fbab3 100644 --- a/app/src/manager/folder.rs +++ b/app/src/manager/folder.rs @@ -41,7 +41,7 @@ impl<'a> Folder<'a> { impl<'a> Widget for Folder<'a> { 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() { info!("{:?}", x); return; diff --git a/app/src/status/layout.rs b/app/src/status/layout.rs index 642dc8fa2..c6d42c9e4 100644 --- a/app/src/status/layout.rs +++ b/app/src/status/layout.rs @@ -13,7 +13,7 @@ impl<'a> Layout<'a> { impl<'a> Widget for Layout<'a> { 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() { info!("{:?}", x); return; diff --git a/cspell.json b/cspell.json index df1359790..d9bb06625 100644 --- a/cspell.json +++ b/cspell.json @@ -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"]} diff --git a/plugin/preset/components/folder.lua b/plugin/preset/components/folder.lua index 647c0fbad..62537d50b 100644 --- a/plugin/preset/components/folder.lua +++ b/plugin/preset/components/folder.lua @@ -16,17 +16,9 @@ function Folder:by_kind(kind) end end -function Folder:window(kind) - local folder = self:by_kind(kind) - if folder ~= nil then - return folder.files:slice(folder.offset, MANAGER.layout.folder_height()) - end -end +function Folder:window(kind) return (self:by_kind(kind) or {}).window end -function Folder:hovered(kind) - local folder = self:by_kind(kind) - return folder and folder.hovered -end +function Folder:hovered(kind) return (self:by_kind(kind) or {}).hovered end function Folder:parent(area) local window = self:window(self.Kind.Parent) diff --git a/plugin/src/bindings/manager.rs b/plugin/src/bindings/manager.rs index 44b14ac08..123d52c09 100644 --- a/plugin/src/bindings/manager.rs +++ b/plugin/src/bindings/manager.rs @@ -1,12 +1,31 @@ -use config::THEME; -use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserDataFields, UserDataMethods, Value}; +use config::{MANAGER, THEME}; +use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value}; use super::Url; 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<()> { LUA.register_userdata_type::(|reg| { reg.add_field_function_get("mode", |_, me| me.named_user_value::("mode")); @@ -29,6 +48,7 @@ impl Manager { 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::("window")); reg.add_field_function_get("files", |_, me| me.named_user_value::("files")); reg.add_field_function_get("hovered", |_, me| me.named_user_value::("hovered")); })?; @@ -38,22 +58,20 @@ impl Manager { reg.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| { let iter = lua.create_function(|lua, (me, i): (AnyUserData, usize)| { - let items: Vec = me.named_user_value("items")?; - + let files = me.borrow::()?; let i = i + 1; - Ok(if i > items.len() { + Ok(if i > files.len() { mlua::Variadic::new() } else { - let item = items[i - 1].clone().into_lua(lua)?; - mlua::Variadic::from_iter([i.into_lua(lua)?, item]) + mlua::Variadic::from_iter([i.into_lua(lua)?, File::from(&files[i - 1]).into_lua(lua)?]) }) })?; Ok((iter, me, 0)) }); reg.add_function("slice", |_, (me, skip, take): (AnyUserData, usize, usize)| { - let items = me.named_user_value::>("items")?; - Ok(items.iter().skip(skip).take(take).cloned().collect::>()) + let files = me.borrow::()?; + Ok(files.iter().skip(skip).take(take).map(File::from).collect::>()) }); })?; @@ -87,61 +105,56 @@ impl Manager { Ok(()) } - pub(crate) fn make<'a>( - scope: &mlua::Scope<'a, 'a>, - inner: &'a core::manager::Manager, - ) -> mlua::Result> { - let ud = scope.create_any_userdata_ref(inner)?; - ud.set_named_user_value("mode", scope.create_any_userdata_ref(inner.active().mode())?)?; - ud.set_named_user_value( - "parent", - inner.parent().and_then(|p| Self::folder(scope, inner, p).ok()), - )?; - ud.set_named_user_value("current", Self::folder(scope, inner, inner.current())?)?; - ud.set_named_user_value("preview", Self::preview(scope, inner, inner.active())?)?; - - Ok(ud) + pub(crate) fn new(scope: &'b mlua::Scope<'a, 'a>, inner: &'a core::manager::Manager) -> Self { + Self { scope, inner } } - pub(crate) fn folder<'a>( - scope: &mlua::Scope<'a, 'a>, - manager: &'a core::manager::Manager, - inner: &'a core::manager::Folder, - ) -> mlua::Result> { - let ud = scope.create_any_userdata_ref(inner)?; - ud.set_named_user_value("files", Self::files(scope, manager, &inner.files)?)?; + pub(crate) fn make(&self) -> mlua::Result> { + let ud = self.scope.create_any_userdata_ref(self.inner)?; ud.set_named_user_value( - "hovered", - inner.hovered.as_ref().and_then(|h| Self::file(scope, manager, h).ok()), + "mode", + self.scope.create_any_userdata_ref(self.inner.active().mode())?, )?; + ud.set_named_user_value("parent", self.inner.parent().and_then(|p| self.folder(p, None).ok()))?; + 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) } - fn files<'a>( - scope: &mlua::Scope<'a, 'a>, - manager: &'a core::manager::Manager, - inner: &'a core::files::Files, + pub(crate) fn folder( + &self, + inner: &'a core::manager::Folder, + window: Option<(usize, usize)>, ) -> mlua::Result> { - let ud = scope.create_any_userdata_ref(inner)?; + let window = window.unwrap_or_else(|| (inner.offset(), MANAGER.layout.folder_height())); + + let ud = self.scope.create_any_userdata_ref(inner)?; ud.set_named_user_value( - "items", - inner.iter().filter_map(|f| Self::file(scope, manager, f).ok()).collect::>(), + "window", + inner + .files + .iter() + .skip(window.0) + .take(window.1) + .filter_map(|f| self.file(f).ok()) + .collect::>(), )?; + 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) } - fn file<'a>( - scope: &mlua::Scope<'a, 'a>, - manager: &'a core::manager::Manager, - inner: &'a core::files::File, - ) -> mlua::Result> { - let ud = scope.create_any_userdata_ref(inner)?; + fn files(&self, inner: &'a core::files::Files) -> mlua::Result> { + self.scope.create_any_userdata_ref(inner) + } + fn file(&self, inner: &'a core::files::File) -> mlua::Result> { + let ud = self.scope.create_any_userdata_ref(inner)?; ud.set_named_user_value( "icon", - scope.create_function(|_, ()| { + self.scope.create_function(|_, ()| { Ok( THEME .icons @@ -154,8 +167,8 @@ impl Manager { ud.set_named_user_value( "style", - scope.create_function(|_, ()| { - let mime = manager.mimetype.get(inner.url()); + self.scope.create_function(|_, ()| { + let mime = self.inner.mimetype.get(inner.url()); Ok( THEME .filetypes @@ -169,14 +182,10 @@ impl Manager { Ok(ud) } - fn preview<'a>( - scope: &mlua::Scope<'a, 'a>, - manager: &'a core::manager::Manager, - tab: &'a core::manager::Tab, - ) -> mlua::Result> { + fn preview(&self, tab: &'a core::manager::Tab) -> mlua::Result> { 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( "folder", inner @@ -184,7 +193,7 @@ impl Manager { .as_ref() .filter(|l| l.is_folder()) .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) diff --git a/plugin/src/components.rs b/plugin/src/components.rs index 2384e4406..90cd5ef98 100644 --- a/plugin/src/components.rs +++ b/plugin/src/components.rs @@ -1,23 +1,14 @@ -use core::Ctx; - use mlua::{Result, Table, TableExt}; use ratatui::layout; -use crate::{bindings, layout::{Paragraph, Rect}, GLOBALS, LUA}; +use crate::{layout::{Paragraph, Rect}, GLOBALS, LUA}; pub struct Status; impl Status { - pub fn render(cx: &Ctx, area: layout::Rect) -> Result> { - LUA.scope(|scope| { - let tbl = LUA.create_table()?; - 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)) - }) + pub fn render(area: layout::Rect) -> Result> { + let comp: Table = GLOBALS.get("Status")?; + comp.call_method::<_, _>("render", Rect(area)) } } @@ -32,14 +23,8 @@ impl Folder { Ok(tbl) } - pub fn render(self, cx: &Ctx, area: layout::Rect) -> Result> { - LUA.scope(|scope| { - let tbl = LUA.create_table()?; - 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()?)) - }) + pub fn render(self, area: layout::Rect) -> Result> { + let comp: Table = GLOBALS.get("Folder")?; + comp.call_method::<_, _>("render", (Rect(area), self.args()?)) } } diff --git a/plugin/src/lib.rs b/plugin/src/lib.rs index 4a6fe9598..f4926f6b7 100644 --- a/plugin/src/lib.rs +++ b/plugin/src/lib.rs @@ -5,7 +5,9 @@ mod components; mod config; mod layout; mod plugin; +mod scope; pub use components::*; use config::*; pub use plugin::*; +pub use scope::*; diff --git a/plugin/src/scope.rs b/plugin/src/scope.rs new file mode 100644 index 000000000..cda5f607f --- /dev/null +++ b/plugin/src/scope.rs @@ -0,0 +1,14 @@ +use core::Ctx; + +use crate::{bindings, GLOBALS, LUA}; + +pub fn scope(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()) + }); +}