refactor: implement FromLua instead of TryFrom<Value> (#3760)

This commit is contained in:
三咲雅 misaki masa 2026-03-13 20:28:44 +08:00 committed by GitHub
parent 3534ba0705
commit fa1ee46edc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 156 additions and 198 deletions

40
Cargo.lock generated
View file

@ -109,9 +109,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.21"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
@ -130,9 +130,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
@ -600,9 +600,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.60"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
dependencies = [
"clap_builder",
"clap_derive",
@ -610,9 +610,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.60"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstream",
"anstyle",
@ -622,9 +622,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.66"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c757a3b7e39161a4e56f9365141ada2a6c915a8622c408ab6bb4b5d047371031"
checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb"
dependencies = [
"clap",
]
@ -641,9 +641,9 @@ dependencies = [
[[package]]
name = "clap_complete_nushell"
version = "4.5.10"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685bc86fd34b7467e0532a4f8435ab107960d69a243785ef0275e571b35b641a"
checksum = "fbb9e9715d29a754b468591be588f6b926f5b0a1eb6a8b62acabeb66ff84d897"
dependencies = [
"clap",
"clap_complete",
@ -651,9 +651,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.55"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
dependencies = [
"heck",
"proc-macro2",
@ -663,9 +663,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "1.0.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "clipboard-win"
@ -2769,9 +2769,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.21.3"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "once_cell_polyfill"
@ -4755,9 +4755,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.22"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
dependencies = [
"matchers",
"nu-ansi-term",

View file

@ -40,7 +40,7 @@ anyhow = "1.0.102"
base64 = "0.22.1"
bitflags = { version = "2.11.0", features = [ "serde" ] }
chrono = "0.4.44"
clap = { version = "4.5.60", features = [ "derive" ] }
clap = { version = "4.6.0", features = [ "derive" ] }
core-foundation-sys = "0.8.7"
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
dirs = "6.0.0"

View file

@ -1,14 +1,12 @@
use std::str::FromStr;
use mlua::{ExternalError, ExternalResult, UserData, Value};
use mlua::{ExternalError, ExternalResult, FromLua, Lua, UserData, Value};
#[derive(Clone, Copy, Default)]
pub struct Color(pub ratatui::style::Color);
impl TryFrom<Value> for Color {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
impl FromLua for Color {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(Self(match value {
Value::String(s) => ratatui::style::Color::from_str(&s.to_str()?).into_lua_err()?,
Value::UserData(ud) => ud.borrow::<Self>()?.0,

View file

@ -1,6 +1,6 @@
use std::fmt::Debug;
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Value};
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, Value};
use super::{Pos, Rect};
@ -70,7 +70,7 @@ impl TryFrom<AnyUserData> for Area {
}
impl FromLua for Area {
fn from_lua(value: Value, _: &mlua::Lua) -> mlua::Result<Self> {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
match value {
Value::UserData(ud) => Self::try_from(ud),
_ => Err(EXPECTED.into_lua_err()),
@ -79,7 +79,7 @@ impl FromLua for Area {
}
impl IntoLua for Area {
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
match self {
Self::Pos(pos) => pos.into_lua(lua),
Self::Rect(rect) => rect.into_lua(lua),

View file

@ -78,14 +78,14 @@ impl UserData for Border {
});
methods.add_function_mut(
"title",
|_, (ud, line, position): (AnyUserData, Value, Option<u8>)| {
|_, (ud, line, position): (AnyUserData, Line, Option<u8>)| {
let position = if position == Some(Borders::BOTTOM.bits()) {
ratatui::widgets::TitlePosition::Bottom
} else {
ratatui::widgets::TitlePosition::Top
};
ud.borrow_mut::<Self>()?.titles.push((position, Line::try_from(line)?.inner));
ud.borrow_mut::<Self>()?.titles.push((position, line.inner));
Ok(ud)
},
);

View file

@ -1,9 +1,7 @@
use mlua::{ExternalError, FromLua};
use mlua::{FromLua, Lua, Value};
use super::Text;
const EXPECTED: &str = "expected a table of strings, Texts, Lines or Spans";
#[derive(Clone, Debug)]
pub struct Cell {
pub(super) text: ratatui::text::Text<'static>,
@ -14,7 +12,7 @@ impl From<Cell> for ratatui::widgets::Cell<'static> {
}
impl FromLua for Cell {
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
Ok(Self { text: Text::try_from(value).map_err(|_| EXPECTED.into_lua_err())?.inner })
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
Ok(Self { text: Text::from_lua(value, lua)?.inner })
}
}

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, IntoLua, Lua, Value};
use mlua::{IntoLua, Lua, Value};
use tracing::error;
use super::Renderable;
@ -42,22 +42,17 @@ where
{
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) {
for widget in tbl.sequence_values::<Renderable>() {
match widget {
Ok(w) => w.render_with(buf, trans),
Err(e) => error!("{e}"),
Err(e) => error!("Failed to convert to renderable elements: {e}"),
}
}
}
Value::UserData(ud) => match Renderable::try_from(ud) {
Value::UserData(ud) => match Renderable::try_from(&ud) {
Ok(w) => w.render_with(buf, trans),
Err(e) => error!("{e}"),
Err(e) => error!("Failed to convert to renderable element: {e}"),
},
_ => error!("Expected a renderable UserData, or a table of them, got: {value:?}"),
_ => error!("Expected a renderable element, or a table of them, got: {value:?}"),
}
}

View file

@ -61,8 +61,8 @@ impl UserData for Gauge {
Ok(ud)
});
methods.add_function_mut("label", |_, (ud, label): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.label = Some(Span::try_from(label)?.0);
methods.add_function_mut("label", |_, (ud, label): (AnyUserData, Span)| {
ud.borrow_mut::<Self>()?.label = Some(label.0);
Ok(ud)
});

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, mem, ops::{Deref, DerefMut}};
use ansi_to_tui::IntoText;
use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use ratatui::widgets::Widget;
use unicode_width::UnicodeWidthChar;
@ -29,7 +29,7 @@ impl DerefMut for Line {
impl Line {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Self::try_from(value))?;
let new = lua.create_function(|_, (_, line): (Table, Self)| Ok(line))?;
let parse = lua.create_function(|_, code: mlua::String| {
let code = code.as_bytes();
@ -55,30 +55,6 @@ impl Line {
}
}
impl TryFrom<Value> for Line {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
Ok(Self {
inner: match value {
Value::Table(tb) => return Self::try_from(tb),
Value::String(s) => s.to_string_lossy().into(),
Value::UserData(ud) => {
if let Ok(Span(span)) = ud.take() {
span.into()
} else if let Ok(line) = ud.take() {
return Ok(line);
} else {
Err(EXPECTED.into_lua_err())?
}
}
_ => Err(EXPECTED.into_lua_err())?,
},
..Default::default()
})
}
}
impl TryFrom<Table> for Line {
type Error = mlua::Error;
@ -108,6 +84,28 @@ impl From<Line> for ratatui::text::Line<'static> {
fn from(value: Line) -> Self { value.inner }
}
impl FromLua for Line {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(Self {
inner: match value {
Value::Table(tb) => return Self::try_from(tb),
Value::String(s) => s.to_string_lossy().into(),
Value::UserData(ud) => {
if let Ok(Span(span)) = ud.take() {
span.into()
} else if let Ok(line) = ud.take() {
return Ok(line);
} else {
Err(EXPECTED.into_lua_err())?
}
}
_ => Err(EXPECTED.into_lua_err())?,
},
..Default::default()
})
}
}
impl UserData for Line {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
crate::impl_area_method!(methods);
@ -122,7 +120,7 @@ impl UserData for Line {
methods.add_method("visible", |_, me, ()| {
Ok(me.iter().flat_map(|s| s.content.chars()).any(|c| c.width().unwrap_or(0) > 0))
});
methods.add_function_mut("truncate", |_, (ud, t): (AnyUserData, Table)| {
methods.add_function_mut("truncate", |lua, (ud, t): (AnyUserData, Table)| {
let mut me = ud.borrow_mut::<Self>()?;
let max = t.raw_get("max")?;
@ -134,7 +132,7 @@ impl UserData for Line {
let ellipsis = match t.raw_get::<Value>("ellipsis")? {
Value::Nil => (1, ratatui::text::Span::raw("")),
v => {
let mut span = Span::try_from(v)?;
let mut span = Span::from_lua(v, lua)?;
(span.truncate(max), span.0)
}
};

View file

@ -1,10 +1,8 @@
use mlua::{ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use mlua::{IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::Widget;
use super::{Area, Text};
const EXPECTED: &str = "expected a table of strings, Texts, Lines or Spans";
// --- List
#[derive(Clone, Debug, Default)]
pub struct List {
@ -15,12 +13,7 @@ pub struct List {
impl List {
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>() {
items.push(Text::try_from(v?).map_err(|_| EXPECTED.into_lua_err())?);
}
let new = lua.create_function(|_, (_, items): (Table, Vec<Text>)| {
Ok(Self { inner: ratatui::widgets::List::new(items), ..Default::default() })
})?;

View file

@ -1,6 +1,6 @@
use std::{ops::Deref, str::FromStr};
use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Pad;
@ -29,10 +29,10 @@ impl From<Pos> for yazi_config::popup::Position {
fn from(value: Pos) -> Self { value.inner }
}
impl TryFrom<mlua::Table> for Pos {
impl TryFrom<Table> for Pos {
type Error = mlua::Error;
fn try_from(t: mlua::Table) -> Result<Self, Self::Error> {
fn try_from(t: Table) -> Result<Self, Self::Error> {
use yazi_config::popup::{Offset, Origin, Position};
Ok(Self::from(Position {
@ -47,10 +47,8 @@ impl TryFrom<mlua::Table> for Pos {
}
}
impl TryFrom<Value> for Pos {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
impl FromLua for Pos {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::Table(tbl) => Self::try_from(tbl)?,
Value::UserData(ud) => {
@ -75,10 +73,9 @@ impl Pos {
position.into_lua(lua)
}
pub fn new_input(v: Value) -> mlua::Result<Self> {
let mut p = Self::try_from(v)?;
p.inner.offset.height = 3;
Ok(p)
pub fn with_height(mut self, height: u16) -> Self {
self.inner.offset.height = height;
self
}
}

View file

@ -1,6 +1,6 @@
use std::any::TypeId;
use mlua::{AnyUserData, ExternalError};
use mlua::{AnyUserData, ExternalError, FromLua, Lua, Value};
use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text};
use crate::{Error, elements::Area};
@ -81,17 +81,11 @@ impl TryFrom<&AnyUserData> for Renderable {
Some(t) if t == TypeId::of::<Border>() => Self::Border(ud.take()?),
Some(t) if t == TypeId::of::<Gauge>() => Self::Gauge(Box::new(ud.take()?)),
Some(t) if t == TypeId::of::<Table>() => Self::Table(Box::new(ud.take()?)),
_ => Err(format!("expected a UserData of renderable element, not: {ud:#?}").into_lua_err())?,
_ => Err(format!("expected a renderable userdata, not: {ud:#?}").into_lua_err())?,
})
}
}
impl TryFrom<AnyUserData> for Renderable {
type Error = mlua::Error;
fn try_from(ud: AnyUserData) -> Result<Self, Self::Error> { Self::try_from(&ud) }
}
impl From<Error> for Renderable {
fn from(error: Error) -> Self {
Self::Text(Text {
@ -101,3 +95,12 @@ impl From<Error> for Renderable {
})
}
}
impl FromLua for Renderable {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
match value {
Value::UserData(ud) => Self::try_from(&ud),
_ => Err(format!("expected a renderable userdata, not: {value:#?}").into_lua_err()),
}
}
}

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Cell;
@ -36,10 +36,8 @@ impl From<Row> for ratatui::widgets::Row<'static> {
}
}
impl TryFrom<Value> for Row {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
impl FromLua for Row {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::UserData(ud) => {
if let Ok(row) = ud.take() {

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ops::{Deref, DerefMut}};
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use unicode_width::UnicodeWidthChar;
const EXPECTED: &str = "expected a string or Span";
@ -19,7 +19,7 @@ impl DerefMut for Span {
impl Span {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Self::try_from(value))?;
let new = lua.create_function(|_, (_, span): (Table, Self)| Ok(span))?;
let span = lua.create_table()?;
span.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?;
@ -58,10 +58,8 @@ impl Span {
}
}
impl TryFrom<Value> for Span {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
impl FromLua for Span {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(Self(match value {
Value::String(s) => s.to_string_lossy().into(),
Value::UserData(ud) => {

View file

@ -1,11 +1,9 @@
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, UserData, Value};
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, UserData, Value};
use ratatui::widgets::StatefulWidget;
use super::{Area, Row};
use crate::{Style, elements::Constraint};
const EXPECTED: &str = "expected a table of Rows";
// --- Table
#[derive(Clone, Debug, Default)]
pub struct Table {
@ -33,12 +31,7 @@ pub struct Table {
impl 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>() {
rows.push(Row::try_from(v?).map_err(|_| EXPECTED.into_lua_err())?);
}
let new = lua.create_function(|_, (_, rows): (mlua::Table, Vec<Row>)| {
Ok(Self { rows, ..Default::default() })
})?;
@ -101,12 +94,12 @@ impl UserData for Table {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
crate::impl_area_method!(methods);
methods.add_function_mut("header", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.header = Some(Row::try_from(value)?.into());
methods.add_function_mut("header", |_, (ud, header): (AnyUserData, Row)| {
ud.borrow_mut::<Self>()?.header = Some(header.into());
Ok(ud)
});
methods.add_function_mut("footer", |_, (ud, value): (AnyUserData, Value)| {
ud.borrow_mut::<Self>()?.footer = Some(Row::try_from(value)?.into());
methods.add_function_mut("footer", |_, (ud, footer): (AnyUserData, Row)| {
ud.borrow_mut::<Self>()?.footer = Some(footer.into());
Ok(ud)
});
methods.add_function_mut("widths", |_, (ud, widths): (AnyUserData, Vec<Constraint>)| {

View file

@ -1,7 +1,7 @@
use std::{any::TypeId, mem};
use ansi_to_tui::IntoText;
use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use ratatui::widgets::Widget;
use super::{Area, Line, Span, Wrap};
@ -21,7 +21,7 @@ pub struct Text {
impl Text {
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
let new = lua.create_function(|_, (_, value): (Table, Value)| Self::try_from(value))?;
let new = lua.create_function(|_, (_, text): (Table, Self)| Ok(text))?;
let parse = lua.create_function(|_, code: mlua::String| {
Ok(Self { inner: code.as_bytes().into_text().into_lua_err()?, ..Default::default() })
@ -41,26 +41,6 @@ impl Text {
}
}
impl TryFrom<Value> for Text {
type Error = mlua::Error;
fn try_from(value: Value) -> mlua::Result<Self> {
let inner = match value {
Value::Table(tb) => return Self::try_from(tb),
Value::String(s) => s.to_string_lossy().into(),
Value::UserData(ud) => match ud.type_id() {
Some(t) if t == TypeId::of::<Line>() => ud.take::<Line>()?.inner.into(),
Some(t) if t == TypeId::of::<Span>() => ud.take::<Span>()?.0.into(),
Some(t) if t == TypeId::of::<Self>() => return ud.take(),
Some(t) if t == TypeId::of::<Error>() => ud.take::<Error>()?.into_string().into(),
_ => Err(EXPECTED.into_lua_err())?,
},
_ => Err(EXPECTED.into_lua_err())?,
};
Ok(Self { inner, ..Default::default() })
}
}
impl TryFrom<Table> for Text {
type Error = mlua::Error;
@ -102,6 +82,24 @@ impl From<Text> for ratatui::widgets::Paragraph<'static> {
}
}
impl FromLua for Text {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
let inner = match value {
Value::Table(tb) => return Self::try_from(tb),
Value::String(s) => s.to_string_lossy().into(),
Value::UserData(ud) => match ud.type_id() {
Some(t) if t == TypeId::of::<Line>() => ud.take::<Line>()?.inner.into(),
Some(t) if t == TypeId::of::<Span>() => ud.take::<Span>()?.0.into(),
Some(t) if t == TypeId::of::<Self>() => return ud.take(),
Some(t) if t == TypeId::of::<Error>() => ud.take::<Error>()?.into_string().into(),
_ => Err(EXPECTED.into_lua_err())?,
},
_ => Err(EXPECTED.into_lua_err())?,
};
Ok(Self { inner, ..Default::default() })
}
}
impl UserData for Text {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
crate::impl_area_method!(methods);

View file

@ -1,7 +1,6 @@
use std::ops::Deref;
use mlua::{AnyUserData, ExternalError, Lua, ObjectLike, Table, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use yazi_codegen::FromLuaOwned;
use mlua::{AnyUserData, ExternalError, FromLua, Lua, ObjectLike, Table, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use crate::{Cha, Url, impl_file_fields, impl_file_methods};
@ -9,7 +8,7 @@ pub type FileRef = UserDataRef<File>;
const EXPECTED: &str = "expected a table, File, or fs::File";
#[derive(Clone, FromLuaOwned)]
#[derive(Clone)]
pub struct File {
inner: yazi_fs::File,
@ -47,19 +46,7 @@ impl File {
}
pub fn install(lua: &Lua) -> mlua::Result<()> {
lua.globals().raw_set("File", lua.create_function(|_, value: Value| Self::try_from(value))?)
}
}
impl TryFrom<Value> for File {
type Error = mlua::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Table(tbl) => Self::try_from(tbl),
Value::UserData(ud) => Self::try_from(ud),
_ => Err(EXPECTED.into_lua_err())?,
}
lua.globals().raw_set("File", lua.create_function(|_, file: Self| Ok(file))?)
}
}
@ -79,7 +66,17 @@ impl TryFrom<AnyUserData> for File {
type Error = mlua::Error;
fn try_from(value: AnyUserData) -> Result<Self, Self::Error> {
Ok(if let Ok(me) = value.borrow::<Self>() { me.clone() } else { value.get("bare")? })
Ok(if let Ok(me) = value.take::<Self>() { me } else { value.get("bare")? })
}
}
impl FromLua for File {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
match value {
Value::Table(tbl) => Self::try_from(tbl),
Value::UserData(ud) => Self::try_from(ud),
_ => Err(EXPECTED.into_lua_err())?,
}
}
}

View file

@ -117,6 +117,7 @@ macro_rules! impl_style_method {
macro_rules! impl_style_shorthands {
($methods:ident, $($field:tt).+) => {
$methods.add_function_mut("fg", |lua, (ud, value): (mlua::AnyUserData, mlua::Value)| {
use mlua::FromLua;
use ratatui::style::Modifier;
let me = &mut ud.borrow_mut::<Self>()?.$($field).+;
@ -128,12 +129,13 @@ macro_rules! impl_style_shorthands {
me.fg.map($crate::Color).into_lua(lua)
}
_ => {
me.fg = Some($crate::Color::try_from(value)?.0);
me.fg = Some($crate::Color::from_lua(value, lua)?.0);
ud.into_lua(lua)
}
}
});
$methods.add_function_mut("bg", |lua, (ud, value): (mlua::AnyUserData, mlua::Value)| {
use mlua::FromLua;
use ratatui::style::Modifier;
let me = &mut ud.borrow_mut::<Self>()?.$($field).+;
@ -145,7 +147,7 @@ macro_rules! impl_style_shorthands {
me.bg.map($crate::Color).into_lua(lua)
}
_ => {
me.bg = Some($crate::Color::try_from(value)?.0);
me.bg = Some($crate::Color::from_lua(value, lua)?.0);
ud.into_lua(lua)
}
}

View file

@ -1,4 +1,4 @@
use mlua::{IntoLua, Lua};
use mlua::{IntoLua, Lua, Value};
pub struct Range<T>(std::ops::Range<T>);
@ -10,7 +10,7 @@ impl<T> IntoLua for Range<T>
where
T: IntoLua,
{
fn into_lua(self, lua: &Lua) -> mlua::Result<mlua::Value> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua.create_sequence_from([self.0.start, self.0.end])?.into_lua(lua)
}
}

View file

@ -32,7 +32,7 @@ yazi-shared = { path = "../yazi-shared", version = "26.2.2" }
# External dependencies
clap = { workspace = true }
clap_complete = "4.5.66"
clap_complete = "4.6.0"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.10"
clap_complete_nushell = "4.6.0"
vergen-gitcl = { version = "9.1.0", features = [ "build", "rustc" ] }

View file

@ -46,9 +46,9 @@ yazi-shared = { path = "../yazi-shared", version = "26.2.2" }
# External build dependencies
anyhow = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.66"
clap_complete = "4.6.0"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.10"
clap_complete_nushell = "4.6.0"
serde = { workspace = true }
serde_json = { workspace = true }
vergen-gitcl = { version = "9.1.0", features = [ "build" ] }

View file

@ -61,7 +61,7 @@ tokio = { workspace = true }
tokio-stream = { workspace = true }
tracing = { workspace = true }
tracing-appender = "0.2.4"
tracing-subscriber = { version = "0.3.22", features = [ "env-filter" ] }
tracing-subscriber = { version = "0.3.23", features = [ "env-filter" ] }
[target."cfg(unix)".dependencies]
libc = { workspace = true }

View file

@ -1,4 +1,4 @@
use mlua::{IntoLua, Lua, Table};
use mlua::{IntoLua, Lua, Table, Value};
use yazi_binding::{Cha, File, Id, Path, Url};
pub(super) struct FilesOp(yazi_fs::FilesOp);
@ -42,7 +42,7 @@ impl FilesOp {
}
impl IntoLua for FilesOp {
fn into_lua(self, lua: &Lua) -> mlua::Result<mlua::Value> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua.create_any_userdata(self.0)?.into_lua(lua)
}
}

View file

@ -56,7 +56,7 @@ impl Utils {
value: t.raw_get("value").unwrap_or_default(),
cursor: None, // TODO
obscure: t.raw_get("obscure")?,
position: Pos::new_input(t.raw_get("pos")?)?.into(),
position: t.raw_get::<Pos>("pos")?.with_height(3).into(),
realtime,
completion: false,
}));
@ -77,22 +77,15 @@ impl Utils {
}
pub(super) fn confirm(lua: &Lua) -> mlua::Result<Function> {
fn body(t: &Table) -> mlua::Result<ratatui::widgets::Paragraph<'static>> {
Ok(match t.raw_get::<Value>("body")? {
Value::Nil => Default::default(),
v => Text::try_from(v)?.into(),
})
}
lua.create_async_function(|lua, t: Table| async move {
if runtime!(lua)?.blocking {
return Err("Cannot call `ya.confirm()` while main thread is blocked".into_lua_err());
}
let result = ConfirmProxy::show(ConfirmCfg {
position: Pos::try_from(t.raw_get::<Value>("pos")?)?.into(),
title: Line::try_from(t.raw_get::<Value>("title")?)?.into(),
body: body(&t)?,
position: t.raw_get::<Pos>("pos")?.into(),
title: t.raw_get::<Line>("title")?.into(),
body: t.raw_get::<Option<Text>>("body")?.unwrap_or_default().into(),
list: Default::default(), // TODO
});

View file

@ -1,4 +1,4 @@
use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
use mlua::{ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
use yazi_binding::{Error, elements::{Area, Renderable, Text}};
use yazi_config::YAZI;
use yazi_fs::FsUrl;
@ -41,10 +41,7 @@ impl Utils {
let mut lock = PreviewLock::try_from(t)?;
lock.data = match value {
Value::Nil => vec![],
Value::Table(tbl) => tbl
.sequence_values::<AnyUserData>()
.map(|ud| ud.and_then(Renderable::try_from))
.collect::<mlua::Result<_>>()?,
Value::Table(tbl) => tbl.sequence_values::<Renderable>().collect::<mlua::Result<_>>()?,
Value::UserData(ud) => match Renderable::try_from(&ud) {
Ok(r) => vec![r],
Err(e) => {

View file

@ -36,9 +36,9 @@ impl Utils {
}
pub(super) fn spot_widgets(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|_, (t, widgets): (Table, Vec<AnyUserData>)| {
lua.create_function(|_, (t, widgets): (Table, Vec<Renderable>)| {
let mut lock = SpotLock::try_from(t)?;
lock.data = widgets.into_iter().map(Renderable::try_from).collect::<mlua::Result<_>>()?;
lock.data = widgets;
MgrProxy::update_spotted(UpdateSpottedOpt { lock });
Ok(())