feat!: make ya.confirm() and ui.Pos() public API (#2921)

This commit is contained in:
三咲雅 misaki masa 2025-06-26 18:12:09 +08:00 committed by GitHub
parent 590d336716
commit 9d05946f4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 85 additions and 54 deletions

View file

@ -124,7 +124,7 @@ separator_style = { fg = "darkgray" }
[confirm] [confirm]
border = { fg = "blue" } border = { fg = "blue" }
title = { fg = "blue" } title = { fg = "blue" }
content = {} body = {}
list = {} list = {}
btn_yes = { reversed = true } btn_yes = { reversed = true }
btn_no = {} btn_no = {}

View file

@ -124,7 +124,7 @@ separator_style = { fg = "darkgray" }
[confirm] [confirm]
border = { fg = "blue" } border = { fg = "blue" }
title = { fg = "blue" } title = { fg = "blue" }
content = {} body = {}
list = {} list = {}
btn_yes = { reversed = true } btn_yes = { reversed = true }
btn_no = {} btn_no = {}

View file

@ -200,16 +200,16 @@ delete_origin = "center"
delete_offset = [ 0, 0, 70, 20 ] delete_offset = [ 0, 0, 70, 20 ]
# overwrite # overwrite
overwrite_title = "Overwrite file?" overwrite_title = "Overwrite file?"
overwrite_content = "Will overwrite the following file:" overwrite_body = "Will overwrite the following file:"
overwrite_origin = "center" overwrite_origin = "center"
overwrite_offset = [ 0, 0, 50, 15 ] overwrite_offset = [ 0, 0, 50, 15 ]
# quit # quit
quit_title = "Quit?" quit_title = "Quit?"
quit_content = "The following tasks are still running, are you sure you want to quit?" quit_body = "The following tasks are still running, are you sure you want to quit?"
quit_origin = "center" quit_origin = "center"
quit_offset = [ 0, 0, 50, 15 ] quit_offset = [ 0, 0, 50, 15 ]
[pick] [pick]
open_title = "Open with:" open_title = "Open with:"

View file

@ -16,16 +16,16 @@ pub struct Confirm {
pub delete_offset: Offset, pub delete_offset: Offset,
// overwrite // overwrite
pub overwrite_title: String, pub overwrite_title: String,
pub overwrite_content: String, pub overwrite_body: String,
pub overwrite_origin: Origin, pub overwrite_origin: Origin,
pub overwrite_offset: Offset, pub overwrite_offset: Offset,
// quit // quit
pub quit_title: String, pub quit_title: String,
pub quit_content: String, pub quit_body: String,
pub quit_origin: Origin, pub quit_origin: Origin,
pub quit_offset: Offset, pub quit_offset: Offset,
} }
impl Confirm { impl Confirm {

View file

@ -26,7 +26,7 @@ pub struct PickCfg {
pub struct ConfirmCfg { pub struct ConfirmCfg {
pub position: Position, pub position: Position,
pub title: Line<'static>, pub title: Line<'static>,
pub content: Paragraph<'static>, pub body: Paragraph<'static>,
pub list: Paragraph<'static>, pub list: Paragraph<'static>,
} }
@ -107,13 +107,13 @@ impl ConfirmCfg {
fn new( fn new(
title: String, title: String,
(origin, offset): (Origin, Offset), (origin, offset): (Origin, Offset),
content: Option<Text<'static>>, body: Option<Text<'static>>,
list: Option<Text<'static>>, list: Option<Text<'static>>,
) -> Self { ) -> Self {
Self { Self {
position: Position::new(origin, offset), position: Position::new(origin, offset),
title: Line::raw(title), title: Line::raw(title),
content: content.map(|c| Paragraph::new(c).wrap(Wrap { trim: false })).unwrap_or_default(), body: body.map(|c| Paragraph::new(c).wrap(Wrap { trim: false })).unwrap_or_default(),
list: list.map(|l| Paragraph::new(l).wrap(Wrap { trim: false })).unwrap_or_default(), list: list.map(|l| Paragraph::new(l).wrap(Wrap { trim: false })).unwrap_or_default(),
} }
} }
@ -140,7 +140,7 @@ impl ConfirmCfg {
Self::new( Self::new(
YAZI.confirm.overwrite_title.to_owned(), YAZI.confirm.overwrite_title.to_owned(),
(YAZI.confirm.overwrite_origin, YAZI.confirm.overwrite_offset), (YAZI.confirm.overwrite_origin, YAZI.confirm.overwrite_offset),
Some(Text::raw(&YAZI.confirm.overwrite_content)), Some(Text::raw(&YAZI.confirm.overwrite_body)),
Some(url.to_string().into()), Some(url.to_string().into()),
) )
} }
@ -149,7 +149,7 @@ impl ConfirmCfg {
Self::new( Self::new(
Self::replace_number(&YAZI.confirm.quit_title, len), Self::replace_number(&YAZI.confirm.quit_title, len),
(YAZI.confirm.quit_origin, YAZI.confirm.quit_offset), (YAZI.confirm.quit_origin, YAZI.confirm.quit_offset),
Some(Text::raw(&YAZI.confirm.quit_content)), Some(Text::raw(&YAZI.confirm.quit_body)),
Self::truncate_list(names.into_iter(), len, 10), Self::truncate_list(names.into_iter(), len, 10),
) )
} }

View file

@ -132,10 +132,10 @@ pub struct Which {
#[derive(Deserialize, DeserializeOver2)] #[derive(Deserialize, DeserializeOver2)]
pub struct Confirm { pub struct Confirm {
pub border: Style, pub border: Style,
pub title: Style, pub title: Style,
pub content: Style, pub body: Style,
pub list: Style, pub list: Style,
pub btn_yes: Style, pub btn_yes: Style,
pub btn_no: Style, pub btn_no: Style,

View file

@ -26,7 +26,7 @@ impl Confirm {
self.close(false); self.close(false);
self.title = opt.cfg.title; self.title = opt.cfg.title;
self.content = opt.cfg.content; self.body = opt.cfg.body;
self.list = opt.cfg.list; self.list = opt.cfg.list;
self.position = opt.cfg.position; self.position = opt.cfg.position;

View file

@ -4,9 +4,9 @@ use yazi_config::popup::Position;
#[derive(Default)] #[derive(Default)]
pub struct Confirm { pub struct Confirm {
pub title: Line<'static>, pub title: Line<'static>,
pub content: Paragraph<'static>, pub body: Paragraph<'static>,
pub list: Paragraph<'static>, pub list: Paragraph<'static>,
pub position: Position, pub position: Position,
pub offset: usize, pub offset: usize,

View file

@ -3,20 +3,20 @@ use yazi_config::THEME;
use crate::Ctx; use crate::Ctx;
pub(crate) struct Content<'a> { pub(crate) struct Body<'a> {
cx: &'a Ctx, cx: &'a Ctx,
border: bool, border: bool,
} }
impl<'a> Content<'a> { impl<'a> Body<'a> {
pub(crate) fn new(cx: &'a Ctx, border: bool) -> Self { Self { cx, border } } pub(crate) fn new(cx: &'a Ctx, border: bool) -> Self { Self { cx, border } }
} }
impl Widget for Content<'_> { impl Widget for Body<'_> {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let confirm = &self.cx.confirm; let confirm = &self.cx.confirm;
// Content area // Inner area
let inner = area.inner(Margin::new(1, 0)); let inner = area.inner(Margin::new(1, 0));
// Border // Border
@ -27,11 +27,11 @@ impl Widget for Content<'_> {
}; };
confirm confirm
.content .body
.clone() .clone()
.alignment(ratatui::layout::Alignment::Center) .alignment(ratatui::layout::Alignment::Center)
.block(block) .block(block)
.style(THEME.confirm.content.derive(Styled::style(&confirm.content))) .style(THEME.confirm.body.derive(Styled::style(&confirm.body)))
.render(inner, buf); .render(inner, buf);
} }
} }

View file

@ -25,21 +25,21 @@ impl Widget for Confirm<'_> {
.title_alignment(Alignment::Center) .title_alignment(Alignment::Center)
.render(area, buf); .render(area, buf);
let content_border = confirm.list.line_count(area.width) != 0; let body_border = confirm.list.line_count(area.width) != 0;
let content_height = confirm.content.line_count(area.width) as u16; let body_height = confirm.body.line_count(area.width) as u16;
let chunks = Layout::vertical([ let chunks = Layout::vertical([
Constraint::Length(if content_height == 0 { Constraint::Length(if body_height == 0 {
0 0
} else { } else {
content_height.saturating_add(content_border as u16) body_height.saturating_add(body_border as u16)
}), }),
Constraint::Fill(1), Constraint::Fill(1),
Constraint::Length(1), Constraint::Length(1),
]) ])
.split(area.inner(Margin::new(0, 1))); .split(area.inner(Margin::new(0, 1)));
super::Content::new(self.cx, content_border).render(chunks[0], buf); super::Body::new(self.cx, body_border).render(chunks[0], buf);
super::List::new(self.cx).render(chunks[1], buf); super::List::new(self.cx).render(chunks[1], buf);
super::Buttons.render(chunks[2], buf); super::Buttons.render(chunks[2], buf);
} }

View file

@ -1 +1 @@
yazi_macro::mod_flat!(buttons confirm content list); yazi_macro::mod_flat!(buttons confirm body list);

View file

@ -158,7 +158,7 @@ impl Theme {
match key { match key {
b"border" => Style::from(t.border).into_lua(lua), b"border" => Style::from(t.border).into_lua(lua),
b"title" => Style::from(t.title).into_lua(lua), b"title" => Style::from(t.title).into_lua(lua),
b"content" => Style::from(t.content).into_lua(lua), b"body" => Style::from(t.body).into_lua(lua),
b"list" => Style::from(t.list).into_lua(lua), b"list" => Style::from(t.list).into_lua(lua),
b"btn_yes" => Style::from(t.btn_yes).into_lua(lua), b"btn_yes" => Style::from(t.btn_yes).into_lua(lua),

View file

@ -1,9 +1,11 @@
use std::{ops::Deref, str::FromStr}; use std::{ops::Deref, str::FromStr};
use mlua::{AnyUserData, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value}; use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Pad; use super::Pad;
const EXPECTED: &str = "expected a Pos";
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct Pos { pub struct Pos {
inner: yazi_config::popup::Position, inner: yazi_config::popup::Position,
@ -45,6 +47,24 @@ impl TryFrom<mlua::Table> for Pos {
} }
} }
impl TryFrom<Value> for Pos {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
Ok(match value {
Value::Table(tbl) => Self::try_from(tbl)?,
Value::UserData(ud) => {
if let Ok(pos) = ud.borrow() {
*pos
} else {
Err(EXPECTED.into_lua_err())?
}
}
_ => Err(EXPECTED.into_lua_err())?,
})
}
}
impl Pos { impl Pos {
pub fn compose(lua: &Lua) -> mlua::Result<Value> { pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, t): (Table, Table)| Self::try_from(t))?; let new = lua.create_function(|_, (_, t): (Table, Table)| Self::try_from(t))?;
@ -55,8 +75,8 @@ impl Pos {
position.into_lua(lua) position.into_lua(lua)
} }
pub fn new_input(t: mlua::Table) -> mlua::Result<Self> { pub fn new_input(v: Value) -> mlua::Result<Self> {
let mut p = Self::try_from(t)?; let mut p = Self::try_from(v)?;
p.inner.offset.height = 3; p.inner.offset.height = 3;
Ok(p) Ok(p)
} }

View file

@ -76,7 +76,7 @@ macro_rules! runtime_mut {
#[macro_export] #[macro_export]
macro_rules! deprecate { macro_rules! deprecate {
($lua:ident, $tt:tt) => {{ ($lua:ident, $tt:tt) => {{
let id = match $lua.named_registry_value::<$crate::RtRef>("ir")?.current() { let id = match $crate::runtime!($lua)?.current() {
Some(id) => &format!("`{id}.yazi` plugin"), Some(id) => &format!("`{id}.yazi` plugin"),
None => "`init.lua` config", None => "`init.lua` config",
}; };

View file

@ -9,7 +9,7 @@ use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy};
use yazi_shared::{Debounce, event::Cmd}; use yazi_shared::{Debounce, event::Cmd};
use super::Utils; use super::Utils;
use crate::{bindings::InputRx, elements::{Line, Pos, Text}}; use crate::{bindings::InputRx, deprecate, elements::{Line, Pos, Text}};
impl Utils { impl Utils {
pub(super) fn which(lua: &Lua) -> mlua::Result<Function> { pub(super) fn which(lua: &Lua) -> mlua::Result<Function> {
@ -40,13 +40,24 @@ impl Utils {
pub(super) fn input(lua: &Lua) -> mlua::Result<Function> { pub(super) fn input(lua: &Lua) -> mlua::Result<Function> {
lua.create_async_function(|lua, t: Table| async move { lua.create_async_function(|lua, t: Table| async move {
let mut pos = t.raw_get::<Value>("pos")?;
if pos.is_nil() {
pos = t.raw_get("position")?;
if !pos.is_nil() {
deprecate!(
lua,
"The `position` property of `ya.input()` is deprecated, use `pos` instead in your {}\nSee #2921 for more details: https://github.com/sxyazi/yazi/pull/2921"
);
}
}
let realtime = t.raw_get("realtime").unwrap_or_default(); let realtime = t.raw_get("realtime").unwrap_or_default();
let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg { let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg {
title: t.raw_get("title")?, title: t.raw_get("title")?,
value: t.raw_get("value").unwrap_or_default(), value: t.raw_get("value").unwrap_or_default(),
cursor: None, // TODO cursor: None, // TODO
obscure: t.raw_get("obscure").unwrap_or_default(), obscure: t.raw_get("obscure").unwrap_or_default(),
position: Pos::new_input(t.raw_get::<Table>("position")?)?.into(), position: Pos::new_input(pos)?.into(),
realtime, realtime,
completion: false, completion: false,
})); }));
@ -67,8 +78,8 @@ impl Utils {
} }
pub(super) fn confirm(lua: &Lua) -> mlua::Result<Function> { pub(super) fn confirm(lua: &Lua) -> mlua::Result<Function> {
fn content(t: &Table) -> mlua::Result<ratatui::widgets::Paragraph<'static>> { fn body(t: &Table) -> mlua::Result<ratatui::widgets::Paragraph<'static>> {
Ok(match t.raw_get::<Value>("content")? { Ok(match t.raw_get::<Value>("body")? {
Value::Nil => Default::default(), Value::Nil => Default::default(),
v => Text::try_from(v)?.into(), v => Text::try_from(v)?.into(),
}) })
@ -76,9 +87,9 @@ impl Utils {
lua.create_async_function(|_, t: Table| async move { lua.create_async_function(|_, t: Table| async move {
let result = ConfirmProxy::show(ConfirmCfg { let result = ConfirmProxy::show(ConfirmCfg {
position: Pos::try_from(t.raw_get::<Table>("pos")?)?.into(), position: Pos::try_from(t.raw_get::<Value>("pos")?)?.into(),
title: Line::try_from(t.raw_get::<Value>("title")?)?.into(), title: Line::try_from(t.raw_get::<Value>("title")?)?.into(),
content: content(&t)?, body: body(&t)?,
list: Default::default(), // TODO list: Default::default(), // TODO
}); });