feat: new ya.confirm() API (#2095)

This commit is contained in:
三咲雅 · Misaki Masa 2024-12-25 00:35:46 +08:00 committed by GitHub
parent 50a81bea31
commit 7d3e58951c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 74 additions and 39 deletions

View file

@ -204,7 +204,7 @@ overwrite_offset = [ 0, 0, 50, 15 ]
# quit # quit
quit_title = "Quit?" quit_title = "Quit?"
quit_content = "The following task is still running, are you sure you want to quit?" quit_content = "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 ]

View file

@ -1,4 +1,4 @@
use ratatui::{text::Text, widgets::{Paragraph, Wrap}}; use ratatui::{text::{Line, Text}, widgets::{Paragraph, Wrap}};
use yazi_shared::url::Url; use yazi_shared::url::Url;
use super::{Offset, Origin, Position}; use super::{Offset, Origin, Position};
@ -24,8 +24,8 @@ pub struct PickCfg {
#[derive(Default)] #[derive(Default)]
pub struct ConfirmCfg { pub struct ConfirmCfg {
pub title: String,
pub position: Position, pub position: Position,
pub title: Line<'static>,
pub content: Paragraph<'static>, pub content: Paragraph<'static>,
pub list: Paragraph<'static>, pub list: Paragraph<'static>,
} }
@ -112,10 +112,10 @@ impl ConfirmCfg {
list: Option<Text<'static>>, list: Option<Text<'static>>,
) -> Self { ) -> Self {
Self { Self {
title,
position: Position::new(origin, offset), position: Position::new(origin, offset),
content: content.map(|c| Paragraph::new(c).wrap(Wrap { trim: false })).unwrap_or_default(), title: Line::raw(title),
list: list.map(|l| Paragraph::new(l).wrap(Wrap { trim: false })).unwrap_or_default(), content: content.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(),
} }
} }

View file

@ -29,8 +29,8 @@ impl Confirm {
self.content = opt.cfg.content; self.content = opt.cfg.content;
self.list = opt.cfg.list; self.list = opt.cfg.list;
self.offset = 0;
self.position = opt.cfg.position; self.position = opt.cfg.position;
self.offset = 0;
self.callback = Some(opt.tx); self.callback = Some(opt.tx);
self.visible = true; self.visible = true;

View file

@ -1,15 +1,15 @@
use ratatui::widgets::Paragraph; use ratatui::{text::Line, widgets::Paragraph};
use tokio::sync::oneshot::Sender; use tokio::sync::oneshot::Sender;
use yazi_config::popup::Position; use yazi_config::popup::Position;
#[derive(Default)] #[derive(Default)]
pub struct Confirm { pub struct Confirm {
pub title: String, pub title: Line<'static>,
pub content: Paragraph<'static>, pub content: Paragraph<'static>,
pub list: Paragraph<'static>, pub list: Paragraph<'static>,
pub offset: usize,
pub position: Position, pub position: Position,
pub offset: usize,
pub(super) callback: Option<Sender<bool>>, pub(super) callback: Option<Sender<bool>>,
pub visible: bool, pub visible: bool,

View file

@ -1,4 +1,4 @@
use ratatui::{buffer::Buffer, layout::{Alignment, Constraint, Layout, Margin, Rect}, text::Line, widgets::{Block, BorderType, Widget}}; use ratatui::{buffer::Buffer, layout::{Alignment, Constraint, Layout, Margin, Rect}, widgets::{Block, BorderType, Widget}};
use yazi_config::THEME; use yazi_config::THEME;
use crate::Ctx; use crate::Ctx;
@ -12,7 +12,7 @@ impl<'a> Confirm<'a> {
} }
impl Widget for Confirm<'_> { impl Widget for Confirm<'_> {
fn render(self, _win: Rect, buf: &mut Buffer) { fn render(self, _: Rect, buf: &mut Buffer) {
let confirm = &self.cx.confirm; let confirm = &self.cx.confirm;
let area = self.cx.manager.area(confirm.position); let area = self.cx.manager.area(confirm.position);
@ -21,21 +21,26 @@ impl Widget for Confirm<'_> {
Block::bordered() Block::bordered()
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.border_style(THEME.confirm.border) .border_style(THEME.confirm.border)
.title(Line::styled(&confirm.title, THEME.confirm.title)) .title(confirm.title.clone().style(THEME.confirm.title.derive(confirm.title.style)))
.title_alignment(Alignment::Center) .title_alignment(Alignment::Center)
.render(area, buf); .render(area, buf);
let content = confirm.content.clone(); let content = confirm.content.clone();
let content_height = content.line_count(area.width).saturating_add(1) as u16; let content_border = confirm.list.line_count(area.width) != 0;
let content_height = content.line_count(area.width) as u16;
let chunks = Layout::vertical([ let chunks = Layout::vertical([
Constraint::Length(if content_height == 1 { 0 } else { content_height }), Constraint::Length(if content_height == 0 {
0
} else {
content_height.saturating_add(content_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(content).render(chunks[0], buf); super::Content::new(self.cx, content_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,28 +1,37 @@
use ratatui::{buffer::Buffer, layout::{Margin, Rect}, widgets::{Block, Borders, Paragraph, Widget}}; use ratatui::{buffer::Buffer, layout::{Margin, Rect}, style::Styled, widgets::{Block, Borders, Widget}};
use yazi_config::THEME; use yazi_config::THEME;
use crate::Ctx;
pub(crate) struct Content<'a> { pub(crate) struct Content<'a> {
p: Paragraph<'a>, cx: &'a Ctx,
border: bool,
} }
impl<'a> Content<'a> { impl<'a> Content<'a> {
pub(crate) fn new(p: Paragraph<'a>) -> Self { Self { p } } pub(crate) fn new(cx: &'a Ctx, border: bool) -> Self { Self { cx, border } }
} }
impl Widget for Content<'_> { impl Widget for Content<'_> {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let confirm = &self.cx.confirm;
// Content area // Content area
let inner = area.inner(Margin::new(1, 0)); let inner = area.inner(Margin::new(1, 0));
// Bottom border // Border
let block = Block::new().borders(Borders::BOTTOM).border_style(THEME.confirm.border); let block = if self.border {
block.clone().render(area.inner(Margin::new(1, 0)), buf); Block::new().borders(Borders::BOTTOM).border_style(THEME.confirm.border)
} else {
Block::new()
};
self confirm
.p .content
.clone()
.alignment(ratatui::layout::Alignment::Center) .alignment(ratatui::layout::Alignment::Center)
.block(block) .block(block)
.style(THEME.confirm.content) .style(THEME.confirm.content.derive(Styled::style(&confirm.content)))
.render(inner, buf); .render(inner, buf);
} }
} }

View file

@ -93,6 +93,10 @@ impl TryFrom<Table> for Line {
} }
} }
impl From<Line> for ratatui::text::Line<'static> {
fn from(value: Line) -> Self { value.0 }
}
impl UserData for Line { impl UserData for Line {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
crate::impl_style_method!(methods, 0.style); crate::impl_style_method!(methods, 0.style);

View file

@ -3,13 +3,13 @@ use std::{str::FromStr, time::Duration};
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value}; use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
use yazi_config::{keymap::{Chord, Key}, popup::InputCfg}; use yazi_config::{keymap::{Chord, Key}, popup::{ConfirmCfg, InputCfg}};
use yazi_macro::emit; use yazi_macro::emit;
use yazi_proxy::{AppProxy, InputProxy}; use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy};
use yazi_shared::{Debounce, Layer, event::Cmd}; use yazi_shared::{Debounce, Layer, event::Cmd};
use super::Utils; use super::Utils;
use crate::{bindings::InputRx, elements::Pos}; use crate::{bindings::InputRx, 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> {
@ -68,17 +68,26 @@ impl Utils {
}) })
} }
// TODO: redesign the confirm API pub(super) fn confirm(lua: &Lua) -> mlua::Result<Function> {
// pub(super) fn confirm(lua: &Lua, ya: &Table) -> mlua::Result<Function> { fn content(t: &Table) -> mlua::Result<ratatui::widgets::Paragraph<'static>> {
// lua.create_async_function(|_, t: Table| async move { Ok(match t.raw_get::<Value>("content") {
// let result = ConfirmProxy::show(ConfirmCfg { Ok(v) if v.is_nil() => Default::default(),
// title: t.raw_get("title")?, Ok(v) => Text::try_from(v)?.into(),
// content: t.raw_get("content")?, Err(e) => Err(e)?,
// position: Position::try_from(t.raw_get::<_, Table>("position")?)?.into(), })
// }); }
// Ok(result.await)
// }) lua.create_async_function(|_, t: Table| async move {
// } let result = ConfirmProxy::show(ConfirmCfg {
position: Pos::try_from(t.raw_get::<Table>("pos")?)?.into(),
title: Line::try_from(t.raw_get::<Value>("title")?)?.into(),
content: content(&t)?,
list: Default::default(), // TODO
});
Ok(result.await)
})
}
pub(super) fn notify(lua: &Lua) -> mlua::Result<Function> { pub(super) fn notify(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|_, t: Table| { lua.create_function(|_, t: Table| {

View file

@ -30,6 +30,7 @@ pub fn compose(lua: &Lua, isolate: bool) -> mlua::Result<Table> {
// Layout // Layout
b"which" => Utils::which(lua)?, b"which" => Utils::which(lua)?,
b"input" => Utils::input(lua)?, b"input" => Utils::input(lua)?,
b"confirm" => Utils::confirm(lua)?,
b"notify" => Utils::notify(lua)?, b"notify" => Utils::notify(lua)?,
// Log // Log

View file

@ -36,6 +36,13 @@ impl From<Style> for ratatui::style::Style {
} }
} }
impl Style {
#[inline]
pub fn derive(self, other: ratatui::style::Style) -> ratatui::style::Style {
ratatui::style::Style::from(self).patch(other)
}
}
#[derive(Default, Deserialize)] #[derive(Default, Deserialize)]
pub struct StyleShadow { pub struct StyleShadow {
#[serde(default)] #[serde(default)]