feat: new ui.Align, ui.Wrap, and ui.Edge (#2802)

This commit is contained in:
三咲雅 misaki masa 2025-05-28 16:49:47 +08:00 committed by GitHub
parent 74a8ea9bc0
commit d7716cab44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 217 additions and 104 deletions

4
Cargo.lock generated
View file

@ -2390,9 +2390,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.5.9" version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.52.0", "windows-sys 0.52.0",

View file

@ -20,7 +20,7 @@ function Current:empty()
end end
return { return {
ui.Line(s):area(self._area):align(ui.Line.CENTER), ui.Line(s):area(self._area):align(ui.Align.CENTER),
} }
end end
@ -43,7 +43,7 @@ function Current:redraw()
return { return {
ui.List(left):area(self._area), ui.List(left):area(self._area),
ui.Text(right):area(self._area):align(ui.Text.RIGHT), ui.Text(right):area(self._area):align(ui.Align.RIGHT),
} }
end end

View file

@ -1,4 +1,5 @@
Header = { Header = {
-- TODO: remove these two constants
LEFT = 0, LEFT = 0,
RIGHT = 1, RIGHT = 1,
@ -83,7 +84,7 @@ function Header:redraw()
return { return {
ui.Line(left):area(self._area), ui.Line(left):area(self._area),
ui.Line(right):area(self._area):align(ui.Line.RIGHT), ui.Line(right):area(self._area):align(ui.Align.RIGHT),
} }
end end

View file

@ -29,7 +29,7 @@ function Marker:redraw()
w = 1, w = 1,
h = math.min(1 + last[2] - last[1], self._area.y + self._area.h - y), h = math.min(1 + last[2] - last[1], self._area.y + self._area.h - y),
} }
elements[#elements + 1] = ui.Bar(ui.Bar.LEFT):area(rect):style(last[3]) elements[#elements + 1] = ui.Bar(ui.Edge.LEFT):area(rect):style(last[3])
end end
local last = { 0, 0, nil } -- start, end, style local last = { 0, 0, nil } -- start, end, style

View file

@ -10,8 +10,8 @@ end
function Rail:build() function Rail:build()
self._base = { self._base = {
ui.Bar(ui.Bar.RIGHT):area(self._chunks[1]):symbol(th.mgr.border_symbol):style(th.mgr.border_style), ui.Bar(ui.Edge.RIGHT):area(self._chunks[1]):symbol(th.mgr.border_symbol):style(th.mgr.border_style),
ui.Bar(ui.Bar.LEFT):area(self._chunks[3]):symbol(th.mgr.border_symbol):style(th.mgr.border_style), ui.Bar(ui.Edge.LEFT):area(self._chunks[3]):symbol(th.mgr.border_symbol):style(th.mgr.border_style),
} }
self._children = { self._children = {
Marker:new(self._chunks[1], self._tab.parent), Marker:new(self._chunks[1], self._tab.parent),

View file

@ -1,4 +1,5 @@
Status = { Status = {
-- TODO: remove these two constants
LEFT = 0, LEFT = 0,
RIGHT = 1, RIGHT = 1,
@ -141,7 +142,7 @@ function Status:redraw()
return { return {
ui.Text(""):area(self._area):style(th.status.overall), ui.Text(""):area(self._area):style(th.status.overall),
ui.Line(left):area(self._area), ui.Line(left):area(self._area),
ui.Line(right):area(self._area):align(ui.Line.RIGHT), ui.Line(right):area(self._area):align(ui.Align.RIGHT),
table.unpack(ui.redraw(Progress:new(self._area, right_width))), table.unpack(ui.redraw(Progress:new(self._area, right_width))),
} }
end end

View file

@ -45,7 +45,7 @@ function M:peek(job)
else else
ya.preview_widget(job, { ya.preview_widget(job, {
ui.Text(left):area(job.area), ui.Text(left):area(job.area),
ui.Text(right):area(job.area):align(ui.Text.RIGHT), ui.Text(right):area(job.area):align(ui.Align.RIGHT),
}) })
end end
end end

View file

@ -1,6 +1,6 @@
local M = {} local M = {}
function M.msg(job, s) ya.preview_widget(job, ui.Text(ui.Line(s):reverse()):area(job.area):wrap(ui.Text.WRAP)) end function M.msg(job, s) ya.preview_widget(job, ui.Text(ui.Line(s):reverse()):area(job.area):wrap(ui.Wrap.YES)) end
function M:peek(job) function M:peek(job)
local path = tostring(job.file.url) local path = tostring(job.file.url)

View file

@ -11,7 +11,7 @@ function M:peek(job)
text = ui.Text(string.format("Failed to start `%s`, error: %s", cmd, err)) text = ui.Text(string.format("Failed to start `%s`, error: %s", cmd, err))
end end
ya.preview_widget(job, text:area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, text:area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek() end function M:seek() end

View file

@ -16,7 +16,7 @@ function M:peek(job)
if #folder.files == 0 then if #folder.files == 0 then
local done, err = folder.stage() local done, err = folder.stage()
local s = not done and "Loading..." or not err and "No items" or string.format("Error: %s", err) local s = not done and "Loading..." or not err and "No items" or string.format("Error: %s", err)
return ya.preview_widget(job, ui.Line(s):area(job.area):align(ui.Line.CENTER)) return ya.preview_widget(job, ui.Line(s):area(job.area):align(ui.Align.CENTER))
end end
local items = {} local items = {}

View file

@ -16,7 +16,7 @@ function M:peek(job)
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
local _, err = ya.image_show(cache, job.area) local _, err = ya.image_show(cache, job.area)
ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek() end function M:seek() end

View file

@ -9,7 +9,7 @@ function M:peek(job)
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
local _, err = ya.image_show(url, job.area) local _, err = ya.image_show(url, job.area)
ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek() end function M:seek() end

View file

@ -34,7 +34,7 @@ function M:peek(job)
lines = lines:gsub("\t", string.rep(" ", rt.preview.tab_size)) lines = lines:gsub("\t", string.rep(" ", rt.preview.tab_size))
ya.preview_widget( ya.preview_widget(
job, job,
ui.Text.parse(lines):area(job.area):wrap(rt.preview.wrap == "yes" and ui.Text.WRAP or ui.Text.WRAP_NO) ui.Text.parse(lines):area(job.area):wrap(rt.preview.wrap == "yes" and ui.Wrap.YES or ui.Wrap.NO)
) )
end end
end end

View file

@ -14,7 +14,7 @@ function M:peek(job)
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
local _, err = ya.image_show(cache, job.area) local _, err = ya.image_show(cache, job.area)
ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek() end function M:seek() end

View file

@ -14,7 +14,7 @@ function M:peek(job)
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
local _, err = ya.image_show(cache, job.area) local _, err = ya.image_show(cache, job.area)
ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek(job) function M:seek(job)

View file

@ -14,7 +14,7 @@ function M:peek(job)
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
local _, err = ya.image_show(cache, job.area) local _, err = ya.image_show(cache, job.area)
ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek() end function M:seek() end

View file

@ -14,7 +14,7 @@ function M:peek(job)
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
local _, err = ya.image_show(cache, job.area) local _, err = ya.image_show(cache, job.area)
ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Text.WRAP)) ya.preview_widget(job, err and ui.Text(tostring(err)):area(job.area):wrap(ui.Wrap.YES))
end end
function M:seek(job) function M:seek(job)

View file

@ -0,0 +1,40 @@
use std::ops::Deref;
use mlua::{FromLua, IntoLua, Lua, Value};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Align(pub(super) ratatui::layout::Alignment);
impl Deref for Align {
type Target = ratatui::layout::Alignment;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl Align {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
lua.create_table_from([("LEFT", 0), ("CENTER", 1), ("RIGHT", 2)])?.into_lua(lua)
}
}
impl FromLua for Align {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
let Value::Integer(n) = value else {
return Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "Align".to_string(),
message: Some("expected an integer representation of Align".to_string()),
});
};
Ok(Self(match n {
0 => ratatui::layout::Alignment::Left,
1 => ratatui::layout::Alignment::Center,
2 => ratatui::layout::Alignment::Right,
_ => Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "Align".to_string(),
message: Some("invalid value for Align".to_string()),
})?,
}))
}
}

View file

@ -1,25 +1,24 @@
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, Value}; use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::Borders; use ratatui::widgets::Borders;
use super::Area; use super::{Area, Edge};
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct Bar { pub struct Bar {
area: Area, area: Area,
direction: ratatui::widgets::Borders, edge: Edge,
symbol: String, symbol: String,
style: ratatui::style::Style, style: ratatui::style::Style,
} }
impl Bar { impl Bar {
pub fn compose(lua: &Lua) -> mlua::Result<Value> { pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, direction): (Table, u8)| { let new =
Ok(Self { direction: Borders::from_bits_truncate(direction), ..Default::default() }) lua.create_function(|_, (_, edge): (Table, Edge)| Ok(Self { edge, ..Default::default() }))?;
})?;
let bar = lua.create_table_from([ let bar = lua.create_table_from([
// Direction // TODO: remove these constants
("NONE", Borders::NONE.bits()), ("NONE", Borders::NONE.bits()),
("TOP", Borders::TOP.bits()), ("TOP", Borders::TOP.bits()),
("RIGHT", Borders::RIGHT.bits()), ("RIGHT", Borders::RIGHT.bits()),
@ -44,31 +43,31 @@ impl Bar {
let symbol = if !self.symbol.is_empty() { let symbol = if !self.symbol.is_empty() {
&self.symbol &self.symbol
} else if self.direction.intersects(Borders::TOP | Borders::BOTTOM) { } else if self.edge.intersects(Borders::TOP | Borders::BOTTOM) {
"" ""
} else if self.direction.intersects(Borders::LEFT | Borders::RIGHT) { } else if self.edge.intersects(Borders::LEFT | Borders::RIGHT) {
"" ""
} else { } else {
" " " "
}; };
if self.direction.contains(Borders::LEFT) { if self.edge.contains(Borders::LEFT) {
for y in rect.top()..rect.bottom() { for y in rect.top()..rect.bottom() {
buf[(rect.left(), y)].set_style(self.style).set_symbol(symbol); buf[(rect.left(), y)].set_style(self.style).set_symbol(symbol);
} }
} }
if self.direction.contains(Borders::TOP) { if self.edge.contains(Borders::TOP) {
for x in rect.left()..rect.right() { for x in rect.left()..rect.right() {
buf[(x, rect.top())].set_style(self.style).set_symbol(symbol); buf[(x, rect.top())].set_style(self.style).set_symbol(symbol);
} }
} }
if self.direction.contains(Borders::RIGHT) { if self.edge.contains(Borders::RIGHT) {
let x = rect.right() - 1; let x = rect.right() - 1;
for y in rect.top()..rect.bottom() { for y in rect.top()..rect.bottom() {
buf[(x, y)].set_style(self.style).set_symbol(symbol); buf[(x, y)].set_style(self.style).set_symbol(symbol);
} }
} }
if self.direction.contains(Borders::BOTTOM) { if self.edge.contains(Borders::BOTTOM) {
let y = rect.bottom() - 1; let y = rect.bottom() - 1;
for x in rect.left()..rect.right() { for x in rect.left()..rect.right() {
buf[(x, y)].set_style(self.style).set_symbol(symbol); buf[(x, y)].set_style(self.style).set_symbol(symbol);
@ -82,8 +81,8 @@ impl UserData for Bar {
crate::impl_area_method!(methods); crate::impl_area_method!(methods);
crate::impl_style_method!(methods, style); crate::impl_style_method!(methods, style);
methods.add_function_mut("direction", |_, (ud, symbol): (AnyUserData, u8)| { methods.add_function_mut("edge", |_, (ud, edge): (AnyUserData, Edge)| {
ud.borrow_mut::<Self>()?.direction = Borders::from_bits_truncate(symbol); ud.borrow_mut::<Self>()?.edge = edge;
Ok(ud) Ok(ud)
}); });
methods.add_function_mut("symbol", |_, (ud, symbol): (AnyUserData, String)| { methods.add_function_mut("symbol", |_, (ud, symbol): (AnyUserData, String)| {

View file

@ -1,7 +1,7 @@
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, Value}; use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::{Borders, Widget}; use ratatui::widgets::{Borders, Widget};
use super::Area; use super::{Area, Edge};
use crate::elements::Line; use crate::elements::Line;
// Type // Type
@ -16,24 +16,20 @@ const QUADRANT_OUTSIDE: u8 = 5;
pub struct Border { pub struct Border {
pub(crate) area: Area, pub(crate) area: Area,
pub(crate) position: ratatui::widgets::Borders, pub(crate) edge: Edge,
pub(crate) r#type: ratatui::widgets::BorderType, pub(crate) r#type: ratatui::widgets::BorderType,
pub(crate) style: ratatui::style::Style, pub(crate) style: ratatui::style::Style,
pub(crate) titles: Vec<(ratatui::widgets::block::Position, ratatui::text::Line<'static>)>, pub(crate) titles: Vec<(ratatui::widgets::block::Position, ratatui::text::Line<'static>)>,
} }
impl Border { impl Border {
pub fn compose(lua: &Lua) -> mlua::Result<Value> { pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, position): (Table, u8)| { let new = lua
Ok(Border { .create_function(|_, (_, edge): (Table, Edge)| Ok(Border { edge, ..Default::default() }))?;
position: ratatui::widgets::Borders::from_bits_truncate(position),
..Default::default()
})
})?;
let border = lua.create_table_from([ let border = lua.create_table_from([
// Position // TODO: remove these constants
("NONE", Borders::NONE.bits()), ("NONE", Borders::NONE.bits()),
("TOP", Borders::TOP.bits()), ("TOP", Borders::TOP.bits()),
("RIGHT", Borders::RIGHT.bits()), ("RIGHT", Borders::RIGHT.bits()),
@ -59,7 +55,7 @@ impl Border {
trans: impl FnOnce(yazi_config::popup::Position) -> ratatui::layout::Rect, trans: impl FnOnce(yazi_config::popup::Position) -> ratatui::layout::Rect,
) { ) {
let mut block = ratatui::widgets::Block::default() let mut block = ratatui::widgets::Block::default()
.borders(self.position) .borders(self.edge.0)
.border_type(self.r#type) .border_type(self.r#type)
.border_style(self.style); .border_style(self.style);
@ -103,8 +99,8 @@ impl UserData for Border {
Ok(ud) Ok(ud)
}, },
); );
methods.add_function_mut("position", |_, (ud, position): (AnyUserData, u8)| { methods.add_function_mut("edge", |_, (ud, edge): (AnyUserData, Edge)| {
ud.borrow_mut::<Self>()?.position = ratatui::widgets::Borders::from_bits_truncate(position); ud.borrow_mut::<Self>()?.edge = edge;
Ok(ud) Ok(ud)
}); });
} }

View file

@ -0,0 +1,48 @@
use std::ops::Deref;
use mlua::{FromLua, IntoLua, Lua, Value};
use ratatui::widgets::Borders;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Edge(pub Borders);
impl Deref for Edge {
type Target = Borders;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl Edge {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
lua
.create_table_from([
("NONE", Borders::NONE.bits()),
("TOP", Borders::TOP.bits()),
("RIGHT", Borders::RIGHT.bits()),
("BOTTOM", Borders::BOTTOM.bits()),
("LEFT", Borders::LEFT.bits()),
("ALL", Borders::ALL.bits()),
])?
.into_lua(lua)
}
}
impl FromLua for Edge {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
let Value::Integer(n) = value else {
return Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "Edge".to_string(),
message: Some("expected an integer representation of an Edge".to_string()),
});
};
let Ok(Some(b)) = u8::try_from(n).map(Borders::from_bits) else {
return Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "Edge".to_string(),
message: Some("invalid bits for Edge".to_string()),
});
};
Ok(Self(b))
}
}

View file

@ -7,10 +7,12 @@ use crate::Composer;
pub fn compose(lua: &Lua) -> mlua::Result<Value> { pub fn compose(lua: &Lua) -> mlua::Result<Value> {
Composer::make(lua, 20, |lua, key| { Composer::make(lua, 20, |lua, key| {
match key { match key {
b"Align" => super::Align::compose(lua)?,
b"Bar" => super::Bar::compose(lua)?, b"Bar" => super::Bar::compose(lua)?,
b"Border" => super::Border::compose(lua)?, b"Border" => super::Border::compose(lua)?,
b"Clear" => super::Clear::compose(lua)?, b"Clear" => super::Clear::compose(lua)?,
b"Constraint" => super::Constraint::compose(lua)?, b"Constraint" => super::Constraint::compose(lua)?,
b"Edge" => super::Edge::compose(lua)?,
b"Gauge" => super::Gauge::compose(lua)?, b"Gauge" => super::Gauge::compose(lua)?,
b"Layout" => super::Layout::compose(lua)?, b"Layout" => super::Layout::compose(lua)?,
b"Line" => super::Line::compose(lua)?, b"Line" => super::Line::compose(lua)?,

View file

@ -6,10 +6,7 @@ use ratatui::widgets::Widget;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use super::{Area, Span}; use super::{Area, Span};
use crate::elements::Align;
const LEFT: u8 = 0;
const CENTER: u8 = 1;
const RIGHT: u8 = 2;
const EXPECTED: &str = "expected a string, Span, Line, or a table of them"; const EXPECTED: &str = "expected a string, Span, Line, or a table of them";
@ -40,10 +37,10 @@ impl Line {
let line = lua.create_table_from([ let line = lua.create_table_from([
("parse", parse.into_lua(lua)?), ("parse", parse.into_lua(lua)?),
// Alignment // TODO: remove these constants
("LEFT", LEFT.into_lua(lua)?), ("LEFT", 0.into_lua(lua)?),
("CENTER", CENTER.into_lua(lua)?), ("CENTER", 1.into_lua(lua)?),
("RIGHT", RIGHT.into_lua(lua)?), ("RIGHT", 2.into_lua(lua)?),
])?; ])?;
line.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?)); line.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
@ -120,12 +117,8 @@ impl UserData for Line {
crate::impl_style_shorthands!(methods, inner.style); crate::impl_style_shorthands!(methods, inner.style);
methods.add_method("width", |_, me, ()| Ok(me.inner.width())); methods.add_method("width", |_, me, ()| Ok(me.inner.width()));
methods.add_function_mut("align", |_, (ud, align): (AnyUserData, u8)| { methods.add_function_mut("align", |_, (ud, align): (AnyUserData, Align)| {
ud.borrow_mut::<Self>()?.inner.alignment = Some(match align { ud.borrow_mut::<Self>()?.inner.alignment = Some(align.0);
CENTER => ratatui::layout::Alignment::Center,
RIGHT => ratatui::layout::Alignment::Right,
_ => ratatui::layout::Alignment::Left,
});
Ok(ud) Ok(ud)
}); });
methods.add_method("visible", |_, me, ()| { methods.add_method("visible", |_, me, ()| {

View file

@ -1,3 +1,3 @@
#![allow(clippy::module_inception)] #![allow(clippy::module_inception)]
yazi_macro::mod_flat!(area bar border cell clear constraint elements gauge layout line list pad pos rect renderable row span style table text utils); yazi_macro::mod_flat!(align area bar border cell clear constraint edge elements gauge layout line list pad pos rect renderable row span style table text utils wrap);

View file

@ -4,17 +4,8 @@ use ansi_to_tui::IntoText;
use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value}; use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::Widget; use ratatui::widgets::Widget;
use super::{Area, Line, Span}; use super::{Area, Line, Span, Wrap};
use crate::elements::Align;
// Alignment
pub(super) const LEFT: u8 = 0;
pub(super) const CENTER: u8 = 1;
pub(super) const RIGHT: u8 = 2;
// Wrap
pub const WRAP_NO: u8 = 0;
pub const WRAP: u8 = 1;
pub const WRAP_TRIM: u8 = 2;
const EXPECTED: &str = "expected a string, Line, Span, or a table of them"; const EXPECTED: &str = "expected a string, Line, Span, or a table of them";
@ -24,7 +15,7 @@ pub struct Text {
// TODO: block // TODO: block
pub inner: ratatui::text::Text<'static>, pub inner: ratatui::text::Text<'static>,
pub wrap: u8, pub wrap: Wrap,
pub scroll: ratatui::layout::Position, pub scroll: ratatui::layout::Position,
} }
@ -38,14 +29,13 @@ impl Text {
let text = lua.create_table_from([ let text = lua.create_table_from([
("parse", parse.into_lua(lua)?), ("parse", parse.into_lua(lua)?),
// Alignment // TODO: remove these constants
("LEFT", LEFT.into_lua(lua)?), ("LEFT", 0.into_lua(lua)?),
("CENTER", CENTER.into_lua(lua)?), ("CENTER", 1.into_lua(lua)?),
("RIGHT", RIGHT.into_lua(lua)?), ("RIGHT", 2.into_lua(lua)?),
// Wrap ("WRAP_NO", 0.into_lua(lua)?),
("WRAP_NO", WRAP_NO.into_lua(lua)?), ("WRAP", 1.into_lua(lua)?),
("WRAP", WRAP.into_lua(lua)?), ("WRAP_TRIM", 2.into_lua(lua)?),
("WRAP_TRIM", WRAP_TRIM.into_lua(lua)?),
])?; ])?;
text.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?)); text.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
@ -58,7 +48,7 @@ impl Text {
trans: impl Fn(yazi_config::popup::Position) -> ratatui::layout::Rect, trans: impl Fn(yazi_config::popup::Position) -> ratatui::layout::Rect,
) { ) {
let rect = self.area.transform(trans); let rect = self.area.transform(trans);
if self.wrap == WRAP_NO && self.scroll == Default::default() { if self.wrap.is_none() && self.scroll == Default::default() {
self.inner.render(rect, buf); self.inner.render(rect, buf);
} else { } else {
ratatui::widgets::Paragraph::from(self).render(rect, buf); ratatui::widgets::Paragraph::from(self).render(rect, buf);
@ -127,8 +117,8 @@ impl From<Text> for ratatui::widgets::Paragraph<'static> {
if let Some(align) = align { if let Some(align) = align {
p = p.alignment(align); p = p.alignment(align);
} }
if value.wrap != WRAP_NO { if let Some(wrap) = value.wrap.0 {
p = p.wrap(ratatui::widgets::Wrap { trim: value.wrap == WRAP_TRIM }); p = p.wrap(wrap);
} }
p.scroll((value.scroll.y, value.scroll.x)) p.scroll((value.scroll.y, value.scroll.x))
} }
@ -140,19 +130,12 @@ impl UserData for Text {
crate::impl_style_method!(methods, inner.style); crate::impl_style_method!(methods, inner.style);
crate::impl_style_shorthands!(methods, inner.style); crate::impl_style_shorthands!(methods, inner.style);
methods.add_function_mut("align", |_, (ud, align): (AnyUserData, u8)| { methods.add_function_mut("align", |_, (ud, align): (AnyUserData, Align)| {
ud.borrow_mut::<Self>()?.inner.alignment = Some(match align { ud.borrow_mut::<Self>()?.inner.alignment = Some(align.0);
CENTER => ratatui::layout::Alignment::Center,
RIGHT => ratatui::layout::Alignment::Right,
_ => ratatui::layout::Alignment::Left,
});
Ok(ud) Ok(ud)
}); });
methods.add_function_mut("wrap", |_, (ud, wrap): (AnyUserData, u8)| { methods.add_function_mut("wrap", |_, (ud, wrap): (AnyUserData, Wrap)| {
ud.borrow_mut::<Self>()?.wrap = match wrap { ud.borrow_mut::<Self>()?.wrap = wrap;
w @ (WRAP | WRAP_TRIM | WRAP_NO) => w,
_ => return Err("expected a WRAP, WRAP_TRIM or WRAP_NO".into_lua_err()),
};
Ok(ud) Ok(ud)
}); });
methods.add_function_mut("scroll", |_, (ud, x, y): (AnyUserData, u16, u16)| { methods.add_function_mut("scroll", |_, (ud, x, y): (AnyUserData, u16, u16)| {

View file

@ -0,0 +1,50 @@
use std::ops::Deref;
use mlua::{FromLua, IntoLua, Lua, Value};
use yazi_config::preview::PreviewWrap;
#[derive(Clone, Copy, Debug, Default)]
pub struct Wrap(pub(super) Option<ratatui::widgets::Wrap>);
impl Deref for Wrap {
type Target = Option<ratatui::widgets::Wrap>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl Wrap {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
lua.create_table_from([("NO", 0), ("YES", 1), ("TRIM", 2)])?.into_lua(lua)
}
}
impl From<PreviewWrap> for Wrap {
fn from(value: PreviewWrap) -> Self {
Self(match value {
PreviewWrap::No => None,
PreviewWrap::Yes => Some(ratatui::widgets::Wrap { trim: false }),
})
}
}
impl FromLua for Wrap {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
let Value::Integer(n) = value else {
return Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "Wrap".to_string(),
message: Some("expected an integer representation of a Wrap".to_string()),
});
};
Ok(Self(match n {
0 => None,
1 => Some(ratatui::widgets::Wrap { trim: false }),
2 => Some(ratatui::widgets::Wrap { trim: true }),
_ => Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "Wrap".to_string(),
message: Some("invalid value for Wrap".to_string()),
})?,
}))
}
}

View file

@ -1,10 +1,10 @@
use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value}; use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
use yazi_config::{YAZI, preview::PreviewWrap}; use yazi_config::YAZI;
use yazi_macro::emit; use yazi_macro::emit;
use yazi_shared::{errors::PeekError, event::Cmd}; use yazi_shared::{errors::PeekError, event::Cmd};
use super::Utils; use super::Utils;
use crate::{elements::{Area, Rect, Renderable, Text, WRAP, WRAP_NO}, external::Highlighter, file::FileRef}; use crate::{elements::{Area, Rect, Renderable, Text}, external::Highlighter, file::FileRef};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct PreviewLock { pub struct PreviewLock {
@ -51,7 +51,7 @@ impl Utils {
lock.data = vec![Renderable::Text(Text { lock.data = vec![Renderable::Text(Text {
area, area,
inner, inner,
wrap: if YAZI.preview.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO }, wrap: YAZI.preview.wrap.into(),
scroll: Default::default(), scroll: Default::default(),
})]; })];

View file

@ -4,7 +4,7 @@ use yazi_macro::emit;
use yazi_shared::{Id, event::Cmd}; use yazi_shared::{Id, event::Cmd};
use super::Utils; use super::Utils;
use crate::{elements::Renderable, file::FileRef}; use crate::{elements::{Edge, Renderable}, file::FileRef};
pub struct SpotLock { pub struct SpotLock {
pub url: yazi_shared::url::Url, pub url: yazi_shared::url::Url,
@ -73,7 +73,7 @@ impl Utils {
Renderable::Clear(crate::elements::Clear { area }), Renderable::Clear(crate::elements::Clear { area }),
Renderable::Border(crate::elements::Border { Renderable::Border(crate::elements::Border {
area, area,
position: ratatui::widgets::Borders::ALL, edge: Edge(ratatui::widgets::Borders::ALL),
r#type: ratatui::widgets::BorderType::Rounded, r#type: ratatui::widgets::BorderType::Rounded,
style: THEME.spot.border.into(), style: THEME.spot.border.into(),
titles: vec![( titles: vec![(