From 1a1820cf77060ee7defe9b8952cde1105a7090a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Sat, 21 Sep 2024 01:47:34 +0800 Subject: [PATCH] feat: add the `area()` API for renderable elements (#1667) --- yazi-plugin/preset/plugins/archive.lua | 20 ++++++++++---------- yazi-plugin/preset/plugins/extract.lua | 6 +++--- yazi-plugin/src/elements/bar.rs | 5 +++++ yazi-plugin/src/elements/border.rs | 5 +++++ yazi-plugin/src/elements/clear.rs | 6 +++++- yazi-plugin/src/elements/gauge.rs | 1 + yazi-plugin/src/elements/list.rs | 6 +++++- yazi-plugin/src/elements/paragraph.rs | 4 ++++ yazi-plugin/src/macros.rs | 16 ++++++++++++++++ 9 files changed, 54 insertions(+), 15 deletions(-) diff --git a/yazi-plugin/preset/plugins/archive.lua b/yazi-plugin/preset/plugins/archive.lua index e7e3080b..b410984d 100644 --- a/yazi-plugin/preset/plugins/archive.lua +++ b/yazi-plugin/preset/plugins/archive.lua @@ -4,7 +4,7 @@ function M:peek() local limit = self.area.h local paths, sizes = {}, {} - local files, bound, code = self:list_files({ "-p", tostring(self.file.url) }, self.skip, limit) + local files, bound, code = self.list_files({ "-p", tostring(self.file.url) }, self.skip, limit) if code ~= 0 then return ya.preview_widgets(self, { ui.Paragraph(self.area, { @@ -53,7 +53,7 @@ function M:seek(units) end end -function M:spawn_7z(args) +function M.spawn_7z(args) local last_error = nil local try = function(name) local stdout = args[1] == "l" and Command.PIPED or Command.NULL @@ -88,8 +88,8 @@ end --- 1: failed to spawn --- 2: wrong password --- 3: partial success -function M:list_files(args, skip, limit) - local child = self:spawn_7z { "l", "-ba", "-slt", table.unpack(args) } +function M.list_files(args, skip, limit) + local child = M.spawn_7z { "l", "-ba", "-slt", table.unpack(args) } if not child then return {}, 0, 1 end @@ -98,7 +98,7 @@ function M:list_files(args, skip, limit) local key, value = "", "" repeat local next, event = child:read_line() - if event == 1 and self:is_encrypted(next) then + if event == 1 and M.is_encrypted(next) then code = 2 break elseif event == 1 then @@ -145,8 +145,8 @@ end --- 1: failed to spawn --- 2: wrong password --- 3: partial success -function M:list_meta(args) - local child = self:spawn_7z { "l", "-slt", table.unpack(args) } +function M.list_meta(args) + local child = M.spawn_7z { "l", "-slt", table.unpack(args) } if not child then return nil, 1 end @@ -157,7 +157,7 @@ function M:list_meta(args) i = i + 1 local next, event = child:read_line() - if event == 1 and self:is_encrypted(next) then + if event == 1 and M.is_encrypted(next) then code = 2 break elseif event == 1 then @@ -178,8 +178,8 @@ function M:list_meta(args) return typ ~= "" and typ or nil, code end -function M:is_encrypted(s) return s:find(" Wrong password", 1, true) end +function M.is_encrypted(s) return s:find(" Wrong password", 1, true) end -function M:is_tar(url) return require("archive"):list_meta { "-p", tostring(url) } == "tar" end +function M.is_tar(url) return M.list_meta { "-p", tostring(url) } == "tar" end return M diff --git a/yazi-plugin/preset/plugins/extract.lua b/yazi-plugin/preset/plugins/extract.lua index ecc3cd32..3ed701d3 100644 --- a/yazi-plugin/preset/plugins/extract.lua +++ b/yazi-plugin/preset/plugins/extract.lua @@ -48,13 +48,13 @@ function M:try_with(from, pwd, to) end local archive = require("archive") - local child, code = archive:spawn_7z { "x", "-aou", "-p" .. pwd, "-o" .. tostring(tmp), tostring(from) } + local child, code = archive.spawn_7z { "x", "-aou", "-p" .. pwd, "-o" .. tostring(tmp), tostring(from) } if not child then fail("Spawn `7z` and `7zz` both commands failed, error code %s", code) end local output, err = child:wait_with_output() - if output and output.status.code == 2 and archive:is_encrypted(output.stderr) then + if output and output.status.code == 2 and archive.is_encrypted(output.stderr) then fs.remove("dir_clean", tmp) return true -- Need to retry end @@ -77,7 +77,7 @@ function M:tidy(from, to, tmp) end local only = #outs == 1 - if only and not outs[1].cha.is_dir and require("archive"):is_tar(outs[1].url) then + if only and not outs[1].cha.is_dir and require("archive").is_tar(outs[1].url) then self:entry { tostring(outs[1].url), tostring(to) } fs.remove("file", outs[1].url) fs.remove("dir", tmp) diff --git a/yazi-plugin/src/elements/bar.rs b/yazi-plugin/src/elements/bar.rs index a7124def..f59087ed 100644 --- a/yazi-plugin/src/elements/bar.rs +++ b/yazi-plugin/src/elements/bar.rs @@ -42,8 +42,13 @@ impl Bar { impl UserData for Bar { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::impl_area_method!(methods); crate::impl_style_method!(methods, style); + methods.add_function("direction", |_, (ud, symbol): (AnyUserData, u8)| { + ud.borrow_mut::()?.direction = Borders::from_bits_truncate(symbol); + Ok(ud) + }); methods.add_function("symbol", |_, (ud, symbol): (AnyUserData, String)| { ud.borrow_mut::()?.symbol = symbol; Ok(ud) diff --git a/yazi-plugin/src/elements/border.rs b/yazi-plugin/src/elements/border.rs index 13f46ff3..0c30c91a 100644 --- a/yazi-plugin/src/elements/border.rs +++ b/yazi-plugin/src/elements/border.rs @@ -55,8 +55,13 @@ impl Border { impl UserData for Border { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::impl_area_method!(methods); crate::impl_style_method!(methods, style); + methods.add_function("position", |_, (ud, position): (AnyUserData, u8)| { + ud.borrow_mut::()?.position = ratatui::widgets::Borders::from_bits_truncate(position); + Ok(ud) + }); methods.add_function("type", |_, (ud, value): (AnyUserData, u8)| { ud.borrow_mut::()?.type_ = match value { ROUNDED => ratatui::widgets::BorderType::Rounded, diff --git a/yazi-plugin/src/elements/clear.rs b/yazi-plugin/src/elements/clear.rs index 424f879d..9e1121bf 100644 --- a/yazi-plugin/src/elements/clear.rs +++ b/yazi-plugin/src/elements/clear.rs @@ -55,7 +55,11 @@ impl Renderable for Clear { fn clone_render(&self, buf: &mut ratatui::buffer::Buffer) { Box::new(*self).render(buf); } } -impl UserData for Clear {} +impl UserData for Clear { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::impl_area_method!(methods); + } +} #[inline] const fn is_overlapping(a: &Rect, b: &Rect) -> bool { diff --git a/yazi-plugin/src/elements/gauge.rs b/yazi-plugin/src/elements/gauge.rs index 0c1f78d6..86af590a 100644 --- a/yazi-plugin/src/elements/gauge.rs +++ b/yazi-plugin/src/elements/gauge.rs @@ -25,6 +25,7 @@ impl Gauge { impl UserData for Gauge { fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::impl_area_method!(methods); crate::impl_style_method!(methods, style); methods.add_function("percent", |_, (ud, percent): (AnyUserData, u8)| { diff --git a/yazi-plugin/src/elements/list.rs b/yazi-plugin/src/elements/list.rs index 3e08b574..9f95d8b8 100644 --- a/yazi-plugin/src/elements/list.rs +++ b/yazi-plugin/src/elements/list.rs @@ -22,7 +22,11 @@ impl List { } } -impl UserData for List {} +impl UserData for List { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::impl_area_method!(methods); + } +} impl Renderable for List { fn area(&self) -> ratatui::layout::Rect { self.area } diff --git a/yazi-plugin/src/elements/paragraph.rs b/yazi-plugin/src/elements/paragraph.rs index f3ce272c..9ace9892 100644 --- a/yazi-plugin/src/elements/paragraph.rs +++ b/yazi-plugin/src/elements/paragraph.rs @@ -58,6 +58,7 @@ impl Paragraph { impl UserData for Paragraph { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::impl_area_method!(methods); crate::impl_style_method!(methods, style); crate::impl_style_shorthands!(methods, style); @@ -76,6 +77,9 @@ impl UserData for Paragraph { }; Ok(ud) }); + methods.add_method("max_width", |_, me, ()| { + Ok(me.text.lines.iter().take(me.area.height as usize).map(|l| l.width()).max()) + }); } } diff --git a/yazi-plugin/src/macros.rs b/yazi-plugin/src/macros.rs index 5a476faa..4437d090 100644 --- a/yazi-plugin/src/macros.rs +++ b/yazi-plugin/src/macros.rs @@ -26,6 +26,22 @@ macro_rules! impl_style_method { }; } +#[macro_export] +macro_rules! impl_area_method { + ($methods:ident) => { + use $crate::{bindings::Cast, elements::{Rect, RectRef}}; + + $methods.add_function("area", |lua, (ud, area): (mlua::AnyUserData, Option)| { + if let Some(r) = area { + ud.borrow_mut::()?.area = *r; + Ok(ud) + } else { + Rect::cast(lua, ud.borrow::()?.area) + } + }); + }; +} + #[macro_export] macro_rules! impl_style_shorthands { ($methods:ident, $($field:tt).+) => {