feat: truncate long paths in archive preview file list (#2778)

This commit is contained in:
三咲雅 misaki masa 2025-05-19 23:23:40 +08:00 committed by GitHub
parent 70e459a011
commit b6ae5d3ca9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 257 additions and 87 deletions

View file

@ -79,8 +79,8 @@ end
function Entity:redraw()
local lines = {}
for _, c in ipairs(self._children) do
local line = ui.Line((type(c[1]) == "string" and self[c[1]] or c[1])(self))
c.width, lines[#lines + 1] = line:width(), line
local line = (type(c[1]) == "string" and self[c[1]] or c[1])(self)
c.width, lines[#lines + 1] = ui.width(line), line
end
return ui.Line(lines):style(self:style())
end
@ -101,12 +101,11 @@ function Entity:ellipsis(max)
for _, child in ipairs(self._children) do
adv = adv + child.width
if adv >= max then
return not f.cha.is_dir and f.url.ext and "…." .. f.url.ext or ""
return not f.cha.is_dir and f.url.ext and "…." .. f.url.ext or nil
elseif child.id == 4 then
break
end
end
return ""
end
-- Children

View file

@ -2,7 +2,6 @@ local M = {}
function M:peek(job)
local limit = job.area.h
local paths, sizes = {}, {}
local files, bound, code = self.list_files({ "-p", tostring(job.file.url) }, job.skip, limit)
if code ~= 0 then
@ -13,31 +12,40 @@ function M:peek(job)
)
end
local left, right = {}, {}
for _, f in ipairs(files) do
local icon = File({
url = Url(f.path),
cha = Cha { kind = f.attr:sub(1, 1) == "D" and 1 or 0 },
}):icon()
if icon then
paths[#paths + 1] = ui.Line { ui.Span(" " .. icon.text .. " "):style(icon.style), f.path }
if f.size > 0 then
right[#right + 1] = string.format(" %s ", ya.readable_size(f.size))
else
paths[#paths + 1] = f.path
right[#right + 1] = " "
end
if f.size > 0 then
sizes[#sizes + 1] = string.format(" %s ", ya.readable_size(f.size))
if icon then
left[#left + 1] = ui.Span(" " .. icon.text .. " "):style(icon.style)
else
sizes[#sizes + 1] = ""
left[#left + 1] = " "
end
left[#left] = ui.Line {
left[#left],
ya.truncate(f.path, {
rtl = true,
max = math.max(0, job.area.w - ui.width(left[#left]) - ui.width(right[#right])),
}),
}
end
if job.skip > 0 and bound < job.skip + limit then
ya.emit("peek", { math.max(0, bound - limit), only_if = job.file.url, upper_bound = true })
else
ya.preview_widget(job, {
ui.Text(paths):area(job.area),
ui.Text(sizes):area(job.area):align(ui.Text.RIGHT),
ui.Text(left):area(job.area),
ui.Text(right):area(job.area):align(ui.Text.RIGHT),
})
end
end

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, Lua, MetaMethod, Table, UserData};
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::Borders;
use super::Area;
@ -13,7 +13,7 @@ pub struct Bar {
}
impl Bar {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, direction): (Table, u8)| {
Ok(Self { direction: Borders::from_bits_truncate(direction), ..Default::default() })
})?;
@ -29,7 +29,7 @@ impl Bar {
])?;
bar.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(bar)
bar.into_lua(lua)
}
pub(super) fn render(

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, Lua, MetaMethod, Table, UserData, Value};
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::{Borders, Widget};
use super::Area;
@ -24,7 +24,7 @@ pub struct Border {
}
impl Border {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, position): (Table, u8)| {
Ok(Border {
position: ratatui::widgets::Borders::from_bits_truncate(position),
@ -50,7 +50,7 @@ impl Border {
])?;
border.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(border)
border.into_lua(lua)
}
pub(super) fn render(

View file

@ -1,6 +1,6 @@
use std::sync::atomic::{AtomicBool, Ordering};
use mlua::{Lua, MetaMethod, Table, UserData};
use mlua::{IntoLua, Lua, MetaMethod, Table, UserData, Value};
use yazi_adapter::ADAPTOR;
use super::Area;
@ -13,13 +13,13 @@ pub struct Clear {
}
impl Clear {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, area): (Table, Area)| Ok(Clear { area }))?;
let clear = lua.create_table()?;
clear.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(clear)
clear.into_lua(lua)
}
pub(super) fn render(

View file

@ -1,20 +1,22 @@
use mlua::{FromLua, Lua, Table, UserData};
use mlua::{FromLua, IntoLua, Lua, UserData, Value};
#[derive(Clone, Copy, Default, FromLua)]
pub struct Constraint(pub(super) ratatui::layout::Constraint);
impl Constraint {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
use ratatui::layout::Constraint as C;
lua.create_table_from([
("Min", lua.create_function(|_, n: u16| Ok(Self(C::Min(n))))?),
("Max", lua.create_function(|_, n: u16| Ok(Self(C::Max(n))))?),
("Length", lua.create_function(|_, n: u16| Ok(Self(C::Length(n))))?),
("Percentage", lua.create_function(|_, n: u16| Ok(Self(C::Percentage(n))))?),
("Ratio", lua.create_function(|_, (a, b): (u32, u32)| Ok(Self(C::Ratio(a, b))))?),
("Fill", lua.create_function(|_, n: u16| Ok(Self(C::Fill(n))))?),
])
lua
.create_table_from([
("Min", lua.create_function(|_, n: u16| Ok(Self(C::Min(n))))?),
("Max", lua.create_function(|_, n: u16| Ok(Self(C::Max(n))))?),
("Length", lua.create_function(|_, n: u16| Ok(Self(C::Length(n))))?),
("Percentage", lua.create_function(|_, n: u16| Ok(Self(C::Percentage(n))))?),
("Ratio", lua.create_function(|_, (a, b): (u32, u32)| Ok(Self(C::Ratio(a, b))))?),
("Fill", lua.create_function(|_, n: u16| Ok(Self(C::Fill(n))))?),
])?
.into_lua(lua)
}
}

View file

@ -23,6 +23,8 @@ pub fn compose(lua: &Lua) -> mlua::Result<Value> {
b"Style" => super::Style::compose(lua)?,
b"Table" => super::Table::compose(lua)?,
b"Text" => super::Text::compose(lua)?,
b"width" => super::Utils::width(lua)?,
_ => return Ok(Value::Nil),
}
.into_lua(lua)

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, ExternalError, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use ratatui::widgets::Widget;
use super::{Area, Span};
@ -15,13 +15,13 @@ pub struct Gauge {
}
impl Gauge {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, _: Table| Ok(Gauge::default()))?;
let gauge = lua.create_table()?;
gauge.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(gauge)
gauge.into_lua(lua)
}
pub(super) fn render(

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, Lua, MetaMethod, Table, UserData, UserDataMethods};
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use super::{Constraint, Rect};
@ -13,13 +13,13 @@ pub struct Layout {
}
impl Layout {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, _: Table| Ok(Self::default()))?;
let layout = lua.create_table_from([("HORIZONTAL", HORIZONTAL), ("VERTICAL", VERTICAL)])?;
layout.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(layout)
layout.into_lua(lua)
}
}

View file

@ -21,7 +21,7 @@ pub struct Line {
}
impl Line {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Line::try_from(value))?;
let parse = lua.create_function(|_, code: mlua::String| {
@ -47,7 +47,7 @@ impl Line {
])?;
line.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(line)
line.into_lua(lua)
}
pub(super) fn render(
@ -148,26 +148,70 @@ impl UserData for Line {
}
};
let (mut width, mut last) = (0, None);
'outer: for (x, span) in me.inner.iter_mut().enumerate() {
for (y, c) in span.content.char_indices() {
width += c.width().unwrap_or(0);
match last {
None if width > max - ellipsis.0 => last = Some((false, x, y)),
Some((false, x, y)) if width > max => {
last = Some((true, x, y));
break 'outer;
}
_ => {}
fn traverse(
max: usize,
threshold: usize,
it: impl Iterator<Item = (usize, usize, char)>,
) -> (Option<(usize, usize, usize)>, bool) {
let (mut adv, mut cut) = (0, None);
for (x, y, c) in it {
adv += c.width().unwrap_or(0);
if adv <= threshold {
cut = Some((x, y, adv));
} else if adv > max {
break;
}
}
(cut, adv > max)
}
if let Some((true, x, y)) = last {
let spans = &mut me.inner.spans;
let rtl = t.raw_get("rtl")?;
let (cut, remain) = if rtl {
traverse(
max,
max - ellipsis.0,
me.inner
.iter()
.enumerate()
.rev()
.flat_map(|(x, s)| s.content.char_indices().rev().map(move |(y, c)| (x, y, c))),
)
} else {
traverse(
max,
max - ellipsis.0,
me.inner
.iter()
.enumerate()
.flat_map(|(x, s)| s.content.char_indices().map(move |(y, c)| (x, y, c))),
)
};
let Some((x, y, width)) = cut else {
me.inner.spans.clear();
me.inner.spans.push(ellipsis.1);
return Ok(ud);
};
if !remain {
return Ok(ud);
}
let spans = &mut me.inner.spans;
let len = match (rtl, width == max) {
(a, b) if a == b => spans[x].content[y..].chars().next().map_or(0, |c| c.len_utf8()),
_ => 0,
};
if rtl {
match &mut spans[x].content {
Cow::Borrowed(s) => spans[x].content = Cow::Borrowed(&s[..y]),
Cow::Owned(s) => s.truncate(y),
Cow::Borrowed(s) => spans[x].content = Cow::Borrowed(&s[y + len..]),
Cow::Owned(s) => _ = s.drain(..y + len),
}
spans.splice(..x, [ellipsis.1]);
} else {
match &mut spans[x].content {
Cow::Borrowed(s) => spans[x].content = Cow::Borrowed(&s[..y + len]),
Cow::Owned(s) => s.truncate(y + len),
}
spans.truncate(x + 1);
spans.push(ellipsis.1);
@ -177,3 +221,80 @@ impl UserData for Line {
});
}
}
#[cfg(test)]
mod tests {
use mlua::{UserDataRef, chunk};
use super::*;
fn truncate(s: &str, max: usize, rtl: bool) -> String {
let lua = Lua::new();
let comp = Line::compose(&lua).unwrap();
let line: UserDataRef<Line> = lua
.load(chunk! {
return $comp($s):truncate { max = $max, rtl = $rtl }
})
.call(())
.unwrap();
line.inner.spans.iter().map(|s| s.content.as_ref()).collect()
}
#[test]
fn test_truncate() {
assert_eq!(truncate("你好world", 0, false), "");
assert_eq!(truncate("你好world", 1, false), "");
assert_eq!(truncate("你好world", 2, false), "");
assert_eq!(truncate("你好,世界", 3, false), "你…");
assert_eq!(truncate("你好,世界", 4, false), "你…");
assert_eq!(truncate("你好,世界", 5, false), "你好…");
assert_eq!(truncate("Hello, world", 5, false), "Hell…");
assert_eq!(truncate("Ni好世界", 3, false), "Ni…");
}
#[test]
fn test_truncate_rtl() {
assert_eq!(truncate("world你好", 0, true), "");
assert_eq!(truncate("world你好", 1, true), "");
assert_eq!(truncate("world你好", 2, true), "");
assert_eq!(truncate("你好,世界", 3, true), "…界");
assert_eq!(truncate("你好,世界", 4, true), "…界");
assert_eq!(truncate("你好,世界", 5, true), "…世界");
assert_eq!(truncate("Hello, world", 5, true), "…orld");
assert_eq!(truncate("你好Shi界", 3, true), "…界");
}
#[test]
fn test_truncate_oboe() {
assert_eq!(truncate("Hello, world", 11, false), "Hello, wor…");
assert_eq!(truncate("你好,世界", 9, false), "你好,世…");
assert_eq!(truncate("你好世Jie", 9, false), "你好,世…");
assert_eq!(truncate("Hello, world", 11, true), "…llo, world");
assert_eq!(truncate("你好,世界", 9, true), "…好,世界");
assert_eq!(truncate("Ni好世界", 9, true), "…好,世界");
}
#[test]
fn test_truncate_exact() {
assert_eq!(truncate("Hello, world", 12, false), "Hello, world");
assert_eq!(truncate("你好,世界", 10, false), "你好,世界");
assert_eq!(truncate("Hello, world", 12, true), "Hello, world");
assert_eq!(truncate("你好,世界", 10, true), "你好,世界");
}
#[test]
fn test_truncate_overflow() {
assert_eq!(truncate("Hello, world", 13, false), "Hello, world");
assert_eq!(truncate("你好,世界", 11, false), "你好,世界");
assert_eq!(truncate("Hello, world", 13, true), "Hello, world");
assert_eq!(truncate("你好,世界", 11, true), "你好,世界");
}
}

View file

@ -1,4 +1,4 @@
use mlua::{ExternalError, Lua, MetaMethod, Table, UserData, Value};
use mlua::{ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::Widget;
use super::{Area, Text};
@ -14,7 +14,7 @@ pub struct List {
}
impl List {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, seq): (Table, Table)| {
let mut items = Vec::with_capacity(seq.raw_len());
for v in seq.sequence_values::<Value>() {
@ -27,7 +27,7 @@ impl List {
let list = lua.create_table()?;
list.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(list)
list.into_lua(lua)
}
pub(super) fn render(

View file

@ -1,3 +1,3 @@
#![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);
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);

View file

@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign, Deref};
use mlua::{FromLua, Lua, MetaMethod, Table, UserData};
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
#[derive(Clone, Copy, Default, FromLua)]
pub struct Pad(ratatui::widgets::Padding);
@ -16,7 +16,7 @@ impl From<ratatui::widgets::Padding> for Pad {
}
impl Pad {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new =
lua.create_function(|_, (_, top, right, bottom, left): (Table, u16, u16, u16, u16)| {
Ok(Self(ratatui::widgets::Padding::new(left, right, top, bottom)))
@ -47,7 +47,7 @@ impl Pad {
])?;
pad.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(pad)
pad.into_lua(lua)
}
}

View file

@ -1,6 +1,6 @@
use std::{ops::Deref, str::FromStr};
use mlua::{AnyUserData, ExternalResult, Lua, MetaMethod, Table, UserData};
use mlua::{AnyUserData, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Pad;
@ -46,13 +46,13 @@ impl TryFrom<mlua::Table> for Pos {
}
impl Pos {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, t): (Table, Table)| Self::try_from(t))?;
let position = lua.create_table()?;
position.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(position)
position.into_lua(lua)
}
pub fn new_input(t: mlua::Table) -> mlua::Result<Self> {

View file

@ -1,6 +1,6 @@
use std::ops::Deref;
use mlua::{FromLua, Lua, MetaMethod, Table, UserData};
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Pad;
@ -24,7 +24,7 @@ impl From<ratatui::layout::Size> for Rect {
}
impl Rect {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, args): (Table, Table)| {
Ok(Self(ratatui::layout::Rect {
x: args.raw_get("x").unwrap_or_default(),
@ -37,7 +37,7 @@ impl Rect {
let rect = lua.create_table_from([("default", Self(ratatui::layout::Rect::default()))])?;
rect.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(rect)
rect.into_lua(lua)
}
pub(super) fn pad(self, pad: Pad) -> Self {

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, ExternalError, Lua, MetaMethod, Table, UserData, Value};
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Cell;
@ -14,7 +14,7 @@ pub struct Row {
}
impl Row {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, cells): (Table, Vec<Cell>)| {
Ok(Self { cells, ..Default::default() })
})?;
@ -22,7 +22,7 @@ impl Row {
let row = lua.create_table()?;
row.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(row)
row.into_lua(lua)
}
}

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use mlua::{AnyUserData, ExternalError, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use unicode_width::UnicodeWidthChar;
const EXPECTED: &str = "expected a string or Span";
@ -8,13 +8,13 @@ const EXPECTED: &str = "expected a string or Span";
pub struct Span(pub(super) ratatui::text::Span<'static>);
impl Span {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Span::try_from(value))?;
let span = lua.create_table()?;
span.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(span)
span.into_lua(lua)
}
pub(super) fn truncate(&mut self, max: usize) -> usize {

View file

@ -1,19 +1,19 @@
use std::str::FromStr;
use mlua::{AnyUserData, ExternalError, ExternalResult, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use yazi_shared::theme::Color;
#[derive(Clone, Copy, Default)]
pub struct Style(pub(super) ratatui::style::Style);
impl Style {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Self::try_from(value))?;
let style = lua.create_table()?;
style.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(style)
style.into_lua(lua)
}
}

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, ExternalError, Lua, MetaMethod, UserData, Value};
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, UserData, Value};
use ratatui::widgets::StatefulWidget;
use super::{Area, Row};
@ -32,7 +32,7 @@ pub struct Table {
}
impl Table {
pub fn compose(lua: &Lua) -> mlua::Result<mlua::Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, seq): (mlua::Table, mlua::Table)| {
let mut rows = Vec::with_capacity(seq.raw_len());
for v in seq.sequence_values::<Value>() {
@ -45,7 +45,7 @@ impl Table {
let table = lua.create_table()?;
table.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(table)
table.into_lua(lua)
}
pub fn selected_cell(&self) -> Option<&ratatui::text::Text> {

View file

@ -29,7 +29,7 @@ pub struct Text {
}
impl Text {
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Text::try_from(value))?;
let parse = lua.create_function(|_, code: mlua::String| {
@ -49,7 +49,7 @@ impl Text {
])?;
text.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
Ok(text)
text.into_lua(lua)
}
pub(super) fn render(

View file

@ -0,0 +1,35 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use unicode_width::UnicodeWidthStr;
use super::{Line, Span};
pub(super) struct Utils;
impl Utils {
pub(super) fn width(lua: &Lua) -> mlua::Result<Value> {
let f = lua.create_function(|_, v: Value| match v {
Value::String(s) => {
let (mut acc, b) = (0, s.as_bytes());
for c in b.utf8_chunks() {
acc += c.valid().width();
if !c.invalid().is_empty() {
acc += 1;
}
}
Ok(acc)
}
Value::UserData(ud) => {
if let Ok(line) = ud.borrow::<Line>() {
Ok(line.inner.width())
} else if let Ok(span) = ud.borrow::<Span>() {
Ok(span.0.width())
} else {
Err("expected a string, Line, or Span".into_lua_err())?
}
}
_ => Err("expected a string, Line, or Span".into_lua_err())?,
})?;
f.into_lua(lua)
}
}

View file

@ -96,17 +96,20 @@ impl Utils {
#[cfg(test)]
mod tests {
use mlua::Value;
use mlua::chunk;
use super::*;
fn truncate(s: &str, max: usize, rtl: bool) -> String {
let lua = Lua::new();
let t = lua
.create_table_from([("max", Value::Integer(max as i64)), ("rtl", Value::Boolean(rtl))])
.unwrap();
let f = Utils::truncate(&lua).unwrap();
Utils::truncate(&lua).unwrap().call((s, t)).unwrap()
lua
.load(chunk! {
return $f($s, { max = $max, rtl = $rtl })
})
.call(())
.unwrap()
}
#[test]