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;
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 yazi_shared::Id;
#[derive(Default)]
pub struct Cmp {
pub(super) caches: HashMap<PathBuf, Vec<String>>,
@ -7,7 +9,7 @@ pub struct Cmp {
pub(super) offset: usize,
pub cursor: usize,
pub(super) ticket: usize,
pub(super) ticket: Id,
pub visible: bool,
}

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, mem, ops::ControlFlow, path::PathBuf};
use yazi_macro::render;
use yazi_shared::event::{Cmd, CmdCow, Data};
use yazi_shared::{Id, event::{Cmd, CmdCow, Data}};
use crate::cmp::Cmp;
@ -11,7 +11,7 @@ struct Opt {
cache: Vec<String>,
cache_name: PathBuf,
word: Cow<'static, str>,
ticket: usize,
ticket: Id,
}
impl From<CmdCow> for Opt {
@ -20,7 +20,7 @@ impl From<CmdCow> for Opt {
cache: c.take_any("cache").unwrap_or_default(),
cache_name: c.take_any("cache-name").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 yazi_fs::{CWD, expand_path};
use yazi_macro::{emit, render};
use yazi_shared::event::{Cmd, CmdCow, Data};
use yazi_shared::{Id, event::{Cmd, CmdCow, Data}};
use crate::cmp::Cmp;
struct Opt {
word: Cow<'static, str>,
ticket: usize,
ticket: Id,
}
impl From<CmdCow> for Opt {
fn from(mut c: CmdCow) -> Self {
Self {
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) => {
if let Ok(t) = ud.take::<yazi_binding::Url>() {
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>() {
Data::Any(Box::new(t))
} else if let Ok(t) = ud.take::<super::body::BodyYankIter>() {
@ -107,6 +109,7 @@ impl Sendable {
}
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::Bytes(b) => Value::String(lua.create_string(b)?),
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::Function(_) => Err("function is not supported".into_lua_err())?,
Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
Value::UserData(ud) => {
if let Ok(t) = ud.take::<yazi_binding::Url>() {
DataKey::Url(t.into())
} else {
Err("unsupported userdata included".into_lua_err())?
}
}
Value::UserData(_) => Err("userdata 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())?,
})
}
#[inline]
fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> {
Ok(match key {
DataKey::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?,
key => Self::key_to_value_ref(lua, &key)?,
})
Self::key_to_value_ref(lua, &key)
}
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::Number(n) => Value::Number(n.get()),
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 mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods, Value};
use yazi_binding::{UrlRef, cached_field};
use yazi_plugin::Id;
use yazi_binding::{Id, UrlRef, cached_field};
use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected};

View file

@ -1,7 +1,7 @@
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);

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_flat!(clipboard composer id lua runtime);
yazi_macro::mod_flat!(clipboard composer lua runtime);
pub fn init() -> anyhow::Result<()> {
CLIPBOARD.with(<_>::default);

View file

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

View file

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

View file

@ -1,7 +1,7 @@
use tokio::sync::mpsc;
use yazi_config::popup::InputCfg;
use yazi_macro::emit;
use yazi_shared::{errors::InputError, event::Cmd};
use yazi_shared::{Id, errors::InputError, event::Cmd};
pub struct InputProxy;
@ -14,7 +14,7 @@ impl InputProxy {
}
#[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)));
}
}

View file

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

View file

@ -46,15 +46,15 @@ impl Cmd {
// --- With
#[inline]
pub fn with(mut self, name: impl Into<DataKey>, value: impl ToString) -> Self {
self.args.insert(name.into(), Data::String(value.to_string()));
pub fn with(mut self, name: impl Into<DataKey>, value: impl Into<Data>) -> Self {
self.args.insert(name.into(), value.into());
self
}
#[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 {
self.args.insert(name.into(), Data::String(v.to_string()));
self.args.insert(name.into(), v.into());
}
self
}

View file

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

View file

@ -2,7 +2,9 @@ use std::{fmt::Display, str::FromStr, sync::atomic::{AtomicU64, Ordering}};
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);
impl Id {
@ -22,6 +24,14 @@ impl FromStr for Id {
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 {
type Error = <u64 as TryFrom<i64>>::Error;

View file

@ -1,7 +1,7 @@
use std::{borrow::Cow, path::MAIN_SEPARATOR_STR};
use yazi_macro::render;
use yazi_shared::event::{CmdCow, Data};
use yazi_shared::{Id, event::{CmdCow, Data}};
use crate::input::Input;
@ -13,14 +13,14 @@ const SEPARATOR: char = std::path::MAIN_SEPARATOR;
struct Opt {
word: Cow<'static, str>,
_ticket: usize, // FIXME: not used
_ticket: Id, // FIXME: not used
}
impl From<CmdCow> for Opt {
fn from(mut c: CmdCow) -> Self {
Self {
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(),
}
}
}