feat!: add ui.Text, ui.Table, remove ui.Paragraph and ui.ListItem (#1776)

This commit is contained in:
三咲雅 · Misaki Masa 2024-10-14 01:54:03 +08:00 committed by GitHub
parent 35c3c9e0f7
commit 43b5ae0e6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 466 additions and 273 deletions

View File

@ -42,7 +42,7 @@ impl Manager {
if let Some(ref p) = tab.parent {
to_watch.insert(&p.url);
}
if let Some(h) = tab.current.hovered().filter(|&h| h.is_dir()) {
if let Some(h) = tab.hovered().filter(|&h| h.is_dir()) {
to_watch.insert(&h.url);
}
}

View File

@ -20,9 +20,9 @@ yazi_macro::mod_flat!(
tab_switch
unyank
update_files
update_mimetype
update_mimes
update_paged
update_task
update_tasks
update_yanked
yank
);

View File

@ -40,7 +40,7 @@ impl Tabs {
if !opt.current {
tab.cd(opt.url);
} else if let Some(h) = self.active().current.hovered() {
} else if let Some(h) = self.active().hovered() {
tab.conf = self.active().conf.clone();
tab.apply_files_attrs();
tab.reveal(h.url.to_regular());

View File

@ -52,7 +52,7 @@ impl Manager {
Self::update_current(tab, op, tasks);
} else if matches!(&tab.parent, Some(p) if *url == p.url) {
Self::update_parent(tab, op);
} else if matches!(tab.current.hovered(), Some(h) if *url == h.url) {
} else if matches!(tab.hovered(), Some(h) if *url == h.url) {
Self::update_hovered(tab, op);
} else {
Self::update_history(tab, op);
@ -74,7 +74,7 @@ impl Manager {
}
fn update_current(tab: &mut Tab, op: Cow<FilesOp>, tasks: &Tasks) {
let hovered = tab.current.hovered().filter(|_| tab.current.tracing).map(|h| h.urn_owned());
let hovered = tab.hovered().filter(|_| tab.current.tracing).map(|h| h.urn_owned());
let calc = !matches!(*op, FilesOp::Size(..) | FilesOp::Deleting(..));
let foreign = matches!(op, Cow::Borrowed(_));

View File

@ -19,9 +19,9 @@ impl TryFrom<Cmd> for Opt {
}
impl Manager {
pub fn update_mimetype(&mut self, opt: impl TryInto<Opt>, tasks: &Tasks) {
pub fn update_mimes(&mut self, opt: impl TryInto<Opt>, tasks: &Tasks) {
let Ok(opt) = opt.try_into() else {
return error!("invalid arguments for update_mimetype");
return error!("invalid arguments for update_mimes");
};
let linked = LINKED.read();

View File

@ -3,23 +3,23 @@ use yazi_shared::{event::Cmd, fs::Url};
use crate::manager::Manager;
pub struct Opt {
url: Url,
urls: Vec<Url>,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self { url: c.take_any("url").ok_or(())? })
Ok(Self { urls: c.take_any("urls").ok_or(())? })
}
}
impl Manager {
pub fn update_task(&mut self, opt: impl TryInto<Opt>) {
pub fn update_tasks(&mut self, opt: impl TryInto<Opt>) {
let Ok(opt) = opt.try_into() else {
return;
};
self.watcher.push_file(opt.url);
self.watcher.push_files(opt.urls);
}
}

View File

@ -71,7 +71,7 @@ impl Manager {
pub fn parent(&self) -> Option<&Folder> { self.active().parent.as_ref() }
#[inline]
pub fn hovered(&self) -> Option<&File> { self.active().current.hovered() }
pub fn hovered(&self) -> Option<&File> { self.active().hovered() }
#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> { self.active().hovered_folder() }

View File

@ -53,9 +53,12 @@ impl Watcher {
self.in_tx.send(new.into_iter().cloned().collect()).ok();
}
pub(super) fn push_file(&self, url: Url) {
if url.parent_url().is_some_and(|p| WATCHED.read().contains(&p)) {
self.out_tx.send(url).ok();
pub(super) fn push_files(&self, url: Vec<Url>) {
let watched = WATCHED.read();
for u in url {
if u.parent_url().is_some_and(|p| watched.contains(&p)) {
self.out_tx.send(u).ok();
}
}
}

View File

@ -4,6 +4,6 @@ use crate::tab::Tab;
impl Tab {
pub fn enter(&mut self, _: Cmd) {
self.current.hovered().filter(|h| h.is_dir()).map(|h| h.url.to_regular()).map(|u| self.cd(u));
self.hovered().filter(|h| h.is_dir()).map(|h| h.url.to_regular()).map(|u| self.cd(u));
}
}

View File

@ -86,7 +86,7 @@ impl Tab {
}
self.selected.clear();
if self.current.hovered().is_some_and(|h| h.is_dir()) {
if self.hovered().is_some_and(|h| h.is_dir()) {
ManagerProxy::peek(true);
}
render_and!(true)

View File

@ -20,13 +20,13 @@ impl Tab {
ManagerProxy::update_paged(); // Update for paged files in next loop
}
let hovered = self.current.hovered().map(|f| f.urn_owned());
let hovered = self.hovered().map(|f| f.urn_owned());
if !self.current.files.set_filter(filter) {
return;
}
self.current.repos(hovered.as_ref().map(|u| u.as_urn()));
if self.current.hovered().map(|f| f.urn()) != hovered.as_ref().map(|u| u.as_urn()) {
if self.hovered().map(|f| f.urn()) != hovered.as_ref().map(|u| u.as_urn()) {
ManagerProxy::hover(None, self.idx);
}

View File

@ -11,12 +11,12 @@ impl Tab {
_ => !self.conf.show_hidden,
};
let hovered = self.current.hovered().map(|f| f.url_owned());
let hovered = self.hovered().map(|f| f.url_owned());
self.apply_files_attrs();
if hovered.as_ref() != self.current.hovered().map(|f| &f.url) {
if hovered.as_ref() != self.hovered().map(|f| &f.url) {
ManagerProxy::hover(hovered, self.idx);
} else if self.current.hovered().is_some_and(|f| f.is_dir()) {
} else if self.hovered().is_some_and(|f| f.is_dir()) {
ManagerProxy::peek(true);
}
ManagerProxy::update_paged();

View File

@ -14,14 +14,16 @@ yazi_macro::mod_flat!(
hidden
leave
linemode
preview
reveal
search
select
select_all
shell
sort
spot
toggle
toggle_all
update_peeked
update_spotted
visual_mode
);

View File

@ -0,0 +1,20 @@
use yazi_shared::event::{Cmd, Data};
use crate::tab::Tab;
struct Opt {
skip: Option<usize>,
}
impl From<Cmd> for Opt {
fn from(c: Cmd) -> Self { Self { skip: c.first().and_then(Data::as_usize) } }
}
impl Tab {
#[yazi_codegen::command]
pub fn spot(&mut self, c: Cmd) {
let Some(hovered) = self.hovered().cloned() else {
return self.preview.reset();
};
}
}

View File

@ -17,8 +17,8 @@ impl TryFrom<Cmd> for Opt {
}
impl Tab {
pub fn preview(&mut self, opt: impl TryInto<Opt>) {
let Some(hovered) = self.current.hovered().map(|h| &h.url) else {
pub fn update_peeked(&mut self, opt: impl TryInto<Opt>) {
let Some(hovered) = self.hovered().map(|h| &h.url) else {
return self.preview.reset();
};

View File

@ -0,0 +1,22 @@
use yazi_plugin::utils::PreviewLock;
use yazi_shared::event::Cmd;
use crate::tab::Tab;
pub struct Opt {
lock: PreviewLock,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self { lock: c.take_any("lock").ok_or(())? })
}
}
impl Tab {
pub fn update_spotted(&mut self, opt: impl TryInto<Opt>) {
todo!();
}
}

View File

@ -7,7 +7,7 @@ use yazi_adapter::Dimension;
use yazi_config::{LAYOUT, popup::{Origin, Position}};
use yazi_fs::{Folder, FolderStage};
use yazi_macro::render;
use yazi_shared::fs::Url;
use yazi_shared::fs::{File, Url};
use super::{Backstack, Config, Finder, History, Mode, Preview};
use crate::tab::Selected;
@ -42,8 +42,11 @@ impl Tab {
#[inline]
pub fn cwd(&self) -> &Url { &self.current.url }
#[inline]
pub fn hovered(&self) -> Option<&File> { self.current.hovered() }
pub fn hovered_rect(&self) -> Option<Rect> {
let y = self.current.files.position(self.current.hovered()?.urn())? - self.current.offset;
let y = self.current.files.position(self.hovered()?.urn())? - self.current.offset;
let mut rect = LAYOUT.load().current;
rect.y = rect.y.saturating_sub(1) + y as u16;
@ -62,7 +65,7 @@ impl Tab {
pub fn selected_or_hovered(&self, reorder: bool) -> Box<dyn Iterator<Item = &Url> + '_> {
if self.selected.is_empty() {
Box::new(self.current.hovered().map(|h| vec![&h.url]).unwrap_or_default().into_iter())
Box::new(self.hovered().map(|h| vec![&h.url]).unwrap_or_default().into_iter())
} else if !reorder {
Box::new(self.selected.keys())
} else {
@ -73,7 +76,7 @@ impl Tab {
}
pub fn hovered_and_selected(&self, reorder: bool) -> Box<dyn Iterator<Item = &Url> + '_> {
let Some(h) = self.current.hovered() else { return Box::new(iter::empty()) };
let Some(h) = self.hovered() else { return Box::new(iter::empty()) };
if self.selected.is_empty() {
Box::new([&h.url, &h.url].into_iter())
@ -89,7 +92,7 @@ impl Tab {
// --- History
#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> {
self.current.hovered().filter(|&h| h.is_dir()).and_then(|h| self.history.get(&h.url))
self.hovered().filter(|&h| h.is_dir()).and_then(|h| self.history.get(&h.url))
}
pub fn apply_files_attrs(&mut self) {

View File

@ -65,20 +65,22 @@ impl<'a> Executor<'a> {
};
}
on!(MANAGER, update_task);
on!(MANAGER, update_tasks);
on!(MANAGER, update_files, &self.app.cx.tasks);
on!(MANAGER, update_mimetype, &self.app.cx.tasks);
on!(MANAGER, update_mimes, &self.app.cx.tasks);
on!(MANAGER, update_paged, &self.app.cx.tasks);
on!(MANAGER, update_yanked);
on!(MANAGER, hover);
on!(MANAGER, peek);
on!(MANAGER, seek);
on!(ACTIVE, spot);
on!(MANAGER, refresh, &self.app.cx.tasks);
on!(MANAGER, quit, &self.app.cx.tasks);
on!(MANAGER, close, &self.app.cx.tasks);
on!(MANAGER, suspend);
on!(ACTIVE, escape);
on!(ACTIVE, preview);
on!(ACTIVE, update_peeked);
on!(ACTIVE, update_spotted);
// Navigation
on!(ACTIVE, arrow);

View File

@ -90,7 +90,7 @@ impl File {
});
reg.add_method("in_current", |_, me, ()| Ok(me.folder().url == me.tab().current.url));
reg.add_method("in_preview", |_, me, ()| {
Ok(me.tab().current.hovered().is_some_and(|f| f.url == me.folder().url))
Ok(me.tab().hovered().is_some_and(|f| f.url == me.folder().url))
});
reg.add_method("found", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;

View File

@ -19,7 +19,7 @@ function Current:empty()
end
return {
ui.Paragraph(self._area, { line }):align(ui.Paragraph.CENTER),
ui.Text(line):area(self._area):align(ui.Text.CENTER),
}
end
@ -32,14 +32,12 @@ function Current:render()
local entities, linemodes = {}, {}
for _, f in ipairs(files) do
linemodes[#linemodes + 1] = Linemode:new(f):render()
local entity = Entity:new(f)
entities[#entities + 1] = ui.ListItem(entity:render()):style(entity:style())
entities[#entities + 1] = Entity:new(f):render()
end
return {
ui.List(self._area, entities),
ui.Paragraph(self._area, linemodes):align(ui.Paragraph.RIGHT),
ui.List(entities):area(self._area),
ui.Text(linemodes):area(self._area):align(ui.Text.RIGHT),
}
end

View File

@ -81,7 +81,7 @@ function Entity:render()
for _, c in ipairs(self._children) do
lines[#lines + 1] = (type(c[1]) == "string" and self[c[1]] or c[1])(self)
end
return ui.Line(lines)
return ui.Line(lines):style(self:style())
end
function Entity:style()

View File

@ -96,8 +96,8 @@ function Header:render()
local left = self:children_render(self.LEFT)
return {
ui.Paragraph(self._area, { left }),
ui.Paragraph(self._area, { right }):align(ui.Paragraph.RIGHT),
ui.Text(left):area(self._area),
ui.Text(right):area(self._area):align(ui.Text.RIGHT),
}
end

View File

@ -17,12 +17,11 @@ function Parent:render()
local items = {}
for _, f in ipairs(self._folder.window) do
local entity = Entity:new(f)
items[#items + 1] = ui.ListItem(entity:render()):style(entity:style())
items[#items + 1] = Entity:new(f):render()
end
return {
ui.List(self._area, items),
ui.List(items):area(self._area),
}
end

View File

@ -18,7 +18,7 @@ end
function Progress:partial_render()
local progress = cx.tasks.progress
if progress.total == 0 then
return { ui.Paragraph(self._area, {}) }
return { ui.Text {} }
end
local gauge = ui.Gauge(self._area)

View File

@ -133,10 +133,11 @@ 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.Paragraph(self._area, { left }),
ui.Paragraph(self._area, { right }):align(ui.Paragraph.RIGHT),
table.unpack(Progress:render(self._area, right:width())),
ui.Text(left):area(self._area),
ui.Text(right):area(self._area):align(ui.Text.RIGHT),
table.unpack(Progress:render(self._area, right_width)),
}
end

View File

@ -7,9 +7,10 @@ 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.Paragraph(self.area, {
ui.Line(code == 2 and "File list in this archive is encrypted" or "Spawn `7z` and `7zz` both commands failed"),
}),
ui.Text(
ui.Line(code == 2 and "File list in this archive is encrypted" or "Spawn `7z` and `7zz` both commands failed")
)
:area(self.area),
})
end
@ -36,8 +37,8 @@ function M:peek()
ya.manager_emit("peek", { math.max(0, bound - limit), only_if = self.file.url, upper_bound = true })
else
ya.preview_widgets(self, {
ui.Paragraph(self.area, paths),
ui.Paragraph(self.area, sizes):align(ui.Paragraph.RIGHT),
ui.Text(paths):area(self.area),
ui.Text(sizes):area(self.area):align(ui.Text.RIGHT),
})
end
end

View File

@ -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.Paragraph(self.area, { ui.Line(err):reverse() }),
ui.Text(ui.Line(err):reverse()):area(self.area),
})
end
end

View File

@ -1,11 +1,6 @@
local M = {}
function M:msg(s)
local p = ui.Paragraph(self.area, {
ui.Line(s):reverse(),
})
ya.preview_widgets(self, { p:wrap(ui.Paragraph.WRAP) })
end
function M:msg(s) ya.preview_widgets(self, { ui.Text(ui.Line(s):reverse()):area(self.area):wrap(ui.Text.WRAP) }) end
function M:peek()
local path = tostring(self.file.url)
@ -31,7 +26,7 @@ function M:peek()
elseif self.skip > 0 and i < self.skip + limit then
ya.manager_emit("peek", { math.max(0, i - limit), only_if = self.file.url, upper_bound = true })
else
ya.preview_widgets(self, { ui.Paragraph(self.area, lines) })
ya.preview_widgets(self, { ui.Text(lines):area(self.area) })
end
end

View File

@ -6,16 +6,23 @@ function M:peek()
local p
if output then
p = ui.Paragraph.parse(self.area, "----- File Type Classification -----\n\n" .. output.stdout)
p = ui.Text.parse("----- File Type Classification -----\n\n" .. output.stdout):area(self.area)
else
p = ui.Paragraph(self.area, {
ui.Line(string.format("Spawn `%s` command returns %s", cmd, code)),
})
p = ui.Text(string.format("Spawn `%s` command returns %s", cmd, code)):area(self.area)
end
ya.preview_widgets(self, { p:wrap(ui.Paragraph.WRAP) })
ya.preview_widgets(self, { p:wrap(ui.Text.WRAP) })
end
function M:seek() end
function M:spot(skip)
local rect = ui.Rect { x = 10, y = 10, w = 20, h = 20 }
ya.spot_widgets(self, {
ui.Clear(rect),
ui.Table(rect),
})
end
return M

View File

@ -13,19 +13,17 @@ function M:peek()
if #folder.files == 0 then
return ya.preview_widgets(self, {
ui.Paragraph(self.area, { ui.Line(folder.stage.is_loading and "Loading..." or "No items") })
:align(ui.Paragraph.CENTER),
ui.Text(ui.Line(folder.stage.is_loading and "Loading..." or "No items")):area(self.area):align(ui.Text.CENTER),
})
end
local items = {}
for _, f in ipairs(folder.window) do
local entity = Entity:new(f)
items[#items + 1] = ui.ListItem(entity:render()):style(entity:style())
items[#items + 1] = Entity:new(f):render()
end
ya.preview_widgets(self, {
ui.List(self.area, items),
ui.List(items):area(self.area),
table.unpack(Marker:new(self.area, folder):render()),
})
end

View File

@ -37,7 +37,7 @@ function M:peek()
ya.manager_emit("peek", { math.max(0, i - limit), only_if = self.file.url, upper_bound = true })
else
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) })
ya.preview_widgets(self, { ui.Text.parse(lines):area(self.area) })
end
end

View File

@ -28,7 +28,7 @@ function M:fetch()
return
end
if next(updates) then
ya.manager_emit("update_mimetype", { updates = updates })
ya.manager_emit("update_mimes", { updates = updates })
updates, last = {}, ya.time()
end
end

View File

@ -3,7 +3,7 @@ use mlua::AnyUserData;
use crate::elements::Renderable;
pub fn cast_to_renderable(ud: &AnyUserData) -> Option<Box<dyn Renderable + Send>> {
if let Ok(c) = ud.take::<crate::elements::Paragraph>() {
if let Ok(c) = ud.take::<crate::elements::Text>() {
Some(Box::new(c))
} else if let Ok(c) = ud.take::<crate::elements::List>() {
Some(Box::new(c))
@ -15,6 +15,8 @@ pub fn cast_to_renderable(ud: &AnyUserData) -> Option<Box<dyn Renderable + Send>
Some(Box::new(c))
} else if let Ok(c) = ud.take::<crate::elements::Gauge>() {
Some(Box::new(c))
} else if let Ok(c) = ud.take::<crate::elements::Table>() {
Some(Box::new(c))
} else {
None
}

View File

@ -45,11 +45,11 @@ impl UserData for Bar {
crate::impl_area_method!(methods);
crate::impl_style_method!(methods, style);
methods.add_function("direction", |_, (ud, symbol): (AnyUserData, u8)| {
methods.add_function_mut("direction", |_, (ud, symbol): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.direction = Borders::from_bits_truncate(symbol);
Ok(ud)
});
methods.add_function("symbol", |_, (ud, symbol): (AnyUserData, String)| {
methods.add_function_mut("symbol", |_, (ud, symbol): (AnyUserData, String)| {
ud.borrow_mut::<Self>()?.symbol = symbol;
Ok(ud)
});

View File

@ -58,11 +58,11 @@ impl UserData for Border {
crate::impl_area_method!(methods);
crate::impl_style_method!(methods, style);
methods.add_function("position", |_, (ud, position): (AnyUserData, u8)| {
methods.add_function_mut("position", |_, (ud, position): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.position = ratatui::widgets::Borders::from_bits_truncate(position);
Ok(ud)
});
methods.add_function("type", |_, (ud, value): (AnyUserData, u8)| {
methods.add_function_mut("type", |_, (ud, value): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.type_ = match value {
ROUNDED => ratatui::widgets::BorderType::Rounded,
DOUBLE => ratatui::widgets::BorderType::Double,

View File

@ -40,4 +40,8 @@ impl Constraint {
}
}
impl From<Constraint> for ratatui::layout::Constraint {
fn from(value: Constraint) -> Self { value.0 }
}
impl UserData for Constraint {}

View File

@ -15,13 +15,14 @@ pub fn pour(lua: &Lua) -> mlua::Result<()> {
super::Layout::install(lua, &ui)?;
super::Line::install(lua, &ui)?;
super::List::install(lua, &ui)?;
super::ListItem::install(lua, &ui)?;
super::Padding::install(lua, &ui)?;
super::Paragraph::install(lua, &ui)?;
super::Position::install(lua, &ui)?;
super::Rect::install(lua, &ui)?;
super::Span::install(lua, &ui)?;
super::Style::install(lua, &ui)?;
super::Table::install(lua, &ui)?;
super::TableRow::install(lua, &ui)?;
super::Text::install(lua, &ui)?;
lua.globals().raw_set("ui", ui)
}

View File

@ -28,7 +28,7 @@ impl UserData for Gauge {
crate::impl_area_method!(methods);
crate::impl_style_method!(methods, style);
methods.add_function("percent", |_, (ud, percent): (AnyUserData, u8)| {
methods.add_function_mut("percent", |_, (ud, percent): (AnyUserData, u8)| {
if percent > 100 {
return Err("percent must be between 0 and 100".into_lua_err());
}
@ -37,7 +37,7 @@ impl UserData for Gauge {
Ok(ud)
});
methods.add_function("ratio", |_, (ud, ratio): (AnyUserData, f64)| {
methods.add_function_mut("ratio", |_, (ud, ratio): (AnyUserData, f64)| {
if !(0.0..1.0).contains(&ratio) {
return Err("ratio must be between 0 and 1".into_lua_err());
}
@ -46,12 +46,12 @@ impl UserData for Gauge {
Ok(ud)
});
methods.add_function("label", |_, (ud, label): (AnyUserData, Span)| {
methods.add_function_mut("label", |_, (ud, label): (AnyUserData, Span)| {
ud.borrow_mut::<Self>()?.label = Some(label.0);
Ok(ud)
});
methods.add_function("gauge_style", |_, (ud, value): (AnyUserData, Value)| {
methods.add_function_mut("gauge_style", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.gauge_style = Style::try_from(value)?.0;
Ok(ud)
});

View File

@ -26,15 +26,15 @@ impl Layout {
impl UserData for Layout {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("direction", |_, (ud, value): (AnyUserData, bool)| {
methods.add_function_mut("direction", |_, (ud, value): (AnyUserData, bool)| {
ud.borrow_mut::<Self>()?.direction = value;
Ok(ud)
});
methods.add_function("margin", |_, (ud, value): (AnyUserData, u16)| {
methods.add_function_mut("margin", |_, (ud, value): (AnyUserData, u16)| {
ud.borrow_mut::<Self>()?.margin = Some(ratatui::layout::Margin::new(value, value));
Ok(ud)
});
methods.add_function("margin_h", |_, (ud, value): (AnyUserData, u16)| {
methods.add_function_mut("margin_h", |_, (ud, value): (AnyUserData, u16)| {
{
let mut me = ud.borrow_mut::<Self>()?;
if let Some(margin) = &mut me.margin {
@ -45,7 +45,7 @@ impl UserData for Layout {
}
Ok(ud)
});
methods.add_function("margin_v", |_, (ud, value): (AnyUserData, u16)| {
methods.add_function_mut("margin_v", |_, (ud, value): (AnyUserData, u16)| {
{
let mut me = ud.borrow_mut::<Self>()?;
if let Some(margin) = &mut me.margin {
@ -56,8 +56,8 @@ impl UserData for Layout {
}
Ok(ud)
});
methods.add_function("constraints", |_, (ud, value): (AnyUserData, Vec<Constraint>)| {
ud.borrow_mut::<Self>()?.constraints = value.into_iter().map(|c| c.0).collect();
methods.add_function_mut("constraints", |_, (ud, value): (AnyUserData, Vec<Constraint>)| {
ud.borrow_mut::<Self>()?.constraints = value.into_iter().map(Into::into).collect();
Ok(ud)
});
methods.add_method("split", |lua, me, value: Rect| {

View File

@ -87,7 +87,7 @@ impl UserData for Line {
crate::impl_style_shorthands!(methods, 0.style);
methods.add_method("width", |_, me, ()| Ok(me.0.width()));
methods.add_function("align", |_, (ud, align): (AnyUserData, u8)| {
methods.add_function_mut("align", |_, (ud, align): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.0.alignment = Some(match align {
CENTER => ratatui::layout::Alignment::Center,
RIGHT => ratatui::layout::Alignment::Right,

View File

@ -1,10 +1,10 @@
use mlua::{ExternalError, FromLua, Lua, Table, UserData, Value};
use mlua::{Lua, Table, UserData, Value};
use ratatui::widgets::Widget;
use super::{Line, Rect, Renderable, Span};
use super::{Rect, Renderable, Text};
// --- List
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct List {
area: Rect,
@ -15,8 +15,13 @@ impl List {
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
ui.raw_set(
"List",
lua.create_function(|_, (area, items): (Rect, Vec<ListItem>)| {
Ok(Self { area, inner: ratatui::widgets::List::new(items) })
lua.create_function(|_, values: Vec<Value>| {
let mut items = Vec::with_capacity(values.len());
for value in values {
items.push(ratatui::widgets::ListItem::new(Text::try_from(value)?));
}
Ok(Self { inner: ratatui::widgets::List::new(items), ..Default::default() })
})?,
)
}
@ -37,44 +42,3 @@ impl Renderable for List {
fn clone_render(&self, buf: &mut ratatui::buffer::Buffer) { Box::new(self.clone()).render(buf) }
}
// --- ListItem
#[derive(Clone, Default, FromLua)]
pub struct ListItem {
content: ratatui::text::Text<'static>,
style: ratatui::style::Style,
}
impl ListItem {
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
ui.raw_set(
"ListItem",
lua.create_function(|_, value: Value| match value {
Value::String(s) => {
Ok(Self { content: s.to_string_lossy().into_owned().into(), ..Default::default() })
}
Value::UserData(ud) => {
let content: ratatui::text::Text = if let Ok(line) = ud.take::<Line>() {
line.0.into()
} else if let Ok(span) = ud.take::<Span>() {
span.0.into()
} else {
return Err("expected a String, Line or Span".into_lua_err());
};
Ok(Self { content, ..Default::default() })
}
_ => Err("expected a String, Line or Span".into_lua_err()),
})?,
)
}
}
impl From<ListItem> for ratatui::widgets::ListItem<'static> {
fn from(value: ListItem) -> Self { Self::new(value.content).style(value.style) }
}
impl UserData for ListItem {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
crate::impl_style_method!(methods, style);
}
}

View File

@ -1,6 +1,3 @@
#![allow(clippy::module_inception)]
yazi_macro::mod_flat!(
bar border clear constraint elements gauge layout line list padding paragraph
position rect span style
);
yazi_macro::mod_flat!(bar border clear constraint elements gauge layout line list padding position rect span style table text);

View File

@ -1,96 +0,0 @@
use ansi_to_tui::IntoText;
use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, Table, UserData};
use ratatui::widgets::Widget;
use super::{Line, Rect, Renderable};
// Alignment
const LEFT: u8 = 0;
const CENTER: u8 = 1;
const RIGHT: u8 = 2;
// Wrap
pub const WRAP_NO: u8 = 0;
pub const WRAP: u8 = 1;
pub const WRAP_TRIM: u8 = 2;
#[derive(Clone, Default)]
pub struct Paragraph {
pub area: Rect,
pub text: ratatui::text::Text<'static>,
pub style: ratatui::style::Style,
pub alignment: ratatui::layout::Alignment,
pub wrap: u8,
}
impl Paragraph {
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
let new = lua.create_function(|_, (_, area, lines): (Table, Rect, Vec<Line>)| {
Ok(Paragraph { area, text: lines.into_iter().map(|s| s.0).collect(), ..Default::default() })
})?;
let parse = lua.create_function(|_, (area, code): (Rect, mlua::String)| {
Ok(Paragraph { area, text: code.into_text().into_lua_err()?, ..Default::default() })
})?;
let paragraph = lua.create_table_from([
("parse", parse.into_lua(lua)?),
// Alignment
("LEFT", LEFT.into_lua(lua)?),
("CENTER", CENTER.into_lua(lua)?),
("RIGHT", RIGHT.into_lua(lua)?),
// Wrap
("WRAP_NO", WRAP_NO.into_lua(lua)?),
("WRAP", WRAP.into_lua(lua)?),
("WRAP_TRIM", WRAP_TRIM.into_lua(lua)?),
])?;
paragraph.set_metatable(Some(lua.create_table_from([("__call", new)])?));
ui.raw_set("Paragraph", 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);
methods.add_function("align", |_, (ud, align): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.alignment = match align {
CENTER => ratatui::layout::Alignment::Center,
RIGHT => ratatui::layout::Alignment::Right,
_ => ratatui::layout::Alignment::Left,
};
Ok(ud)
});
methods.add_function("wrap", |_, (ud, wrap): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.wrap = match wrap {
w @ (WRAP | WRAP_TRIM | WRAP_NO) => w,
_ => return Err("expected a WRAP or WRAP_TRIM or WRAP_OFF".into_lua_err()),
};
Ok(ud)
});
methods.add_method("max_width", |_, me, ()| {
Ok(me.text.lines.iter().take(me.area.height as usize).map(|l| l.width()).max())
});
}
}
impl Renderable for Paragraph {
fn area(&self) -> ratatui::layout::Rect { *self.area }
fn render(self: Box<Self>, buf: &mut ratatui::buffer::Buffer) {
let mut p = ratatui::widgets::Paragraph::new(self.text).style(self.style);
if self.wrap != WRAP_NO {
p = p.wrap(ratatui::widgets::Wrap { trim: self.wrap == WRAP_TRIM });
}
p.alignment(self.alignment).render(*self.area, buf);
}
fn clone_render(&self, buf: &mut ratatui::buffer::Buffer) { Box::new(self.clone()).render(buf) }
}

View File

@ -55,7 +55,7 @@ impl UserData for Style {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
crate::impl_style_shorthands!(methods, 0);
methods.add_function("patch", |_, (ud, value): (AnyUserData, Value)| {
methods.add_function_mut("patch", |_, (ud, value): (AnyUserData, Value)| {
{
let mut me = ud.borrow_mut::<Self>()?;
me.0 = me.0.patch(Self::try_from(value)?.0);

View File

@ -0,0 +1,133 @@
use mlua::{AnyUserData, FromLua, Lua, UserData};
use ratatui::widgets::StatefulWidget;
use super::{Rect, Renderable, Text};
use crate::elements::Constraint;
// --- Table
#[derive(Clone, Default)]
pub struct Table {
area: Rect,
rows: Vec<ratatui::widgets::Row<'static>>,
header: Option<ratatui::widgets::Row<'static>>,
footer: Option<ratatui::widgets::Row<'static>>,
widths: Vec<ratatui::layout::Constraint>,
column_spacing: u16,
block: Option<ratatui::widgets::Block<'static>>,
style: ratatui::style::Style,
highlight_style: ratatui::style::Style,
highlight_symbol: ratatui::text::Text<'static>,
highlight_spacing: ratatui::widgets::HighlightSpacing,
flex: ratatui::layout::Flex,
state: ratatui::widgets::TableState,
}
impl Table {
pub fn install(lua: &Lua, ui: &mlua::Table) -> mlua::Result<()> {
ui.raw_set(
"Table",
lua.create_function(|_, (area, rows): (Rect, Vec<TableRow>)| {
Ok(Self { area, rows: rows.into_iter().map(Into::into).collect(), ..Default::default() })
})?,
)
}
}
impl UserData for Table {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
crate::impl_area_method!(methods);
methods.add_function_mut("header", |_, (ud, row): (AnyUserData, TableRow)| {
ud.borrow_mut::<Self>()?.header = Some(row.into());
Ok(ud)
});
methods.add_function_mut("footer", |_, (ud, row): (AnyUserData, TableRow)| {
ud.borrow_mut::<Self>()?.footer = Some(row.into());
Ok(ud)
});
methods.add_function_mut("widths", |_, (ud, widths): (AnyUserData, Vec<Constraint>)| {
ud.borrow_mut::<Self>()?.widths = widths.into_iter().map(Into::into).collect();
Ok(ud)
});
}
}
impl Renderable for Table {
fn area(&self) -> ratatui::layout::Rect { *self.area }
fn render(mut self: Box<Self>, buf: &mut ratatui::buffer::Buffer) {
let mut table = ratatui::widgets::Table::new(self.rows, self.widths)
.column_spacing(self.column_spacing)
.style(self.style)
.highlight_style(self.highlight_style)
.highlight_symbol(self.highlight_symbol)
.highlight_spacing(self.highlight_spacing)
.flex(self.flex);
if let Some(header) = self.header {
table = table.header(header);
}
if let Some(footer) = self.footer {
table = table.footer(footer);
}
if let Some(block) = self.block {
table = table.block(block);
}
table.render(*self.area, buf, &mut self.state);
}
fn clone_render(&self, buf: &mut ratatui::buffer::Buffer) { Box::new(self.clone()).render(buf) }
}
// --- TableRow
#[derive(Clone, Default, FromLua)]
pub struct TableRow {
cells: Vec<ratatui::widgets::Cell<'static>>,
height: u16,
top_margin: u16,
bottom_margin: u16,
style: ratatui::style::Style,
}
impl TableRow {
pub fn install(lua: &Lua, ui: &mlua::Table) -> mlua::Result<()> {
ui.raw_set(
"TableRow",
lua.create_function(|_, cols: Vec<Text>| {
Ok(Self { cells: cols.into_iter().map(Into::into).collect(), ..Default::default() })
})?,
)
}
}
impl From<TableRow> for ratatui::widgets::Row<'static> {
fn from(value: TableRow) -> Self {
Self::new(value.cells)
.height(value.height)
.top_margin(value.top_margin)
.bottom_margin(value.bottom_margin)
.style(value.style)
}
}
impl UserData for TableRow {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
crate::impl_style_method!(methods, style);
methods.add_function_mut("height", |_, (ud, value): (AnyUserData, u16)| {
ud.borrow_mut::<Self>()?.height = value;
Ok(ud)
});
methods.add_function_mut("margin_t", |_, (ud, value): (AnyUserData, u16)| {
ud.borrow_mut::<Self>()?.top_margin = value;
Ok(ud)
});
methods.add_function_mut("margin_b", |_, (ud, value): (AnyUserData, u16)| {
ud.borrow_mut::<Self>()?.bottom_margin = value;
Ok(ud)
});
}
}

View File

@ -0,0 +1,137 @@
use ansi_to_tui::IntoText;
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, Table, UserData, Value};
use ratatui::widgets::Widget;
use super::{Line, Rect, Renderable, Span};
// 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;
#[derive(Clone, Default, FromLua)]
pub struct Text {
pub area: Rect,
// TODO: block
pub inner: ratatui::text::Text<'static>,
pub wrap: u8,
// TODO: scroll
}
impl Text {
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Text::try_from(value))?;
let parse = lua.create_function(|_, code: mlua::String| {
Ok(Text { inner: code.into_text().into_lua_err()?, ..Default::default() })
})?;
let text = lua.create_table_from([
("parse", parse.into_lua(lua)?),
// Alignment
("LEFT", LEFT.into_lua(lua)?),
("CENTER", CENTER.into_lua(lua)?),
("RIGHT", RIGHT.into_lua(lua)?),
// Wrap
("WRAP_NO", WRAP_NO.into_lua(lua)?),
("WRAP", WRAP.into_lua(lua)?),
("WRAP_TRIM", WRAP_TRIM.into_lua(lua)?),
])?;
text.set_metatable(Some(lua.create_table_from([("__call", new)])?));
ui.raw_set("Text", text)
}
}
impl TryFrom<Value<'_>> for Text {
type Error = mlua::Error;
fn try_from(value: Value) -> mlua::Result<Self> {
match value {
Value::String(s) => {
Ok(Self { inner: s.to_string_lossy().into_owned().into(), ..Default::default() })
}
Value::UserData(ud) => {
let inner: ratatui::text::Text = if let Ok(line) = ud.take::<Line>() {
line.0.into()
} else if let Ok(span) = ud.take::<Span>() {
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::<Value>() {
lines.extend(Self::try_from(v?)?.inner.lines);
}
Ok(Self { inner: lines.into(), ..Default::default() })
}
_ => Err("expected a String, Line, Span or a Table of them".into_lua_err()),
}
}
}
impl From<Text> for ratatui::text::Text<'static> {
fn from(value: Text) -> Self { value.inner }
}
impl From<Text> for ratatui::widgets::Paragraph<'static> {
fn from(value: Text) -> Self {
let align = value.inner.alignment.unwrap_or(ratatui::layout::Alignment::Left);
let mut p = ratatui::widgets::Paragraph::new(value.inner);
if value.wrap != WRAP_NO {
p = p.wrap(ratatui::widgets::Wrap { trim: value.wrap == WRAP_TRIM });
}
p.alignment(align)
}
}
impl UserData for Text {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
crate::impl_area_method!(methods);
crate::impl_style_method!(methods, inner.style);
crate::impl_style_shorthands!(methods, inner.style);
methods.add_function_mut("align", |_, (ud, align): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.inner.alignment = Some(match align {
CENTER => ratatui::layout::Alignment::Center,
RIGHT => ratatui::layout::Alignment::Right,
_ => ratatui::layout::Alignment::Left,
});
Ok(ud)
});
methods.add_function_mut("wrap", |_, (ud, wrap): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.wrap = match wrap {
w @ (WRAP | WRAP_TRIM | WRAP_NO) => w,
_ => return Err("expected a WRAP or WRAP_TRIM or WRAP_OFF".into_lua_err()),
};
Ok(ud)
});
methods.add_method("max_width", |_, me, ()| {
Ok(me.inner.lines.iter().take(me.area.height as usize).map(|l| l.width()).max())
});
}
}
impl Renderable for Text {
fn area(&self) -> ratatui::layout::Rect { *self.area }
fn render(self: Box<Self>, buf: &mut ratatui::buffer::Buffer) {
let area = *self.area;
let p: ratatui::widgets::Paragraph = (*self).into();
p.render(area, buf);
}
fn clone_render(&self, buf: &mut ratatui::buffer::Buffer) { Box::new(self.clone()).render(buf) }
}

View File

@ -23,9 +23,9 @@ pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
// Elements
let ui = lua.create_table()?;
elements::Line::install(&lua, &ui)?;
elements::Paragraph::install(&lua, &ui)?;
elements::Rect::install(&lua, &ui)?;
elements::Span::install(&lua, &ui)?;
elements::Text::install(&lua, &ui)?;
lua.globals().raw_set("ui", ui)?;
Ok(lua)

View File

@ -1,7 +1,7 @@
#[macro_export]
macro_rules! impl_style_method {
($methods:ident, $($field:tt).+) => {
$methods.add_function("style", |_, (ud, value): (mlua::AnyUserData, mlua::Value)| {
$methods.add_function_mut("style", |_, (ud, value): (mlua::AnyUserData, mlua::Value)| {
ud.borrow_mut::<Self>()?.$($field).+ = $crate::elements::Style::try_from(value)?.0;
Ok(ud)
});
@ -14,7 +14,7 @@ macro_rules! impl_area_method {
use mlua::IntoLua;
use $crate::elements::Rect;
$methods.add_function("area", |lua, (ud, area): (mlua::AnyUserData, Option<Rect>)| {
$methods.add_function_mut("area", |lua, (ud, area): (mlua::AnyUserData, Option<Rect>)| {
if let Some(r) = area {
ud.borrow_mut::<Self>()?.area = r;
ud.into_lua(lua)
@ -28,51 +28,51 @@ macro_rules! impl_area_method {
#[macro_export]
macro_rules! impl_style_shorthands {
($methods:ident, $($field:tt).+) => {
$methods.add_function("fg", |_, (ud, color): (mlua::AnyUserData, String)| {
$methods.add_function_mut("fg", |_, (ud, color): (mlua::AnyUserData, String)| {
ud.borrow_mut::<Self>()?.$($field).+.fg = yazi_shared::theme::Color::try_from(color).ok().map(Into::into);
Ok(ud)
});
$methods.add_function("bg", |_, (ud, color): (mlua::AnyUserData, String)| {
$methods.add_function_mut("bg", |_, (ud, color): (mlua::AnyUserData, String)| {
ud.borrow_mut::<Self>()?.$($field).+.bg = yazi_shared::theme::Color::try_from(color).ok().map(Into::into);
Ok(ud)
});
$methods.add_function("bold", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("bold", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::BOLD;
Ok(ud)
});
$methods.add_function("dim", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("dim", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::DIM;
Ok(ud)
});
$methods.add_function("italic", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("italic", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::ITALIC;
Ok(ud)
});
$methods.add_function("underline", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("underline", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::UNDERLINED;
Ok(ud)
});
$methods.add_function("blink", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("blink", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::SLOW_BLINK;
Ok(ud)
});
$methods.add_function("blink_rapid", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("blink_rapid", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::RAPID_BLINK;
Ok(ud)
});
$methods.add_function("reverse", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("reverse", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::REVERSED;
Ok(ud)
});
$methods.add_function("hidden", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("hidden", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::HIDDEN;
Ok(ud)
});
$methods.add_function("crossed", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("crossed", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier |= ratatui::style::Modifier::CROSSED_OUT;
Ok(ud)
});
$methods.add_function("reset", |_, ud: mlua::AnyUserData| {
$methods.add_function_mut("reset", |_, ud: mlua::AnyUserData| {
ud.borrow_mut::<Self>()?.$($field).+.add_modifier = ratatui::style::Modifier::empty();
Ok(ud)
});

View File

@ -65,11 +65,11 @@ impl UserData for Command {
)
}
methods.add_function("arg", |_, (ud, arg): (AnyUserData, mlua::String)| {
methods.add_function_mut("arg", |_, (ud, arg): (AnyUserData, mlua::String)| {
ud.borrow_mut::<Self>()?.inner.arg(arg.to_string_lossy().as_ref());
Ok(ud)
});
methods.add_function("args", |_, (ud, args): (AnyUserData, Vec<mlua::String>)| {
methods.add_function_mut("args", |_, (ud, args): (AnyUserData, Vec<mlua::String>)| {
{
let mut me = ud.borrow_mut::<Self>()?;
for arg in args {
@ -78,11 +78,11 @@ impl UserData for Command {
}
Ok(ud)
});
methods.add_function("cwd", |_, (ud, dir): (AnyUserData, mlua::String)| {
methods.add_function_mut("cwd", |_, (ud, dir): (AnyUserData, mlua::String)| {
ud.borrow_mut::<Self>()?.inner.current_dir(dir.to_str()?);
Ok(ud)
});
methods.add_function(
methods.add_function_mut(
"env",
|_, (ud, key, value): (AnyUserData, mlua::String, mlua::String)| {
ud.borrow_mut::<Self>()?
@ -91,15 +91,15 @@ impl UserData for Command {
Ok(ud)
},
);
methods.add_function("stdin", |_, (ud, stdio): (AnyUserData, Value)| {
methods.add_function_mut("stdin", |_, (ud, stdio): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.inner.stdin(make_stdio(stdio)?);
Ok(ud)
});
methods.add_function("stdout", |_, (ud, stdio): (AnyUserData, Value)| {
methods.add_function_mut("stdout", |_, (ud, stdio): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.inner.stdout(make_stdio(stdio)?);
Ok(ud)
});
methods.add_function("stderr", |_, (ud, stdio): (AnyUserData, Value)| {
methods.add_function_mut("stderr", |_, (ud, stdio): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.inner.stderr(make_stdio(stdio)?);
Ok(ud)
});

View File

@ -4,7 +4,7 @@ use yazi_macro::emit;
use yazi_shared::{Layer, errors::PeekError, event::Cmd};
use super::Utils;
use crate::{bindings::Window, cast_to_renderable, elements::{Paragraph, Rect, Renderable, WRAP, WRAP_NO}, external::Highlighter, file::FileRef};
use crate::{bindings::Window, cast_to_renderable, elements::{Rect, Renderable, Text, WRAP, WRAP_NO}, external::Highlighter, file::FileRef};
pub struct PreviewLock {
pub url: yazi_shared::fs::Url,
@ -41,7 +41,7 @@ impl Utils {
let area: Rect = t.raw_get("area")?;
let mut lock = PreviewLock::try_from(t)?;
let text = match Highlighter::new(&lock.url).highlight(lock.skip, *area).await {
let inner = match Highlighter::new(&lock.url).highlight(lock.skip, *area).await {
Ok(text) => text,
Err(e @ PeekError::Exceed(max)) => return (e.to_string(), max).into_lua_multi(lua),
Err(e @ PeekError::Unexpected(_)) => {
@ -49,14 +49,14 @@ impl Utils {
}
};
lock.data = vec![Box::new(Paragraph {
lock.data = vec![Box::new(Text {
area,
text,
inner,
wrap: if PREVIEW.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO },
..Default::default()
})];
emit!(Call(Cmd::new("preview").with_any("lock", lock), Layer::Manager));
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
(Value::Nil, Value::Nil).into_lua_multi(lua)
})?,
)?;
@ -67,7 +67,7 @@ impl Utils {
let mut lock = PreviewLock::try_from(t)?;
lock.data = widgets.into_iter().filter_map(|ud| cast_to_renderable(&ud)).collect();
emit!(Call(Cmd::new("preview").with_any("lock", lock), Layer::Manager));
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
Ok(())
})?,
)?;

View File

@ -38,8 +38,8 @@ impl ManagerProxy {
}
#[inline]
pub fn update_task(url: &Url) {
emit!(Call(Cmd::new("update_task").with_any("url", url.clone()), Layer::Manager));
pub fn update_tasks(url: &Url) {
emit!(Call(Cmd::new("update_tasks").with_any("urls", vec![url.clone()]), Layer::Manager));
}
#[inline]

View File

@ -163,7 +163,7 @@ impl Scheduler {
async move {
if !canceled {
fs::remove_dir_all(&target).await.ok();
ManagerProxy::update_task(&target);
ManagerProxy::update_tasks(&target);
Pump::push_delete(target);
}
ongoing.lock().try_remove(id, TaskStage::Hooked);
@ -191,7 +191,7 @@ impl Scheduler {
Box::new(move |canceled: bool| {
async move {
if !canceled {
ManagerProxy::update_task(&target);
ManagerProxy::update_tasks(&target);
Pump::push_trash(target);
}
ongoing.lock().try_remove(id, TaskStage::Hooked);