feat: promote Id to a first-class type (#2692)

This commit is contained in:
三咲雅 · Misaki Masa 2025-04-28 23:52:23 +08:00 committed by GitHub
parent 2c99075ffa
commit 54687181b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 61 additions and 42 deletions

View file

@ -1,3 +1,3 @@
mod macros; mod macros;
yazi_macro::mod_flat!(error stage url); yazi_macro::mod_flat!(error id stage url);

View file

@ -1,5 +1,7 @@
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use yazi_shared::Id;
#[derive(Default)] #[derive(Default)]
pub struct Cmp { pub struct Cmp {
pub(super) caches: HashMap<PathBuf, Vec<String>>, pub(super) caches: HashMap<PathBuf, Vec<String>>,
@ -7,7 +9,7 @@ pub struct Cmp {
pub(super) offset: usize, pub(super) offset: usize,
pub cursor: usize, pub cursor: usize,
pub(super) ticket: usize, pub(super) ticket: Id,
pub visible: bool, pub visible: bool,
} }

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, mem, ops::ControlFlow, path::PathBuf}; use std::{borrow::Cow, mem, ops::ControlFlow, path::PathBuf};
use yazi_macro::render; use yazi_macro::render;
use yazi_shared::event::{Cmd, CmdCow, Data}; use yazi_shared::{Id, event::{Cmd, CmdCow, Data}};
use crate::cmp::Cmp; use crate::cmp::Cmp;
@ -11,7 +11,7 @@ struct Opt {
cache: Vec<String>, cache: Vec<String>,
cache_name: PathBuf, cache_name: PathBuf,
word: Cow<'static, str>, word: Cow<'static, str>,
ticket: usize, ticket: Id,
} }
impl From<CmdCow> for Opt { impl From<CmdCow> for Opt {
@ -20,7 +20,7 @@ impl From<CmdCow> for Opt {
cache: c.take_any("cache").unwrap_or_default(), cache: c.take_any("cache").unwrap_or_default(),
cache_name: c.take_any("cache-name").unwrap_or_default(), cache_name: c.take_any("cache-name").unwrap_or_default(),
word: c.take_str("word").unwrap_or_default(), word: c.take_str("word").unwrap_or_default(),
ticket: c.get("ticket").and_then(Data::as_usize).unwrap_or(0), ticket: c.get("ticket").and_then(Data::as_id).unwrap_or_default(),
} }
} }
} }

View file

@ -3,20 +3,20 @@ use std::{borrow::Cow, mem, path::{MAIN_SEPARATOR_STR, PathBuf}};
use tokio::fs; use tokio::fs;
use yazi_fs::{CWD, expand_path}; use yazi_fs::{CWD, expand_path};
use yazi_macro::{emit, render}; use yazi_macro::{emit, render};
use yazi_shared::event::{Cmd, CmdCow, Data}; use yazi_shared::{Id, event::{Cmd, CmdCow, Data}};
use crate::cmp::Cmp; use crate::cmp::Cmp;
struct Opt { struct Opt {
word: Cow<'static, str>, word: Cow<'static, str>,
ticket: usize, ticket: Id,
} }
impl From<CmdCow> for Opt { impl From<CmdCow> for Opt {
fn from(mut c: CmdCow) -> Self { fn from(mut c: CmdCow) -> Self {
Self { Self {
word: c.take_first_str().unwrap_or_default(), word: c.take_first_str().unwrap_or_default(),
ticket: c.get("ticket").and_then(Data::as_usize).unwrap_or(0), ticket: c.get("ticket").and_then(Data::as_id).unwrap_or_default(),
} }
} }
} }

View file

@ -43,6 +43,8 @@ impl Sendable {
Value::UserData(ud) => { Value::UserData(ud) => {
if let Ok(t) = ud.take::<yazi_binding::Url>() { if let Ok(t) = ud.take::<yazi_binding::Url>() {
Data::Url(t.into()) Data::Url(t.into())
} else if let Ok(t) = ud.borrow::<yazi_binding::Id>() {
Data::Id(**t)
} else if let Ok(t) = ud.take::<yazi_fs::FilesOp>() { } else if let Ok(t) = ud.take::<yazi_fs::FilesOp>() {
Data::Any(Box::new(t)) Data::Any(Box::new(t))
} else if let Ok(t) = ud.take::<super::body::BodyYankIter>() { } else if let Ok(t) = ud.take::<super::body::BodyYankIter>() {
@ -107,6 +109,7 @@ impl Sendable {
} }
Value::Table(tbl) Value::Table(tbl)
} }
Data::Id(i) => yazi_binding::Id(*i).into_lua(lua)?,
Data::Url(u) => yazi_binding::Url::new(u.clone()).into_lua(lua)?, Data::Url(u) => yazi_binding::Url::new(u.clone()).into_lua(lua)?,
Data::Bytes(b) => Value::String(lua.create_string(b)?), Data::Bytes(b) => Value::String(lua.create_string(b)?),
Data::Any(a) => Value::UserData(if let Some(t) = a.downcast_ref::<yazi_fs::FilesOp>() { Data::Any(a) => Value::UserData(if let Some(t) = a.downcast_ref::<yazi_fs::FilesOp>() {
@ -188,23 +191,15 @@ impl Sendable {
Value::Table(_) => Err("table is not supported".into_lua_err())?, Value::Table(_) => Err("table is not supported".into_lua_err())?,
Value::Function(_) => Err("function is not supported".into_lua_err())?, Value::Function(_) => Err("function is not supported".into_lua_err())?,
Value::Thread(_) => Err("thread is not supported".into_lua_err())?, Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
Value::UserData(ud) => { Value::UserData(_) => Err("userdata is not supported".into_lua_err())?,
if let Ok(t) = ud.take::<yazi_binding::Url>() {
DataKey::Url(t.into())
} else {
Err("unsupported userdata included".into_lua_err())?
}
}
Value::Error(_) => Err("error is not supported".into_lua_err())?, Value::Error(_) => Err("error is not supported".into_lua_err())?,
Value::Other(..) => Err("unknown data is not supported".into_lua_err())?, Value::Other(..) => Err("unknown data is not supported".into_lua_err())?,
}) })
} }
#[inline]
fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> { fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> {
Ok(match key { Self::key_to_value_ref(lua, &key)
DataKey::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?,
key => Self::key_to_value_ref(lua, &key)?,
})
} }
fn key_to_value_ref(lua: &Lua, key: &DataKey) -> mlua::Result<Value> { fn key_to_value_ref(lua: &Lua, key: &DataKey) -> mlua::Result<Value> {
@ -214,7 +209,6 @@ impl Sendable {
DataKey::Integer(i) => Value::Integer(*i), DataKey::Integer(i) => Value::Integer(*i),
DataKey::Number(n) => Value::Number(n.get()), DataKey::Number(n) => Value::Number(n.get()),
DataKey::String(s) => Value::String(lua.create_string(s.as_ref())?), DataKey::String(s) => Value::String(lua.create_string(s.as_ref())?),
DataKey::Url(u) => yazi_binding::Url::new(u.clone()).into_lua(lua)?,
}) })
} }
} }

View file

@ -1,8 +1,7 @@
use std::ops::Deref; use std::ops::Deref;
use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods, Value}; use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods, Value};
use yazi_binding::{UrlRef, cached_field}; use yazi_binding::{Id, UrlRef, cached_field};
use yazi_plugin::Id;
use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected}; use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected};

View file

@ -1,7 +1,7 @@
use mlua::{IntoLua, Lua, Table}; use mlua::{IntoLua, Lua, Table};
use yazi_binding::Url; use yazi_binding::{Id, Url};
use crate::{Id, bindings::Cha, file::File}; use crate::{bindings::Cha, file::File};
pub(super) struct FilesOp(yazi_fs::FilesOp); pub(super) struct FilesOp(yazi_fs::FilesOp);

View file

@ -4,7 +4,7 @@ mod macros;
yazi_macro::mod_pub!(bindings config elements external file fs isolate loader process pubsub utils); yazi_macro::mod_pub!(bindings config elements external file fs isolate loader process pubsub utils);
yazi_macro::mod_flat!(clipboard composer id lua runtime); yazi_macro::mod_flat!(clipboard composer lua runtime);
pub fn init() -> anyhow::Result<()> { pub fn init() -> anyhow::Result<()> {
CLIPBOARD.with(<_>::default); CLIPBOARD.with(<_>::default);

View file

@ -1,7 +1,8 @@
use mlua::{ExternalResult, Function, Lua, Value}; use mlua::{ExternalResult, Function, Lua, Value};
use yazi_binding::Id;
use yazi_dds::body::Body; use yazi_dds::body::Body;
use crate::{Id, runtime::RtRef}; use crate::runtime::RtRef;
pub struct Pubsub; pub struct Pubsub;

View file

@ -1,8 +1,9 @@
use mlua::{AnyUserData, ExternalError, Function, Lua}; use mlua::{AnyUserData, ExternalError, Function, Lua};
use yazi_binding::Id;
use yazi_proxy::{AppProxy, HIDER}; use yazi_proxy::{AppProxy, HIDER};
use super::Utils; use super::Utils;
use crate::{Id, bindings::{Permit, PermitRef}}; use crate::bindings::{Permit, PermitRef};
impl Utils { impl Utils {
pub(super) fn id(lua: &Lua) -> mlua::Result<Function> { pub(super) fn id(lua: &Lua) -> mlua::Result<Function> {

View file

@ -1,7 +1,7 @@
use tokio::sync::mpsc; use tokio::sync::mpsc;
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_macro::emit; use yazi_macro::emit;
use yazi_shared::{errors::InputError, event::Cmd}; use yazi_shared::{Id, errors::InputError, event::Cmd};
pub struct InputProxy; pub struct InputProxy;
@ -14,7 +14,7 @@ impl InputProxy {
} }
#[inline] #[inline]
pub fn complete(word: &str, ticket: usize) { pub fn complete(word: &str, ticket: Id) {
emit!(Call(Cmd::args("input:complete", &[word]).with("ticket", ticket))); emit!(Call(Cmd::args("input:complete", &[word]).with("ticket", ticket)));
} }
} }

View file

@ -26,8 +26,8 @@ impl TabProxy {
emit!(Call( emit!(Call(
// TODO: use second positional argument instead of `args` parameter // TODO: use second positional argument instead of `args` parameter
Cmd::args("mgr:search_do", &[opt.subject]) Cmd::args("mgr:search_do", &[opt.subject])
.with("via", opt.via.as_ref()) .with("via", opt.via.as_ref().to_owned())
.with("args", opt.args_raw) .with("args", opt.args_raw.into_owned())
)); ));
} }
} }

View file

@ -46,15 +46,15 @@ impl Cmd {
// --- With // --- With
#[inline] #[inline]
pub fn with(mut self, name: impl Into<DataKey>, value: impl ToString) -> Self { pub fn with(mut self, name: impl Into<DataKey>, value: impl Into<Data>) -> Self {
self.args.insert(name.into(), Data::String(value.to_string())); self.args.insert(name.into(), value.into());
self self
} }
#[inline] #[inline]
pub fn with_opt(mut self, name: impl Into<DataKey>, value: Option<impl ToString>) -> Self { pub fn with_opt(mut self, name: impl Into<DataKey>, value: Option<impl Into<Data>>) -> Self {
if let Some(v) = value { if let Some(v) = value {
self.args.insert(name.into(), Data::String(v.to_string())); self.args.insert(name.into(), v.into());
} }
self self
} }

View file

@ -2,7 +2,7 @@ use std::{any::Any, borrow::Cow, collections::HashMap};
use serde::{Deserialize, Serialize, de}; use serde::{Deserialize, Serialize, de};
use crate::{OrderedFloat, url::Url}; use crate::{Id, OrderedFloat, url::Url};
// --- Data // --- Data
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -15,6 +15,7 @@ pub enum Data {
String(String), String(String),
List(Vec<Data>), List(Vec<Data>),
Dict(HashMap<DataKey, Data>), Dict(HashMap<DataKey, Data>),
Id(Id),
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
Url(Url), Url(Url),
#[serde(skip)] #[serde(skip)]
@ -83,6 +84,18 @@ impl Data {
} }
} }
impl From<usize> for Data {
fn from(value: usize) -> Self { Self::Id(value.into()) }
}
impl From<String> for Data {
fn from(value: String) -> Self { Self::String(value) }
}
impl From<Id> for Data {
fn from(value: Id) -> Self { Self::Id(value) }
}
// --- Key // --- Key
#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
@ -93,8 +106,6 @@ pub enum DataKey {
Integer(i64), Integer(i64),
Number(OrderedFloat), Number(OrderedFloat),
String(Cow<'static, str>), String(Cow<'static, str>),
#[serde(skip_deserializing)]
Url(Url),
} }
impl DataKey { impl DataKey {
@ -157,6 +168,7 @@ macro_rules! impl_integer_as {
match self { match self {
Data::Integer(i) => <$t>::try_from(*i).ok(), Data::Integer(i) => <$t>::try_from(*i).ok(),
Data::String(s) => s.parse().ok(), Data::String(s) => s.parse().ok(),
Data::Id(i) => <$t>::try_from(i.get()).ok(),
_ => None, _ => None,
} }
} }

View file

@ -2,7 +2,9 @@ use std::{fmt::Display, str::FromStr, sync::atomic::{AtomicU64, Ordering}};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Copy, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize,
)]
pub struct Id(pub u64); pub struct Id(pub u64);
impl Id { impl Id {
@ -22,6 +24,14 @@ impl FromStr for Id {
fn from_str(s: &str) -> Result<Self, Self::Err> { s.parse().map(Self) } fn from_str(s: &str) -> Result<Self, Self::Err> { s.parse().map(Self) }
} }
impl From<u64> for Id {
fn from(value: u64) -> Self { Self(value) }
}
impl From<usize> for Id {
fn from(value: usize) -> Self { Self(value as u64) }
}
impl TryFrom<i64> for Id { impl TryFrom<i64> for Id {
type Error = <u64 as TryFrom<i64>>::Error; type Error = <u64 as TryFrom<i64>>::Error;

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, path::MAIN_SEPARATOR_STR}; use std::{borrow::Cow, path::MAIN_SEPARATOR_STR};
use yazi_macro::render; use yazi_macro::render;
use yazi_shared::event::{CmdCow, Data}; use yazi_shared::{Id, event::{CmdCow, Data}};
use crate::input::Input; use crate::input::Input;
@ -13,14 +13,14 @@ const SEPARATOR: char = std::path::MAIN_SEPARATOR;
struct Opt { struct Opt {
word: Cow<'static, str>, word: Cow<'static, str>,
_ticket: usize, // FIXME: not used _ticket: Id, // FIXME: not used
} }
impl From<CmdCow> for Opt { impl From<CmdCow> for Opt {
fn from(mut c: CmdCow) -> Self { fn from(mut c: CmdCow) -> Self {
Self { Self {
word: c.take_first_str().unwrap_or_default(), word: c.take_first_str().unwrap_or_default(),
_ticket: c.get("ticket").and_then(Data::as_usize).unwrap_or(0), _ticket: c.get("ticket").and_then(Data::as_id).unwrap_or_default(),
} }
} }
} }