refactor: make command data cloneable (#3613)

This commit is contained in:
三咲雅 misaki masa 2026-01-26 07:36:35 +08:00 committed by GitHub
parent face6aed40
commit 92880b844b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
81 changed files with 297 additions and 203 deletions

8
Cargo.lock generated
View file

@ -1242,6 +1242,12 @@ dependencies = [
"litrs",
]
[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "ecdsa"
version = "0.16.9"
@ -5726,6 +5732,7 @@ dependencies = [
"anyhow",
"bitflags 2.10.0",
"crossterm 0.29.0",
"dyn-clone",
"hashbrown",
"mlua",
"ordered-float 5.1.0",
@ -5844,6 +5851,7 @@ version = "26.1.22"
dependencies = [
"anyhow",
"crossterm 0.29.0",
"dyn-clone",
"foldhash",
"futures",
"hashbrown",

View file

@ -34,6 +34,7 @@ clap = { version = "4.5.54", features = [ "derive" ] }
core-foundation-sys = "0.8.7"
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
dirs = "6.0.0"
dyn-clone = "1.0.20"
foldhash = "0.2.0"
futures = "0.3.31"
globset = "0.4.18"

View file

@ -13,10 +13,7 @@ impl Actor for Close {
const NAME: &str = "close";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
if let Some(cb) = cx.confirm.callback.take() {
_ = cb.send(opt.submit);
}
cx.confirm.token.complete(opt.submit);
cx.confirm.visible = false;
succ!(render!());
}

View file

@ -23,7 +23,7 @@ impl Actor for Show {
confirm.position = opt.cfg.position;
confirm.offset = 0;
confirm.callback = Some(opt.tx);
confirm.token = opt.token;
confirm.visible = true;
succ!(render!());

View file

@ -13,6 +13,7 @@ pub(super) struct Core {
c_tasks: Option<Value>,
c_yanked: Option<Value>,
c_layer: Option<Value>,
c_which: Option<Value>,
}
impl Deref for Core {
@ -31,6 +32,7 @@ impl Core {
c_tasks: None,
c_yanked: None,
c_layer: None,
c_which: None,
})
}
}
@ -58,6 +60,7 @@ impl UserData for Core {
b"layer" => {
reuse!(layer, Ok::<_, mlua::Error>(yazi_plugin::bindings::Layer::from(me.layer())))
}
b"which" => reuse!(which, super::Which::make(&me.which)),
_ => Value::Nil,
})
});

View file

@ -1 +1 @@
yazi_macro::mod_flat!(core file files filter finder folder lives mode preference preview ptr selected tab tabs task tasks yanked);
yazi_macro::mod_flat!(core file files filter finder folder lives mode preference preview ptr selected tab tabs task tasks which yanked);

View file

@ -0,0 +1,25 @@
use std::ops::Deref;
use mlua::{AnyUserData, UserData, UserDataFields};
use super::{Lives, PtrCell};
pub(super) struct Which {
inner: PtrCell<yazi_core::which::Which>,
}
impl Deref for Which {
type Target = yazi_core::which::Which;
fn deref(&self) -> &Self::Target { &self.inner }
}
impl Which {
pub(super) fn make(inner: &yazi_core::which::Which) -> mlua::Result<AnyUserData> {
Lives::scoped_userdata(Self { inner: inner.into() })
}
}
impl UserData for Which {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {}
}

View file

@ -22,7 +22,10 @@ impl Actor for Displace {
let tab = cx.tab().id;
let from = cx.cwd().to_owned();
tokio::spawn(async move {
MgrProxy::displace_do(tab, DisplaceDoOpt { to: provider::canonicalize(&from).await, from });
MgrProxy::displace_do(tab, DisplaceDoOpt {
to: provider::canonicalize(&from).await.map_err(Into::into),
from,
});
});
succ!();

View file

@ -20,7 +20,7 @@ impl Actor for DisplaceDo {
let to = match opt.to {
Ok(url) => url,
Err(e) => return act!(mgr:update_files, cx, FilesOp::IOErr(opt.from, e.into())),
Err(e) => return act!(mgr:update_files, cx, FilesOp::IOErr(opt.from, e)),
};
if !to.is_absolute() {

View file

@ -41,7 +41,7 @@ impl Actor for OpenDo {
let urls: Vec<_> =
[UrlCow::default()].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect();
tokio::spawn(async move {
if let Ok(choice) = pick.await {
if let Some(choice) = pick.await {
TasksProxy::open_shell_compat(ProcessOpenOpt {
cwd: opt.cwd,
cmd: openers[choice].run.clone().into(),

View file

@ -33,7 +33,7 @@ impl Actor for Quit {
tokio::spawn(async move {
let mut i = 0;
let mut rx = ConfirmProxy::show_rx(ConfirmCfg::quit(left, left_names));
let token = ConfirmProxy::show_sync(ConfirmCfg::quit(left, left_names));
loop {
select! {
_ = time::sleep(Duration::from_millis(50)) => {
@ -44,8 +44,8 @@ impl Actor for Quit {
return;
}
}
b = &mut rx => {
if b.unwrap_or(false) {
b = token.future() => {
if b {
emit!(Quit(event));
}
return;
@ -53,7 +53,7 @@ impl Actor for Quit {
}
}
if rx.await.unwrap_or(false) {
if token.future().await {
emit!(Quit(event));
}
});

View file

@ -1,4 +1,4 @@
use anyhow::{Result, anyhow};
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::pick::CloseOpt;
use yazi_shared::data::Data;
@ -15,7 +15,7 @@ impl Actor for Close {
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let pick = &mut cx.pick;
if let Some(cb) = pick.callback.take() {
_ = cb.send(if opt.submit { Ok(pick.cursor) } else { Err(anyhow!("canceled")) });
_ = cb.send(if opt.submit { Some(pick.cursor) } else { None });
}
pick.cursor = 0;

View file

@ -13,7 +13,7 @@ impl Actor for Callback {
const NAME: &str = "callback";
fn act(_: &mut Ctx, opt: Self::Options) -> Result<Data> {
opt.tx.try_send(opt.idx)?;
opt.tx.send(opt.idx)?;
succ!();
}
}

View file

@ -9,7 +9,7 @@ use super::Key;
static RE: OnceLock<Regex> = OnceLock::new();
#[derive(Debug, Default, Deserialize)]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct Chord {
#[serde(deserialize_with = "super::deserialize_on")]
pub on: Vec<Key>,

View file

@ -4,7 +4,7 @@ use yazi_shared::event::CmdCow;
use super::Chord;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum ChordCow {
Owned(Chord),
Borrowed(&'static Chord),

View file

@ -4,7 +4,7 @@ use yazi_shared::{scheme::Encode as EncodeScheme, strand::ToStrand, url::{Url, U
use super::{Offset, Position};
use crate::YAZI;
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct InputCfg {
pub title: String,
pub value: String,
@ -15,14 +15,14 @@ pub struct InputCfg {
pub completion: bool,
}
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct PickCfg {
pub title: String,
pub items: Vec<String>,
pub position: Position,
}
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct ConfirmCfg {
pub position: Position,
pub title: Line<'static>,

View file

@ -1,6 +1,6 @@
use ratatui::{text::Line, widgets::Paragraph};
use tokio::sync::oneshot::Sender;
use yazi_config::popup::Position;
use yazi_shared::CompletionToken;
#[derive(Default)]
pub struct Confirm {
@ -11,6 +11,6 @@ pub struct Confirm {
pub position: Position,
pub offset: usize,
pub callback: Option<Sender<bool>>,
pub visible: bool,
pub token: CompletionToken,
pub visible: bool,
}

View file

@ -1,5 +1,4 @@
use anyhow::Result;
use tokio::sync::oneshot::Sender;
use tokio::sync::mpsc::UnboundedSender;
use yazi_config::{YAZI, popup::Position};
use yazi_widgets::Scrollable;
@ -11,7 +10,7 @@ pub struct Pick {
pub offset: usize,
pub cursor: usize,
pub callback: Option<Sender<Result<usize>>>,
pub callback: Option<UnboundedSender<Option<usize>>>,
pub visible: bool,
}

View file

@ -24,7 +24,7 @@ pub struct Client {
pub(super) abilities: HashSet<String>,
}
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Peer {
pub(super) abilities: HashSet<String>,
}

View file

@ -5,7 +5,7 @@ use yazi_shared::url::{Url, UrlCow};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberBulk<'a> {
pub changes: HashMap<UrlCow<'a>, UrlCow<'a>>,
}

View file

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberBye;
impl EmberBye {

View file

@ -6,7 +6,7 @@ use yazi_shared::{Id, url::UrlBuf};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberCd<'a> {
pub tab: Id,
pub url: Cow<'a, UrlBuf>,

View file

@ -5,7 +5,7 @@ use yazi_shared::data::Data;
use super::Ember;
use crate::Sendable;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct EmberCustom {
pub kind: String,
pub data: Data,

View file

@ -6,7 +6,7 @@ use yazi_shared::url::UrlBuf;
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberDelete<'a> {
pub urls: Cow<'a, Vec<UrlBuf>>,
}

View file

@ -6,7 +6,7 @@ use yazi_shared::url::UrlBuf;
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberDuplicate<'a> {
pub items: Cow<'a, Vec<BodyDuplicateItem>>,
}

View file

@ -5,7 +5,7 @@ use yazi_shared::Id;
use super::{EmberBulk, EmberBye, EmberCd, EmberCustom, EmberDelete, EmberDuplicate, EmberHey, EmberHi, EmberHover, EmberLoad, EmberMount, EmberMove, EmberRename, EmberTab, EmberTrash, EmberYank};
use crate::Payload;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum Ember<'a> {
Hi(EmberHi<'a>),
Hey(EmberHey),

View file

@ -7,7 +7,7 @@ use super::{Ember, EmberHi};
use crate::Peer;
/// Server handshake
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberHey {
pub peers: HashMap<Id, Peer>,
pub version: SStr,

View file

@ -8,7 +8,7 @@ use yazi_shared::SStr;
use super::Ember;
/// Client handshake
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberHi<'a> {
/// Kinds of events the client can handle
pub abilities: HashSet<Cow<'a, str>>,

View file

@ -6,7 +6,7 @@ use yazi_shared::{Id, url::UrlBuf};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberHover<'a> {
pub tab: Id,
pub url: Option<Cow<'a, UrlBuf>>,

View file

@ -7,7 +7,7 @@ use yazi_shared::{Id, url::UrlBuf};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberLoad<'a> {
pub tab: Id,
pub url: Cow<'a, UrlBuf>,

View file

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberMount;
impl EmberMount {

View file

@ -6,7 +6,7 @@ use yazi_shared::url::UrlBuf;
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberMove<'a> {
pub items: Cow<'a, Vec<BodyMoveItem>>,
}

View file

@ -6,7 +6,7 @@ use yazi_shared::{Id, url::UrlBuf};
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberRename<'a> {
pub tab: Id,
pub from: Cow<'a, UrlBuf>,

View file

@ -4,7 +4,7 @@ use yazi_shared::Id;
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberTab {
pub id: Id,
}

View file

@ -6,7 +6,7 @@ use yazi_shared::url::UrlBuf;
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberTrash<'a> {
pub urls: Cow<'a, Vec<UrlBuf>>,
}

View file

@ -8,7 +8,7 @@ use yazi_shared::url::UrlBufCov;
use super::Ember;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberYank<'a>(UpdateYankedOpt<'a>);
impl<'a> EmberYank<'a> {

View file

@ -7,7 +7,7 @@ use yazi_shared::Id;
use crate::{ID, ember::Ember};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Payload<'a> {
pub receiver: Id,
pub sender: Id,

View file

@ -84,14 +84,21 @@ impl Sendable {
}
Data::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?,
Data::Path(u) => yazi_binding::Path::new(u).into_lua(lua)?,
Data::Any(a) => {
if a.is::<yazi_fs::FilesOp>() {
lua.create_any_userdata(*a.downcast::<yazi_fs::FilesOp>().unwrap())?.into_lua(lua)?
} else if a.is::<yazi_parser::mgr::UpdateYankedOpt>() {
a.downcast::<yazi_parser::mgr::UpdateYankedOpt>().unwrap().into_lua(lua)?
} else {
Err("unsupported Data::Any included".into_lua_err())?
Data::Any(b) => {
let mut b = b.into_any();
macro_rules! try_cast {
($f:expr) => {
match b.downcast() {
Ok(v) => return $f(*v)?.into_lua(lua),
#[allow(unused_assignments)]
Err(e) => b = e,
}
};
}
try_cast!(|v: yazi_fs::FilesOp| lua.create_any_userdata(v));
try_cast!(|v: yazi_parser::mgr::UpdateYankedOpt| v.into_lua(lua));
Err("unsupported DataAny included".into_lua_err())?
}
data => Self::data_to_value_ref(lua, &data)?,
})
@ -124,12 +131,12 @@ impl Sendable {
Data::Path(u) => yazi_binding::Path::new(u).into_lua(lua)?,
Data::Bytes(b) => Value::String(lua.create_string(b)?),
Data::Any(a) => {
if let Some(t) = a.downcast_ref::<yazi_fs::FilesOp>() {
if let Some(t) = a.as_any().downcast_ref::<yazi_fs::FilesOp>() {
lua.create_any_userdata(t.clone())?.into_lua(lua)?
} else if let Some(t) = a.downcast_ref::<yazi_parser::mgr::UpdateYankedOpt>() {
} else if let Some(t) = a.as_any().downcast_ref::<yazi_parser::mgr::UpdateYankedOpt>() {
t.clone().into_lua(lua)?
} else {
Err("unsupported Data::Any included".into_lua_err())?
Err("unsupported DataAny included".into_lua_err())?
}
}
})

View file

@ -60,7 +60,7 @@ impl App {
drop(loader);
let result = Lives::scope(&self.core, || {
if let Some(cb) = opt.cb {
if let Some(cb) = opt.callback {
cb(&LUA, plugin)
} else {
let job = LUA.create_table_from([("args", Sendable::args_to_table(&LUA, opt.args)?)])?;

View file

@ -1,12 +1,12 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_parser::app::ResumeOpt;
use yazi_shared::data::Data;
use crate::{Term, app::App};
impl App {
pub(crate) fn resume(&mut self, _: VoidOpt) -> Result<Data> {
pub(crate) fn resume(&mut self, opt: ResumeOpt) -> Result<Data> {
self.core.active_mut().preview.reset();
self.term = Some(Term::start().unwrap());
@ -14,7 +14,7 @@ impl App {
// We need to trigger a resize, and render the UI based on the resized area.
act!(resize, self)?;
self.signals.resume(None);
self.signals.resume(opt.token);
succ!(render!());
}

View file

@ -14,7 +14,7 @@ impl App {
// while the app is being suspended.
self.term = None;
self.signals.stop(opt.tx);
self.signals.stop(opt.token);
succ!();
}

View file

@ -1,12 +1,12 @@
use anyhow::Result;
use crossterm::event::{Event as CrosstermEvent, EventStream, KeyEvent, KeyEventKind};
use futures::StreamExt;
use tokio::{select, sync::{mpsc, oneshot}};
use tokio::{select, sync::mpsc};
use yazi_config::YAZI;
use yazi_shared::event::Event;
use yazi_shared::{CompletionToken, event::Event};
pub(super) struct Signals {
tx: mpsc::UnboundedSender<(bool, Option<oneshot::Sender<()>>)>,
tx: mpsc::UnboundedSender<(bool, CompletionToken)>,
}
impl Signals {
@ -17,11 +17,9 @@ impl Signals {
Ok(Self { tx })
}
pub(super) fn stop(&mut self, cb: Option<oneshot::Sender<()>>) { self.tx.send((false, cb)).ok(); }
pub(super) fn stop(&mut self, token: CompletionToken) { self.tx.send((false, token)).ok(); }
pub(super) fn resume(&mut self, cb: Option<oneshot::Sender<()>>) {
self.tx.send((true, cb)).ok();
}
pub(super) fn resume(&mut self, token: CompletionToken) { self.tx.send((true, token)).ok(); }
#[cfg(unix)]
fn handle_sys(n: libc::c_int) -> bool {
@ -71,7 +69,7 @@ impl Signals {
}
}
fn spawn(mut rx: mpsc::UnboundedReceiver<(bool, Option<oneshot::Sender<()>>)>) -> Result<()> {
fn spawn(mut rx: mpsc::UnboundedReceiver<(bool, CompletionToken)>) -> Result<()> {
#[cfg(unix)]
use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP};
@ -96,9 +94,9 @@ impl Signals {
if let Some(t) = &mut term {
select! {
biased;
Some((state, mut callback)) = rx.recv() => {
Some((state, token)) = rx.recv() => {
term = term.filter(|_| state);
callback.take().map(|cb| cb.send(()));
token.complete(true);
},
Some(n) = sys.next() => if !Self::handle_sys(n) { return },
Some(Ok(e)) = t.next() => Self::handle_term(e)
@ -106,9 +104,9 @@ impl Signals {
} else {
select! {
biased;
Some((state, mut callback)) = rx.recv() => {
Some((state, token)) = rx.recv() => {
term = state.then(EventStream::new);
callback.take().map(|cb| cb.send(()));
token.complete(true);
},
Some(n) = sys.next() => if !Self::handle_sys(n) { return },
}

View file

@ -28,6 +28,7 @@ yazi-vfs = { path = "../yazi-vfs", version = "26.1.22" }
anyhow = { workspace = true }
bitflags = { workspace = true }
crossterm = { workspace = true }
dyn-clone = { workspace = true }
hashbrown = { workspace = true }
mlua = { workspace = true }
ordered-float = { workspace = true }

View file

@ -6,6 +6,7 @@ use serde::Deserialize;
use yazi_config::{Style, THEME};
use yazi_shared::event::CmdCow;
#[derive(Clone)]
pub struct NotifyOpt {
pub title: String,
pub content: String,

View file

@ -1,19 +1,18 @@
use std::{borrow::Cow, fmt::Debug, str::FromStr};
use std::{borrow::Cow, fmt::{self, Debug}, str::FromStr};
use anyhow::bail;
use dyn_clone::DynClone;
use hashbrown::HashMap;
use mlua::{Lua, Table};
use serde::Deserialize;
use yazi_shared::{SStr, data::{Data, DataKey}, event::{Cmd, CmdCow}};
pub type PluginCallback = Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send + Sync>;
#[derive(Default)]
#[derive(Clone, Debug, Default)]
pub struct PluginOpt {
pub id: SStr,
pub args: HashMap<DataKey, Data>,
pub mode: PluginMode,
pub cb: Option<PluginCallback>,
pub id: SStr,
pub args: HashMap<DataKey, Data>,
pub mode: PluginMode,
pub callback: Option<Box<dyn PluginCallback>>,
}
impl TryFrom<CmdCow> for PluginOpt {
@ -36,27 +35,16 @@ impl TryFrom<CmdCow> for PluginOpt {
};
let mode = c.str("mode").parse().unwrap_or_default();
Ok(Self { id: Self::normalize_id(id), args, mode, cb: c.take_any("callback") })
}
}
impl Debug for PluginOpt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginOpt")
.field("id", &self.id)
.field("args", &self.args)
.field("mode", &self.mode)
.field("cb", &self.cb.is_some())
.finish()
Ok(Self { id: Self::normalize_id(id), args, mode, callback: c.take_any("callback") })
}
}
impl PluginOpt {
pub fn new_callback(id: impl Into<SStr>, cb: PluginCallback) -> Self {
pub fn new_callback(id: impl Into<SStr>, f: impl PluginCallback) -> Self {
Self {
id: Self::normalize_id(id.into()),
mode: PluginMode::Sync,
cb: Some(cb),
callback: Some(Box::new(f)),
..Default::default()
}
}
@ -98,3 +86,24 @@ impl PluginMode {
if sync { Self::Sync } else { Self::Async }
}
}
// --- Callback
pub trait PluginCallback:
FnOnce(&Lua, Table) -> mlua::Result<()> + Send + Sync + DynClone + 'static
{
}
impl<T> PluginCallback for T where
T: FnOnce(&Lua, Table) -> mlua::Result<()> + Send + Sync + DynClone + 'static
{
}
impl Clone for Box<dyn PluginCallback> {
fn clone(&self) -> Self { dyn_clone::clone_box(&**self) }
}
impl fmt::Debug for dyn PluginCallback {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PluginCallback").finish_non_exhaustive()
}
}

View file

@ -1,10 +1,18 @@
use tokio::sync::oneshot;
use yazi_shared::event::CmdCow;
use anyhow::bail;
use yazi_shared::{CompletionToken, event::CmdCow};
pub struct ResumeOpt {
pub tx: Option<oneshot::Sender<()>>,
pub token: CompletionToken,
}
impl From<CmdCow> for ResumeOpt {
fn from(mut c: CmdCow) -> Self { Self { tx: c.take_any("tx") } }
impl TryFrom<CmdCow> for ResumeOpt {
type Error = anyhow::Error;
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(token) = c.take_any("token") else {
bail!("Invalid 'token' in ResumeOpt");
};
Ok(Self { token })
}
}

View file

@ -1,10 +1,18 @@
use tokio::sync::oneshot;
use yazi_shared::event::CmdCow;
use anyhow::bail;
use yazi_shared::{CompletionToken, event::CmdCow};
pub struct StopOpt {
pub tx: Option<oneshot::Sender<()>>,
pub token: CompletionToken,
}
impl From<CmdCow> for StopOpt {
fn from(mut c: CmdCow) -> Self { Self { tx: c.take_any("tx") } }
impl TryFrom<CmdCow> for StopOpt {
type Error = anyhow::Error;
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(token) = c.take_any("token") else {
bail!("Invalid 'token' in StopOpt");
};
Ok(Self { token })
}
}

View file

@ -14,7 +14,7 @@ impl TryFrom<CmdCow> for ArrowOpt {
fn try_from(c: CmdCow) -> Result<Self, Self::Error> {
let Ok(step) = c.first() else {
bail!("'step' is required for ArrowOpt");
bail!("Invalid 'step' in ArrowOpt");
};
Ok(Self { step })

View file

@ -4,7 +4,7 @@ use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::{Id, event::CmdCow, path::PathBufDyn, strand::{StrandBuf, StrandLike}, url::UrlBuf};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct ShowOpt {
pub cache: Vec<CmpItem>,
pub cache_name: UrlBuf,

View file

@ -1,13 +1,12 @@
use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use tokio::sync::oneshot;
use yazi_config::popup::ConfirmCfg;
use yazi_shared::event::CmdCow;
use yazi_shared::{CompletionToken, event::CmdCow};
#[derive(Debug)]
pub struct ShowOpt {
pub cfg: ConfirmCfg,
pub tx: oneshot::Sender<bool>,
pub cfg: ConfirmCfg,
pub token: CompletionToken,
}
impl TryFrom<CmdCow> for ShowOpt {
@ -15,14 +14,14 @@ impl TryFrom<CmdCow> for ShowOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(cfg) = c.take_any("cfg") else {
bail!("Invalid 'cfg' argument in ShowOpt");
bail!("Invalid 'cfg' in ShowOpt");
};
let Some(tx) = c.take_any("tx") else {
bail!("Invalid 'tx' argument in ShowOpt");
let Some(token) = c.take_any("token") else {
bail!("Invalid 'token' in ShowOpt");
};
Ok(Self { cfg, tx })
Ok(Self { cfg, token })
}
}

View file

@ -15,11 +15,11 @@ impl TryFrom<CmdCow> for ShowOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(cfg) = c.take_any("cfg") else {
bail!("Invalid 'cfg' argument in ShowOpt");
bail!("Invalid 'cfg' in ShowOpt");
};
let Some(tx) = c.take_any("tx") else {
bail!("Invalid 'tx' argument in ShowOpt");
bail!("Invalid 'tx' in ShowOpt");
};
Ok(Self { cfg, tx })

View file

@ -2,9 +2,9 @@ use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::{event::CmdCow, url::UrlBuf};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct DisplaceDoOpt {
pub to: std::io::Result<UrlBuf>,
pub to: Result<UrlBuf, yazi_fs::error::Error>,
pub from: UrlBuf,
}
@ -15,7 +15,7 @@ impl TryFrom<CmdCow> for DisplaceDoOpt {
if let Some(opt) = c.take_any2("opt") {
opt
} else {
bail!("'opt' is required for DisplaceDoOpt");
bail!("Invalid 'opt' in DisplaceDoOpt");
}
}
}

View file

@ -2,7 +2,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_fs::FilterCase;
use yazi_shared::{SStr, event::CmdCow};
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct FilterOpt {
pub query: SStr,
pub case: FilterCase,

View file

@ -3,7 +3,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_fs::FilterCase;
use yazi_shared::{SStr, event::CmdCow};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct FindDoOpt {
pub query: SStr,
pub prev: bool,
@ -19,7 +19,7 @@ impl TryFrom<CmdCow> for FindDoOpt {
}
let Ok(query) = c.take_first() else {
bail!("'query' is required for FindDoOpt");
bail!("Invalid 'query' in FindDoOpt");
};
Ok(Self { query, prev: c.bool("previous"), case: FilterCase::from(&*c) })

View file

@ -1,7 +1,7 @@
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::{event::CmdCow, url::UrlCow};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct OpenOpt {
pub cwd: Option<UrlCow<'static>>,
pub targets: Vec<UrlCow<'static>>,

View file

@ -2,7 +2,7 @@ use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::{event::CmdCow, url::UrlCow};
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct OpenDoOpt {
pub cwd: UrlCow<'static>,
pub targets: Vec<UrlCow<'static>>,
@ -16,7 +16,7 @@ impl TryFrom<CmdCow> for OpenDoOpt {
if let Some(opt) = c.take_any2("opt") {
opt
} else {
bail!("'opt' is required for OpenDoOpt");
bail!("Invalid 'opt' in OpenDoOpt");
}
}
}

View file

@ -25,7 +25,7 @@ impl TryFrom<CmdCow> for SearchOpt {
};
let Ok(args) = yazi_shared::shell::unix::split(c.str("args"), false) else {
bail!("Invalid 'args' argument in SearchOpt");
bail!("Invalid 'args' in SearchOpt");
};
Ok(Self {

View file

@ -13,7 +13,7 @@ impl TryFrom<CmdCow> for UpdateFilesOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(op) = c.take_any("op") else {
bail!("Invalid 'op' argument in UpdateFilesOpt");
bail!("Invalid 'op' in UpdateFilesOpt");
};
Ok(Self { op })

View file

@ -13,7 +13,7 @@ impl TryFrom<CmdCow> for UpdateMimesOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Ok(updates) = c.take("updates") else {
bail!("Invalid 'updates' argument in UpdateMimesOpt");
bail!("Invalid 'updates' in UpdateMimesOpt");
};
Ok(Self { updates })

View file

@ -3,7 +3,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, Value};
use yazi_binding::{FileRef, elements::{Rect, Renderable}};
use yazi_shared::event::CmdCow;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct UpdatePeekedOpt {
pub lock: PreviewLock,
}
@ -17,7 +17,7 @@ impl TryFrom<CmdCow> for UpdatePeekedOpt {
}
let Some(lock) = c.take_any("lock") else {
bail!("Invalid 'lock' argument in UpdatePeekedOpt");
bail!("Invalid 'lock' in UpdatePeekedOpt");
};
Ok(Self { lock })
@ -33,7 +33,7 @@ impl IntoLua for UpdatePeekedOpt {
}
// --- Lock
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct PreviewLock {
pub url: yazi_shared::url::UrlBuf,
pub cha: yazi_fs::cha::Cha,

View file

@ -3,7 +3,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, Value};
use yazi_binding::{FileRef, elements::Renderable};
use yazi_shared::{Id, event::CmdCow};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct UpdateSpottedOpt {
pub lock: SpotLock,
}
@ -17,7 +17,7 @@ impl TryFrom<CmdCow> for UpdateSpottedOpt {
}
let Some(lock) = c.take_any("lock") else {
bail!("Invalid 'lock' argument in UpdateSpottedOpt");
bail!("Invalid 'lock' in UpdateSpottedOpt");
};
Ok(Self { lock })
@ -33,7 +33,7 @@ impl IntoLua for UpdateSpottedOpt {
}
// --- Lock
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct SpotLock {
pub url: yazi_shared::url::UrlBuf,
pub cha: yazi_fs::cha::Cha,

View file

@ -25,7 +25,7 @@ impl TryFrom<CmdCow> for UpdateYankedOpt<'_> {
if let Some(opt) = c.take_any2("opt") {
opt
} else {
bail!("'opt' is required for UpdateYankedOpt");
bail!("Invalid 'opt' in UpdateYankedOpt");
}
}
}

View file

@ -14,7 +14,7 @@ impl TryFrom<CmdCow> for TickOpt {
fn try_from(c: CmdCow) -> Result<Self, Self::Error> {
let Ok(interval) = c.first() else {
bail!("Invalid 'interval' argument in TickOpt");
bail!("Invalid 'interval' in TickOpt");
};
if interval < 0.0 {

View file

@ -1,13 +1,13 @@
use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use tokio::sync::oneshot;
use tokio::sync::mpsc;
use yazi_config::popup::PickCfg;
use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct ShowOpt {
pub cfg: PickCfg,
pub tx: oneshot::Sender<anyhow::Result<usize>>,
pub tx: mpsc::UnboundedSender<Option<usize>>,
}
impl TryFrom<CmdCow> for ShowOpt {
@ -15,11 +15,11 @@ impl TryFrom<CmdCow> for ShowOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(cfg) = c.take_any("cfg") else {
bail!("Missing 'cfg' argument in ShowOpt");
bail!("Invalid 'cfg' in ShowOpt");
};
let Some(tx) = c.take_any("tx") else {
bail!("Missing 'tx' argument in ShowOpt");
bail!("Invalid 'tx' in ShowOpt");
};
Ok(Self { cfg, tx })

View file

@ -5,7 +5,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::{CompletionToken, event::CmdCow, url::UrlCow};
// --- Exec
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct ProcessOpenOpt {
pub cwd: UrlCow<'static>,
pub cmd: OsString,

View file

@ -12,7 +12,7 @@ impl TryFrom<CmdCow> for UpdateSucceedOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(urls) = c.take_any("urls") else {
bail!("Invalid 'urls' argument in UpdateSucceedOpt");
bail!("Invalid 'urls' in UpdateSucceedOpt");
};
Ok(Self { urls })

View file

@ -5,7 +5,7 @@ use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct CallbackOpt {
pub tx: mpsc::Sender<usize>,
pub tx: mpsc::UnboundedSender<usize>,
pub idx: usize,
}
@ -14,11 +14,11 @@ impl TryFrom<CmdCow> for CallbackOpt {
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
let Some(tx) = c.take_any("tx") else {
bail!("Invalid 'tx' argument in CallbackOpt");
bail!("Invalid 'tx' in CallbackOpt");
};
let Ok(idx) = c.first() else {
bail!("Invalid 'idx' argument in CallbackOpt");
bail!("Invalid 'idx' in CallbackOpt");
};
Ok(Self { tx, idx })

View file

@ -3,7 +3,7 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, Value};
use yazi_config::{KEYMAP, keymap::{ChordCow, Key}};
use yazi_shared::{Layer, event::CmdCow};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct ShowOpt {
pub cands: Vec<ChordCow>,
pub silent: bool,

View file

@ -1,11 +1,11 @@
use mlua::{ExternalError, HookTriggers, IntoLua, ObjectLike, VmState};
use mlua::{ExternalError, HookTriggers, IntoLua, Lua, ObjectLike, Table, VmState};
use tokio::{runtime::Handle, select};
use tokio_util::sync::CancellationToken;
use tracing::error;
use yazi_binding::{Error, File, elements::{Rect, Renderable}};
use yazi_config::LAYOUT;
use yazi_dds::Sendable;
use yazi_parser::{app::{PluginCallback, PluginOpt}, mgr::{PreviewLock, UpdatePeekedOpt}};
use yazi_parser::{app::PluginOpt, mgr::{PreviewLock, UpdatePeekedOpt}};
use yazi_proxy::{AppProxy, MgrProxy};
use yazi_shared::{event::Cmd, pool::Symbol};
@ -52,7 +52,7 @@ pub fn peek(
}
fn peek_sync(cmd: &'static Cmd, file: yazi_fs::File, mime: Symbol<str>, skip: usize) {
let cb: PluginCallback = Box::new(move |lua, plugin| {
let cb = move |lua: &Lua, plugin: Table| {
let job = lua.create_table_from([
("area", Rect::from(LAYOUT.get().preview).into_lua(lua)?),
("args", Sendable::args_to_table_ref(lua, &cmd.args)?.into_lua(lua)?),
@ -62,7 +62,7 @@ fn peek_sync(cmd: &'static Cmd, file: yazi_fs::File, mime: Symbol<str>, skip: us
])?;
plugin.call_method("peek", job)
});
};
AppProxy::plugin(PluginOpt::new_callback(&*cmd.name, cb));
}

View file

@ -1,12 +1,12 @@
use mlua::{IntoLua, ObjectLike};
use mlua::{IntoLua, Lua, ObjectLike, Table};
use yazi_binding::{File, elements::Rect};
use yazi_config::LAYOUT;
use yazi_parser::app::{PluginCallback, PluginOpt};
use yazi_parser::app::PluginOpt;
use yazi_proxy::AppProxy;
use yazi_shared::event::Cmd;
pub fn seek_sync(cmd: &'static Cmd, file: yazi_fs::File, units: i16) {
let cb: PluginCallback = Box::new(move |lua, plugin| {
let cb = move |lua: &Lua, plugin: Table| {
let job = lua.create_table_from([
("file", File::new(file).into_lua(lua)?),
("area", Rect::from(LAYOUT.get().preview).into_lua(lua)?),
@ -14,7 +14,7 @@ pub fn seek_sync(cmd: &'static Cmd, file: yazi_fs::File, units: i16) {
])?;
plugin.call_method("seek", job)
});
};
AppProxy::plugin(PluginOpt::new_callback(&*cmd.name, cb));
}

View file

@ -20,7 +20,7 @@ impl Utils {
return Err("Cannot call `ya.which()` while main thread is blocked".into_lua_err());
}
let (tx, mut rx) = mpsc::channel::<usize>(1);
let (tx, mut rx) = mpsc::unbounded_channel::<usize>();
let cands: Vec<_> = t
.raw_get::<Table>("cands")?
.sequence_values::<Table>()

View file

@ -1,10 +1,10 @@
use anyhow::Context;
use futures::future::join_all;
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, MultiValue, Value, Variadic};
use tokio::sync::oneshot;
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, MultiValue, Table, Value, Variadic};
use tokio::sync::mpsc;
use yazi_binding::{Handle, runtime, runtime_mut};
use yazi_dds::Sendable;
use yazi_parser::app::{PluginCallback, PluginOpt};
use yazi_parser::app::PluginOpt;
use yazi_proxy::AppProxy;
use yazi_shared::{LOCAL_SET, data::Data};
@ -115,27 +115,25 @@ impl Utils {
args: MultiValue,
) -> mlua::Result<Vec<Data>> {
let args = Sendable::values_to_list(lua, args)?;
let (tx, rx) = oneshot::channel::<Vec<Data>>();
let (tx, mut rx) = mpsc::channel::<Vec<Data>>(1);
let callback: PluginCallback = {
let id = id.to_owned();
Box::new(move |lua, plugin| {
let Some(block) = runtime!(lua)?.get_block(&id, calls) else {
return Err("sync block not found".into_lua_err());
};
let id_ = id.to_owned();
let callback = move |lua: &Lua, plugin: Table| {
let Some(block) = runtime!(lua)?.get_block(&id_, calls) else {
return Err("sync block not found".into_lua_err());
};
let args = [Ok(Value::Table(plugin))]
.into_iter()
.chain(args.into_iter().map(|d| Sendable::data_to_value(lua, d)))
.collect::<mlua::Result<MultiValue>>()?;
let args = [Ok(Value::Table(plugin))]
.into_iter()
.chain(args.into_iter().map(|d| Sendable::data_to_value(lua, d)))
.collect::<mlua::Result<MultiValue>>()?;
let values = Sendable::values_to_list(lua, block.call(args)?)?;
tx.send(values).map_err(|_| "send failed".into_lua_err())
})
let values = Sendable::values_to_list(lua, block.call(args)?)?;
tx.try_send(values).map_err(|_| "send failed".into_lua_err())
};
AppProxy::plugin(PluginOpt::new_callback(id.to_owned(), callback));
rx.await.into_lua_err()
rx.recv().await.ok_or("recv failed").into_lua_err()
}
}

View file

@ -1,22 +1,22 @@
use std::time::Duration;
use tokio::sync::oneshot;
use yazi_macro::{emit, relay};
use yazi_parser::app::{NotifyLevel, NotifyOpt, PluginOpt, TaskSummary};
use yazi_shared::CompletionToken;
pub struct AppProxy;
impl AppProxy {
pub async fn stop() {
let (tx, rx) = oneshot::channel::<()>();
emit!(Call(relay!(app:stop).with_any("tx", tx)));
rx.await.ok();
let token = CompletionToken::default();
emit!(Call(relay!(app:stop).with_any("token", token.clone())));
token.future().await;
}
pub async fn resume() {
let (tx, rx) = oneshot::channel::<()>();
emit!(Call(relay!(app:resume).with_any("tx", tx)));
rx.await.ok();
let token = CompletionToken::default();
emit!(Call(relay!(app:resume).with_any("token", token.clone())));
token.future().await;
}
pub fn notify(opt: NotifyOpt) {

View file

@ -1,15 +1,15 @@
use tokio::sync::oneshot;
use yazi_config::popup::ConfirmCfg;
use yazi_macro::{emit, relay};
use yazi_shared::CompletionToken;
pub struct ConfirmProxy;
impl ConfirmProxy {
pub async fn show(cfg: ConfirmCfg) -> bool { Self::show_rx(cfg).await.unwrap_or(false) }
pub async fn show(cfg: ConfirmCfg) -> bool { Self::show_sync(cfg).future().await }
pub fn show_rx(cfg: ConfirmCfg) -> oneshot::Receiver<bool> {
let (tx, rx) = oneshot::channel();
emit!(Call(relay!(confirm:show).with_any("tx", tx).with_any("cfg", cfg)));
rx
pub fn show_sync(cfg: ConfirmCfg) -> CompletionToken {
let token = CompletionToken::default();
emit!(Call(relay!(confirm:show).with_any("cfg", cfg).with_any("token", token.clone())));
token
}
}

View file

@ -1,13 +1,13 @@
use tokio::sync::oneshot;
use tokio::sync::mpsc;
use yazi_config::popup::PickCfg;
use yazi_macro::{emit, relay};
pub struct PickProxy;
impl PickProxy {
pub async fn show(cfg: PickCfg) -> anyhow::Result<usize> {
let (tx, rx) = oneshot::channel();
pub async fn show(cfg: PickCfg) -> Option<usize> {
let (tx, mut rx) = mpsc::unbounded_channel::<Option<usize>>();
emit!(Call(relay!(pick:show).with_any("tx", tx).with_any("cfg", cfg)));
rx.await?
rx.recv().await?
}
}

View file

@ -18,6 +18,7 @@ yazi-macro = { path = "../yazi-macro", version = "26.1.22" }
# External dependencies
anyhow = { workspace = true }
crossterm = { workspace = true }
dyn-clone = { workspace = true }
foldhash = { workspace = true }
futures = { workspace = true }
hashbrown = { workspace = true }

View file

@ -0,0 +1,28 @@
use std::{any::Any, fmt};
use dyn_clone::DynClone;
pub trait DataAny: Any + Send + Sync + DynClone {
fn as_any(&self) -> &dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
}
impl<T> DataAny for T
where
T: Any + Send + Sync + DynClone,
{
fn as_any(&self) -> &dyn Any { self }
fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
}
impl Clone for Box<dyn DataAny> {
fn clone(&self) -> Self { dyn_clone::clone_box(&**self) }
}
impl fmt::Debug for dyn DataAny {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DataAny").finish_non_exhaustive()
}
}

View file

@ -1,13 +1,13 @@
use std::{any::Any, borrow::Cow};
use std::borrow::Cow;
use anyhow::{Result, bail};
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use crate::{Id, SStr, data::DataKey, path::PathBufDyn, url::{UrlBuf, UrlCow}};
use crate::{Id, SStr, data::{DataAny, DataKey}, path::PathBufDyn, url::{UrlBuf, UrlCow}};
// --- Data
#[derive(Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Data {
Nil,
@ -25,7 +25,7 @@ pub enum Data {
#[serde(skip)]
Bytes(Vec<u8>),
#[serde(skip)]
Any(Box<dyn Any + Send + Sync>),
Any(Box<dyn DataAny>),
}
impl From<()> for Data {
@ -199,7 +199,7 @@ impl Data {
pub fn into_any<T: 'static>(self) -> Option<T> {
match self {
Self::Any(b) => b.downcast::<T>().ok().map(|b| *b),
Self::Any(b) => b.into_any().downcast::<T>().ok().map(|b| *b),
_ => None,
}
}
@ -207,7 +207,7 @@ impl Data {
// FIXME: find a better name
pub fn into_any2<T: 'static>(self) -> Result<T> {
if let Self::Any(b) = self
&& let Ok(t) = b.downcast::<T>()
&& let Ok(t) = b.into_any().downcast::<T>()
{
Ok(*t)
} else {

View file

@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize, de};
use crate::{Id, SStr, path::PathBufDyn, url::{UrlBuf, UrlCow}};
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(untagged)]
pub enum DataKey {
Nil,

View file

@ -1 +1 @@
yazi_macro::mod_flat!(data key);
yazi_macro::mod_flat!(any data key);

View file

@ -1,12 +1,12 @@
use std::{any::Any, borrow::Cow, fmt::{self, Display}, mem, str::FromStr};
use std::{borrow::Cow, fmt::{self, Display}, mem, str::FromStr};
use anyhow::{Result, anyhow, bail};
use hashbrown::HashMap;
use serde::{Deserialize, de};
use crate::{Layer, SStr, Source, data::{Data, DataKey}};
use crate::{Layer, SStr, Source, data::{Data, DataAny, DataKey}};
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct Cmd {
pub name: SStr,
pub args: HashMap<DataKey, Data>,
@ -76,7 +76,7 @@ impl Cmd {
self
}
pub fn with_any(mut self, name: impl Into<DataKey>, data: impl Any + Send + Sync) -> Self {
pub fn with_any(mut self, name: impl Into<DataKey>, data: impl DataAny) -> Self {
self.args.insert(name.into(), Data::Any(Box::new(data)));
self
}