feat: make custom tab bar easier (#2782)

This commit is contained in:
三咲雅 misaki masa 2025-05-21 13:56:52 +08:00 committed by GitHub
parent 546920e049
commit c6fcb4f799
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 66 additions and 53 deletions

View file

@ -13,5 +13,5 @@ Resolves #
<!--
A clear and concise description of the rationale of the changes, to help our reviewers understand your intent and why it is necessary.
If it already been detailed in the associated issue, please skip this section.
If it has already been detailed in the associated issue, please skip this section.
-->

View file

@ -38,7 +38,7 @@ end
function Modal:children_redraw()
local elements = {}
for _, child in ipairs(self._children) do
elements = ya.list_merge(elements, ya.redraw_with(child[1]:new(self._area)))
elements = ya.list_merge(elements, ui.redraw(child[1]:new(self._area)))
end
return elements
end

View file

@ -26,9 +26,7 @@ function Parent:redraw()
}
end
return {
ui.List(items):area(self._area),
}
return ui.List(items):area(self._area)
end
-- Mouse events

View file

@ -40,9 +40,7 @@ function Progress:redraw()
end
local left = progress.total - progress.succ
return {
gauge
:percent(percent)
:label(ui.Span(string.format("%3d%%, %d left", percent, left)):style(th.status.progress_label)),
}
return gauge
:percent(percent)
:label(ui.Span(string.format("%3d%%, %d left", percent, left)):style(th.status.progress_label))
end

View file

@ -24,7 +24,7 @@ function Rail:reflow() return {} end
function Rail:redraw()
local elements = self._base or {}
for _, child in ipairs(self._children) do
elements = ya.list_merge(elements, ya.redraw_with(child))
elements = ya.list_merge(elements, ui.redraw(child))
end
return elements
end

View file

@ -15,7 +15,7 @@ function Root:layout()
:direction(ui.Layout.VERTICAL)
:constraints({
ui.Constraint.Length(1),
ui.Constraint.Length(#cx.tabs > 1 and 1 or 0),
ui.Constraint.Length(Tabs.height()),
ui.Constraint.Fill(1),
ui.Constraint.Length(1),
})
@ -43,7 +43,7 @@ end
function Root:redraw()
local elements = self._base or {}
for _, child in ipairs(self._children) do
elements = ya.list_merge(elements, ya.redraw_with(child))
elements = ya.list_merge(elements, ui.redraw(child))
end
return elements
end

View file

@ -142,7 +142,7 @@ function Status:redraw()
ui.Text(""):area(self._area):style(th.status.overall),
ui.Line(left):area(self._area),
ui.Line(right):area(self._area):align(ui.Line.RIGHT),
table.unpack(ya.redraw_with(Progress:new(self._area, right_width))),
table.unpack(ui.redraw(Progress:new(self._area, right_width))),
}
end

View file

@ -41,7 +41,7 @@ end
function Tab:redraw()
local elements = self._base or {}
for _, child in ipairs(self._children) do
elements = ya.list_merge(elements, ya.redraw_with(child))
elements = ya.list_merge(elements, ui.redraw(child))
end
return elements
end

View file

@ -38,9 +38,11 @@ function Tabs:redraw()
end
lines[#lines + 1] = ui.Line(th.tabs.sep_outer.close):fg(th.tabs.inactive.bg)
return { ui.Line(lines):area(self._area) }
return ui.Line(lines):area(self._area)
end
function Tabs.height() return #cx.tabs > 1 and 1 or 0 end
function Tabs:inner_width()
local si, so = th.tabs.sep_inner, th.tabs.sep_outer
return math.max(0, self._area.w - ui.Line({ si.open, si.close, so.open, so.close }):width())

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, IntoLua, Lua, Table, Value};
use mlua::{AnyUserData, IntoLua, Lua, Value};
use tracing::error;
use super::Renderable;
@ -25,25 +25,35 @@ pub fn compose(lua: &Lua) -> mlua::Result<Value> {
b"Text" => super::Text::compose(lua)?,
b"width" => super::Utils::width(lua)?,
b"redraw" => super::Utils::redraw(lua)?,
_ => return Ok(Value::Nil),
}
.into_lua(lua)
})
}
pub fn render_once<F>(widgets: Table, buf: &mut ratatui::buffer::Buffer, trans: F)
pub fn render_once<F>(value: Value, buf: &mut ratatui::buffer::Buffer, trans: F)
where
F: Fn(yazi_config::popup::Position) -> ratatui::layout::Rect + Copy,
{
for widget in widgets.sequence_values::<AnyUserData>() {
let Ok(widget) = widget else {
error!("Failed to convert to renderable UserData: {}", widget.unwrap_err());
continue;
};
match value {
Value::Table(tbl) => {
for widget in tbl.sequence_values::<AnyUserData>() {
let Ok(widget) = widget else {
error!("Failed to convert to renderable UserData: {}", widget.unwrap_err());
continue;
};
match Renderable::try_from(widget) {
match Renderable::try_from(widget) {
Ok(w) => w.render(buf, trans),
Err(e) => error!("{e}"),
}
}
}
Value::UserData(ud) => match Renderable::try_from(ud) {
Ok(w) => w.render(buf, trans),
Err(e) => error!("{e}"),
}
},
_ => error!("Expected a renderable UserData, or a table of them, got: {value:?}"),
}
}

View file

@ -1,5 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use mlua::{ExternalError, IntoLua, Lua, ObjectLike, Table, Value};
use tracing::error;
use unicode_width::UnicodeWidthStr;
use yazi_config::LAYOUT;
use super::{Line, Span};
@ -32,4 +34,33 @@ impl Utils {
f.into_lua(lua)
}
pub(super) fn redraw(lua: &Lua) -> mlua::Result<Value> {
let f = lua.create_function(|lua, c: Table| {
let id: mlua::String = c.get("_id")?;
let mut layout = LAYOUT.get();
match id.as_bytes().as_ref() {
b"current" => layout.current = *c.raw_get::<crate::elements::Rect>("_area")?,
b"preview" => layout.preview = *c.raw_get::<crate::elements::Rect>("_area")?,
b"progress" => layout.progress = *c.raw_get::<crate::elements::Rect>("_area")?,
_ => {}
}
LAYOUT.set(layout);
match c.call_method::<Value>("redraw", ())? {
Value::Table(tbl) => Ok(tbl),
Value::UserData(ud) => lua.create_sequence_from([ud]),
_ => {
error!(
"Failed to `redraw()` the `{}` component: expected a table or UserData",
id.display(),
);
lua.create_table()
}
}
})?;
f.into_lua(lua)
}
}

View file

@ -1,6 +1,4 @@
use mlua::{Function, Lua, ObjectLike, Table};
use tracing::error;
use yazi_config::LAYOUT;
use mlua::{Function, Lua, Table};
use yazi_dds::Sendable;
use yazi_macro::{emit, render};
use yazi_shared::{Layer, event::Cmd};
@ -15,29 +13,6 @@ impl Utils {
})
}
pub(super) fn redraw_with(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|lua, c: Table| {
let id: mlua::String = c.get("_id")?;
let mut layout = LAYOUT.get();
match id.as_bytes().as_ref() {
b"current" => layout.current = *c.raw_get::<crate::elements::Rect>("_area")?,
b"preview" => layout.preview = *c.raw_get::<crate::elements::Rect>("_area")?,
b"progress" => layout.progress = *c.raw_get::<crate::elements::Rect>("_area")?,
_ => {}
}
LAYOUT.set(layout);
match c.call_method::<Table>("redraw", ()) {
Err(e) => {
error!("Failed to `redraw()` the `{}` component:\n{e}", id.display());
lua.create_table()
}
ok => ok,
}
})
}
pub(super) fn emit(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|_, (name, args): (mlua::String, Table)| {
let mut cmd = Cmd::new_or(&name.to_str()?, Layer::Mgr)?;

View file

@ -16,7 +16,6 @@ pub fn compose(lua: &Lua, isolate: bool) -> mlua::Result<Value> {
// Call
b"render" => Utils::render(lua)?,
b"redraw_with" => Utils::redraw_with(lua)?,
b"emit" => Utils::emit(lua)?,
b"app_emit" => Utils::app_emit(lua)?,
b"mgr_emit" => Utils::mgr_emit(lua)?,