diff --git a/yazi-plugin/preset/components/current.lua b/yazi-plugin/preset/components/current.lua index f472783d..cca8d042 100644 --- a/yazi-plugin/preset/components/current.lua +++ b/yazi-plugin/preset/components/current.lua @@ -11,15 +11,15 @@ function Current:new(area, tab) end function Current:empty() - local line + local text if self._folder.files.filter then - line = ui.Line("No filter results") + text = ui.Text("No filter results") else - line = ui.Line(self._folder.stage.is_loading and "Loading..." or "No items") + text = ui.Text(self._folder.stage.is_loading and "Loading..." or "No items") end return { - ui.Text(line):area(self._area):align(ui.Text.CENTER), + text:area(self._area):align(ui.Text.CENTER), } end @@ -31,8 +31,8 @@ function Current:render() local entities, linemodes = {}, {} for _, f in ipairs(files) do - linemodes[#linemodes + 1] = Linemode:new(f):render() entities[#entities + 1] = Entity:new(f):render() + linemodes[#linemodes + 1] = Linemode:new(f):render() end return { diff --git a/yazi-plugin/preset/components/header.lua b/yazi-plugin/preset/components/header.lua index d8340808..a5e94ec5 100644 --- a/yazi-plugin/preset/components/header.lua +++ b/yazi-plugin/preset/components/header.lua @@ -95,6 +95,7 @@ function Header:render() self._right_width = right:width() local left = self:children_render(self.LEFT) + return { ui.Text(left):area(self._area), ui.Text(right):area(self._area):align(ui.Text.RIGHT), diff --git a/yazi-plugin/preset/components/marker.lua b/yazi-plugin/preset/components/marker.lua index f75b370b..9a3c9d38 100644 --- a/yazi-plugin/preset/components/marker.lua +++ b/yazi-plugin/preset/components/marker.lua @@ -29,7 +29,7 @@ function Marker:render() w = 1, h = math.min(1 + last[2] - last[1], self._area.y + self._area.h - y), } - elements[#elements + 1] = ui.Bar(rect, ui.Bar.LEFT):style(last[3]) + elements[#elements + 1] = ui.Bar(ui.Bar.LEFT):area(rect):style(last[3]) end local last = { 0, 0, nil } -- start, end, style diff --git a/yazi-plugin/preset/components/progress.lua b/yazi-plugin/preset/components/progress.lua index 463f8935..0bddd11a 100644 --- a/yazi-plugin/preset/components/progress.lua +++ b/yazi-plugin/preset/components/progress.lua @@ -21,7 +21,7 @@ function Progress:partial_render() return { ui.Text {} } end - local gauge = ui.Gauge(self._area) + local gauge = ui.Gauge():area(self._area) if progress.fail == 0 then gauge = gauge:gauge_style(THEME.status.progress_normal) else diff --git a/yazi-plugin/preset/components/rail.lua b/yazi-plugin/preset/components/rail.lua index 822ec942..52f37b7d 100644 --- a/yazi-plugin/preset/components/rail.lua +++ b/yazi-plugin/preset/components/rail.lua @@ -11,8 +11,8 @@ end function Rail:build() self._base = { - ui.Bar(self._chunks[1], ui.Bar.RIGHT):symbol(THEME.manager.border_symbol):style(THEME.manager.border_style), - ui.Bar(self._chunks[3], ui.Bar.LEFT):symbol(THEME.manager.border_symbol):style(THEME.manager.border_style), + ui.Bar(ui.Bar.RIGHT):area(self._chunks[1]):symbol(THEME.manager.border_symbol):style(THEME.manager.border_style), + ui.Bar(ui.Bar.LEFT):area(self._chunks[3]):symbol(THEME.manager.border_symbol):style(THEME.manager.border_style), } self._children = { Marker:new(self._chunks[1], self._tab.parent), diff --git a/yazi-plugin/preset/components/status.lua b/yazi-plugin/preset/components/status.lua index 1c64e40c..cede2de7 100644 --- a/yazi-plugin/preset/components/status.lua +++ b/yazi-plugin/preset/components/status.lua @@ -132,8 +132,10 @@ end function Status:render() local left = self:children_render(self.LEFT) + local right = self:children_render(self.RIGHT) local right_width = right:width() + return { ui.Text(left):area(self._area), ui.Text(right):area(self._area):align(ui.Text.RIGHT), diff --git a/yazi-plugin/preset/plugins/archive.lua b/yazi-plugin/preset/plugins/archive.lua index e992d630..d6bad650 100644 --- a/yazi-plugin/preset/plugins/archive.lua +++ b/yazi-plugin/preset/plugins/archive.lua @@ -7,9 +7,7 @@ function M:peek() 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.Text( - ui.Line(code == 2 and "File list in this archive is encrypted" or "Spawn `7z` and `7zz` both commands failed") - ) + ui.Text(code == 2 and "File list in this archive is encrypted" or "Spawn `7z` and `7zz` both commands failed") :area(self.area), }) end @@ -27,9 +25,9 @@ function M:peek() end if f.size > 0 then - sizes[#sizes + 1] = ui.Line(string.format(" %s ", ya.readable_size(f.size))) + sizes[#sizes + 1] = string.format(" %s ", ya.readable_size(f.size)) else - sizes[#sizes + 1] = ui.Line("") + sizes[#sizes + 1] = "" end end diff --git a/yazi-plugin/preset/plugins/code.lua b/yazi-plugin/preset/plugins/code.lua index 8396dc34..5efdd8a1 100644 --- a/yazi-plugin/preset/plugins/code.lua +++ b/yazi-plugin/preset/plugins/code.lua @@ -6,7 +6,7 @@ function M:peek() ya.manager_emit("peek", { bound, only_if = self.file.url, upper_bound = true }) elseif err and not err:find("cancelled", 1, true) then ya.preview_widgets(self, { - ui.Text(ui.Line(err):reverse()):area(self.area), + ui.Text(err):area(self.area):reverse(), }) end end diff --git a/yazi-plugin/preset/plugins/empty.lua b/yazi-plugin/preset/plugins/empty.lua index bc664a8b..8c7bd21e 100644 --- a/yazi-plugin/preset/plugins/empty.lua +++ b/yazi-plugin/preset/plugins/empty.lua @@ -1,6 +1,6 @@ local M = {} -function M:msg(s) ya.preview_widgets(self, { ui.Text(ui.Line(s):reverse()):area(self.area):wrap(ui.Text.WRAP) }) end +function M:msg(s) ya.preview_widgets(self, { ui.Text(s):area(self.area):reverse():wrap(ui.Text.WRAP) }) end function M:peek() local path = tostring(self.file.url) diff --git a/yazi-plugin/preset/plugins/file.lua b/yazi-plugin/preset/plugins/file.lua index cc8b8255..9856706d 100644 --- a/yazi-plugin/preset/plugins/file.lua +++ b/yazi-plugin/preset/plugins/file.lua @@ -4,14 +4,14 @@ function M:peek() local cmd = os.getenv("YAZI_FILE_ONE") or "file" local output, code = Command(cmd):args({ "-bL", tostring(self.file.url) }):stdout(Command.PIPED):output() - local p + local text if output then - p = ui.Text.parse("----- File Type Classification -----\n\n" .. output.stdout):area(self.area) + text = ui.Text.parse("----- File Type Classification -----\n\n" .. output.stdout) else - p = ui.Text(string.format("Spawn `%s` command returns %s", cmd, code)):area(self.area) + text = ui.Text(string.format("Spawn `%s` command returns %s", cmd, code)) end - ya.preview_widgets(self, { p:wrap(ui.Text.WRAP) }) + ya.preview_widgets(self, { text:area(self.area):wrap(ui.Text.WRAP) }) end function M:seek() end diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index 61fcc8e8..7ccb0f0b 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -13,7 +13,7 @@ function M:peek() if #folder.files == 0 then return ya.preview_widgets(self, { - ui.Text(ui.Line(folder.stage.is_loading and "Loading..." or "No items")):area(self.area):align(ui.Text.CENTER), + ui.Text(folder.stage.is_loading and "Loading..." or "No items"):area(self.area):align(ui.Text.CENTER), }) end diff --git a/yazi-plugin/src/elements/bar.rs b/yazi-plugin/src/elements/bar.rs index 769a3b24..bb0e4953 100644 --- a/yazi-plugin/src/elements/bar.rs +++ b/yazi-plugin/src/elements/bar.rs @@ -3,7 +3,7 @@ use ratatui::widgets::Borders; use super::{Rect, Renderable}; -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Bar { area: Rect, @@ -14,14 +14,8 @@ pub struct Bar { impl Bar { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { - let new = lua.create_function(|_, (_, area, direction): (Table, Rect, u8)| { - Ok(Self { - area, - - direction: Borders::from_bits_truncate(direction), - symbol: Default::default(), - style: Default::default(), - }) + let new = lua.create_function(|_, (_, direction): (Table, u8)| { + Ok(Self { direction: Borders::from_bits_truncate(direction), ..Default::default() }) })?; let bar = lua.create_table_from([ diff --git a/yazi-plugin/src/elements/border.rs b/yazi-plugin/src/elements/border.rs index d25c25a0..de86e1e2 100644 --- a/yazi-plugin/src/elements/border.rs +++ b/yazi-plugin/src/elements/border.rs @@ -22,9 +22,8 @@ pub struct Border { impl Border { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { - let new = lua.create_function(|_, (_, area, position): (Table, Rect, u8)| { + let new = lua.create_function(|_, (_, position): (Table, u8)| { Ok(Border { - area, position: ratatui::widgets::Borders::from_bits_truncate(position), ..Default::default() }) diff --git a/yazi-plugin/src/elements/constraint.rs b/yazi-plugin/src/elements/constraint.rs index 777455b7..34ffecc3 100644 --- a/yazi-plugin/src/elements/constraint.rs +++ b/yazi-plugin/src/elements/constraint.rs @@ -1,42 +1,11 @@ use mlua::{FromLua, Lua, Table, UserData}; -#[derive(Clone, Copy, FromLua)] +#[derive(Clone, Copy, Default, FromLua)] pub struct Constraint(pub(super) ratatui::layout::Constraint); impl Constraint { - pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { - let constraint = lua.create_table_from([ - ( - "Min", - lua.create_function(|_, n: u16| Ok(Constraint(ratatui::layout::Constraint::Min(n))))?, - ), - ( - "Max", - lua.create_function(|_, n: u16| Ok(Constraint(ratatui::layout::Constraint::Max(n))))?, - ), - ( - "Length", - lua.create_function(|_, n: u16| Ok(Constraint(ratatui::layout::Constraint::Length(n))))?, - ), - ( - "Percentage", - lua.create_function(|_, n: u16| { - Ok(Constraint(ratatui::layout::Constraint::Percentage(n))) - })?, - ), - ( - "Ratio", - lua.create_function(|_, (a, b): (u32, u32)| { - Ok(Constraint(ratatui::layout::Constraint::Ratio(a, b))) - })?, - ), - ( - "Fill", - lua.create_function(|_, n: u16| Ok(Constraint(ratatui::layout::Constraint::Fill(n))))?, - ), - ])?; - - ui.raw_set("Constraint", constraint) + pub fn install(_: &Lua, ui: &Table) -> mlua::Result<()> { + ui.raw_set("Constraint", Constraint::default()) } } @@ -44,4 +13,15 @@ impl From for ratatui::layout::Constraint { fn from(value: Constraint) -> Self { value.0 } } -impl UserData for Constraint {} +impl UserData for Constraint { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + use ratatui::layout::Constraint as C; + + methods.add_function("Min", |_, n: u16| Ok(Self(C::Min(n)))); + methods.add_function("Max", |_, n: u16| Ok(Self(C::Max(n)))); + methods.add_function("Length", |_, n: u16| Ok(Self(C::Length(n)))); + methods.add_function("Percentage", |_, n: u16| Ok(Self(C::Percentage(n)))); + methods.add_function("Ratio", |_, (a, b): (u32, u32)| Ok(Self(C::Ratio(a, b)))); + methods.add_function("Fill", |_, n: u16| Ok(Self(C::Fill(n)))); + } +} diff --git a/yazi-plugin/src/elements/gauge.rs b/yazi-plugin/src/elements/gauge.rs index 9561db68..fbfd00be 100644 --- a/yazi-plugin/src/elements/gauge.rs +++ b/yazi-plugin/src/elements/gauge.rs @@ -16,10 +16,7 @@ pub struct Gauge { impl Gauge { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { - ui.raw_set( - "Gauge", - lua.create_function(|_, area: Rect| Ok(Gauge { area, ..Default::default() }))?, - ) + ui.raw_set("Gauge", lua.create_function(|_, ()| Ok(Gauge::default()))?) } } diff --git a/yazi-plugin/src/elements/line.rs b/yazi-plugin/src/elements/line.rs index d025e005..0c91c404 100644 --- a/yazi-plugin/src/elements/line.rs +++ b/yazi-plugin/src/elements/line.rs @@ -10,49 +10,14 @@ const LEFT: u8 = 0; const CENTER: u8 = 1; const RIGHT: u8 = 2; +const EXPECTED: &str = "expected a string, ui.Span, ui.Line, or a table of them"; + #[derive(Clone, FromLua)] pub struct Line(pub(super) ratatui::text::Line<'static>); -impl TryFrom> for Line { - type Error = mlua::Error; - - fn try_from(tb: Table) -> Result { - let seq: Vec<_> = tb.sequence_values().filter_map(|v| v.ok()).collect(); - let mut spans = Vec::with_capacity(seq.len()); - for value in seq { - if let Value::UserData(ud) = value { - if let Ok(span) = ud.take::() { - spans.push(span.0); - } else if let Ok(line) = ud.take::() { - let style = line.0.style; - spans.extend(line.0.spans.into_iter().map(|mut span| { - span.style = style.patch(span.style); - span - })); - } else { - return Err("expected a table of Spans or Lines".into_lua_err()); - } - } - } - Ok(Self(ratatui::text::Line::from(spans))) - } -} - -impl TryFrom> for Line { - type Error = mlua::Error; - - fn try_from(s: mlua::String) -> Result { - Ok(Self(ratatui::text::Line::from(s.to_string_lossy().into_owned()))) - } -} - impl Line { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { - let new = lua.create_function(|_, (_, value): (Table, Value)| match value { - Value::Table(tb) => Line::try_from(tb), - Value::String(s) => Line::try_from(s), - _ => Err("expected a String, or a table of Spans and Lines".into_lua_err()), - })?; + let new = lua.create_function(|_, (_, value): (Table, Value)| Line::try_from(value))?; let parse = lua.create_function(|_, code: mlua::String| { let Some(line) = code.as_bytes().split_inclusive(|&b| b == b'\n').next() else { @@ -81,6 +46,53 @@ impl Line { } } +impl TryFrom> for Line { + type Error = mlua::Error; + + fn try_from(value: Value) -> Result { + Ok(Self(match value { + Value::Table(tb) => return Self::try_from(tb), + Value::String(s) => s.to_string_lossy().into_owned().into(), + Value::UserData(ud) => { + if let Ok(span) = ud.take::() { + span.0.into() + } else if let Ok(mut line) = ud.take::() { + line.0.spans.iter_mut().for_each(|s| s.style = line.0.style.patch(s.style)); + line.0 + } else { + Err(EXPECTED.into_lua_err())? + } + } + _ => Err(EXPECTED.into_lua_err())?, + })) + } +} + +impl TryFrom> for Line { + type Error = mlua::Error; + + fn try_from(tb: Table) -> Result { + let mut spans = Vec::with_capacity(tb.raw_len()); + for v in tb.sequence_values() { + match v? { + Value::String(s) => spans.push(s.to_string_lossy().into_owned().into()), + Value::UserData(ud) => { + if let Ok(span) = ud.take::() { + spans.push(span.0); + } else if let Ok(mut line) = ud.take::() { + line.0.spans.iter_mut().for_each(|s| s.style = line.0.style.patch(s.style)); + spans.extend(line.0.spans); + } else { + return Err(EXPECTED.into_lua_err()); + } + } + _ => Err(EXPECTED.into_lua_err())?, + } + } + Ok(Self(spans.into())) + } +} + impl UserData for Line { fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { crate::impl_style_method!(methods, 0.style); diff --git a/yazi-plugin/src/elements/list.rs b/yazi-plugin/src/elements/list.rs index 3e7c31b5..a2c5b362 100644 --- a/yazi-plugin/src/elements/list.rs +++ b/yazi-plugin/src/elements/list.rs @@ -1,4 +1,4 @@ -use mlua::{Lua, Table, UserData, Value}; +use mlua::{ExternalError, Lua, Table, UserData, Value}; use ratatui::widgets::Widget; use super::{Rect, Renderable, Text}; @@ -15,10 +15,13 @@ impl List { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { ui.raw_set( "List", - lua.create_function(|_, values: Vec| { - let mut items = Vec::with_capacity(values.len()); - for value in values { - items.push(ratatui::widgets::ListItem::new(Text::try_from(value)?)); + lua.create_function(|_, tb: Table| { + let mut items = Vec::with_capacity(tb.raw_len()); + for v in tb.sequence_values::() { + match v? { + Value::Table(_) => Err("Nested table not supported".into_lua_err())?, + v => items.push(Text::try_from(v)?), + } } Ok(Self { inner: ratatui::widgets::List::new(items), ..Default::default() }) diff --git a/yazi-plugin/src/elements/span.rs b/yazi-plugin/src/elements/span.rs index f44ced7c..ecdf0e1a 100644 --- a/yazi-plugin/src/elements/span.rs +++ b/yazi-plugin/src/elements/span.rs @@ -1,17 +1,32 @@ -use mlua::{FromLua, Lua, Table, UserData, UserDataMethods}; +use mlua::{ExternalError, FromLua, Lua, Table, UserData, UserDataMethods, Value}; use unicode_width::UnicodeWidthChar; +const EXPECTED: &str = "expected a string or ui.Span"; + #[derive(Clone, FromLua)] pub struct Span(pub(super) ratatui::text::Span<'static>); impl Span { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { - ui.raw_set( - "Span", - lua.create_function(|_, content: mlua::String| { - Ok(Self(ratatui::text::Span::raw(content.to_string_lossy().into_owned()))) - })?, - ) + ui.raw_set("Span", lua.create_function(|_, value: Value| Span::try_from(value))?) + } +} + +impl TryFrom> for Span { + type Error = mlua::Error; + + fn try_from(value: Value<'_>) -> Result { + Ok(Self(match value { + Value::String(s) => s.to_string_lossy().into_owned().into(), + Value::UserData(ud) => { + if let Ok(span) = ud.take::() { + span.0 + } else { + Err(EXPECTED.into_lua_err())? + } + } + _ => Err(EXPECTED.into_lua_err())?, + })) } } diff --git a/yazi-plugin/src/elements/text.rs b/yazi-plugin/src/elements/text.rs index 25a7d777..f51bd9b9 100644 --- a/yazi-plugin/src/elements/text.rs +++ b/yazi-plugin/src/elements/text.rs @@ -14,6 +14,8 @@ pub const WRAP_NO: u8 = 0; pub const WRAP: u8 = 1; pub const WRAP_TRIM: u8 = 2; +const EXPECTED: &str = "expected a string, ui.Line, ui.Span or a table of them"; + #[derive(Clone, Default, FromLua)] pub struct Text { pub area: Rect, @@ -54,29 +56,45 @@ impl TryFrom> for Text { type Error = mlua::Error; fn try_from(value: Value) -> mlua::Result { - match value { - Value::String(s) => { - Ok(Self { inner: s.to_string_lossy().into_owned().into(), ..Default::default() }) - } + let inner = match value { + Value::Table(tb) => return Self::try_from(tb), + Value::String(s) => s.to_string_lossy().into_owned().into(), Value::UserData(ud) => { - let inner: ratatui::text::Text = if let Ok(line) = ud.take::() { + if let Ok(line) = ud.take::() { line.0.into() } else if let Ok(span) = ud.take::() { span.0.into() } else { - return Err("expected a String, Line or Span".into_lua_err()); - }; - Ok(Self { inner, ..Default::default() }) - } - Value::Table(tb) => { - let mut lines = Vec::with_capacity(tb.raw_len()); - for v in tb.sequence_values::() { - lines.extend(Self::try_from(v?)?.inner.lines); + Err(EXPECTED.into_lua_err())? } - Ok(Self { inner: lines.into(), ..Default::default() }) } - _ => Err("expected a String, Line, Span or a Table of them".into_lua_err()), + _ => Err(EXPECTED.into_lua_err())?, + }; + Ok(Self { inner, ..Default::default() }) + } +} + +impl TryFrom> for Text { + type Error = mlua::Error; + + fn try_from(tb: Table<'_>) -> Result { + let mut lines = Vec::with_capacity(tb.raw_len()); + for v in tb.sequence_values() { + match v? { + Value::String(s) => lines.push(s.to_string_lossy().into_owned().into()), + Value::UserData(ud) => { + if let Ok(span) = ud.take::() { + lines.push(span.0.into()); + } else if let Ok(line) = ud.take::() { + lines.push(line.0); + } else { + return Err(EXPECTED.into_lua_err()); + } + } + _ => Err(EXPECTED.into_lua_err())?, + } } + Ok(Self { inner: lines.into(), ..Default::default() }) } } @@ -86,7 +104,7 @@ impl From for ratatui::text::Text<'static> { impl From for ratatui::widgets::Paragraph<'static> { fn from(value: Text) -> Self { - let align = value.inner.alignment.unwrap_or(ratatui::layout::Alignment::Left); + let align = value.inner.alignment.unwrap_or_default(); let mut p = ratatui::widgets::Paragraph::new(value.inner); if value.wrap != WRAP_NO {