From 750ca0c0d40af099a46d340df47af87eec267d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Wed, 18 Jun 2025 19:30:31 +0800 Subject: [PATCH] fix: throw catchable errors instead of crashing when publishing a message containing invalid UTF-8 over DDS (#2893) --- yazi-core/src/mgr/commands/bulk_rename.rs | 4 +- yazi-core/src/mgr/commands/rename.rs | 3 +- yazi-core/src/mgr/tabs.rs | 3 +- yazi-core/src/mgr/watcher.rs | 7 +- yazi-core/src/mgr/yanked.rs | 3 +- yazi-core/src/tab/commands/cd.rs | 4 +- yazi-core/src/tab/commands/hover.rs | 4 +- yazi-core/src/tab/folder.rs | 3 +- yazi-dds/src/client.rs | 13 +-- yazi-dds/src/payload.rs | 17 ++-- yazi-dds/src/pubsub.rs | 112 ++++++++++++---------- yazi-dds/src/pump.rs | 7 +- yazi-dds/src/server.rs | 24 ++--- yazi-fs/src/mounts/macos.rs | 7 +- yazi-macro/src/fmt.rs | 9 ++ yazi-macro/src/lib.rs | 1 + yazi-macro/src/log.rs | 15 +++ yazi-plugin/src/pubsub/pubsub.rs | 6 +- 18 files changed, 145 insertions(+), 97 deletions(-) create mode 100644 yazi-macro/src/fmt.rs diff --git a/yazi-core/src/mgr/commands/bulk_rename.rs b/yazi-core/src/mgr/commands/bulk_rename.rs index 744764cb..6e0e8044 100644 --- a/yazi-core/src/mgr/commands/bulk_rename.rs +++ b/yazi-core/src/mgr/commands/bulk_rename.rs @@ -7,6 +7,7 @@ use tokio::{fs::{self, OpenOptions}, io::AsyncWriteExt}; use yazi_config::YAZI; use yazi_dds::Pubsub; use yazi_fs::{File, FilesOp, max_common_root, maybe_exists, paths_to_same_file}; +use yazi_macro::err; use yazi_proxy::{AppProxy, HIDER, TasksProxy, WATCHER}; use yazi_shared::{terminal_clear, url::Url}; use yazi_term::tty::TTY; @@ -102,7 +103,8 @@ impl Mgr { } if !succeeded.is_empty() { - Pubsub::pub_from_bulk(succeeded.iter().map(|(o, n)| (o, &n.url)).collect()); + let map = succeeded.iter().map(|(o, n)| (o, &n.url)).collect(); + err!(Pubsub::pub_from_bulk(map)); FilesOp::rename(succeeded); } drop(permit); diff --git a/yazi-core/src/mgr/commands/rename.rs b/yazi-core/src/mgr/commands/rename.rs index 44e80c21..48ebb73a 100644 --- a/yazi-core/src/mgr/commands/rename.rs +++ b/yazi-core/src/mgr/commands/rename.rs @@ -5,6 +5,7 @@ use tokio::fs; use yazi_config::popup::{ConfirmCfg, InputCfg}; use yazi_dds::Pubsub; use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, paths_to_same_file, realname}; +use yazi_macro::err; use yazi_proxy::{ConfirmProxy, InputProxy, TabProxy, WATCHER}; use yazi_shared::{Id, event::CmdCow, url::{Url, UrnBuf}}; @@ -92,7 +93,7 @@ impl Mgr { } TabProxy::reveal(&new); - Pubsub::pub_from_rename(tab, &old, &new); + err!(Pubsub::pub_from_rename(tab, &old, &new)); Ok(()) } diff --git a/yazi-core/src/mgr/tabs.rs b/yazi-core/src/mgr/tabs.rs index 45e81a21..ec517cb8 100644 --- a/yazi-core/src/mgr/tabs.rs +++ b/yazi-core/src/mgr/tabs.rs @@ -3,6 +3,7 @@ use std::ops::{Deref, DerefMut}; use yazi_boot::BOOT; use yazi_dds::Pubsub; use yazi_fs::File; +use yazi_macro::err; use yazi_proxy::MgrProxy; use yazi_shared::{Id, url::Url}; @@ -38,7 +39,7 @@ impl Tabs { self.cursor = idx; MgrProxy::refresh(); MgrProxy::peek(true); - Pubsub::pub_from_tab(self.active().id); + err!(Pubsub::pub_from_tab(self.active().id)); } } diff --git a/yazi-core/src/mgr/watcher.rs b/yazi-core/src/mgr/watcher.rs index a7475387..b0814eb7 100644 --- a/yazi-core/src/mgr/watcher.rs +++ b/yazi-core/src/mgr/watcher.rs @@ -43,10 +43,9 @@ impl Watcher { } #[cfg(any(target_os = "linux", target_os = "macos"))] - yazi_fs::mounts::Partitions::monitor( - yazi_fs::mounts::PARTITIONS.clone(), - yazi_dds::Pubsub::pub_from_mount, - ); + yazi_fs::mounts::Partitions::monitor(yazi_fs::mounts::PARTITIONS.clone(), || { + yazi_macro::err!(yazi_dds::Pubsub::pub_from_mount()) + }); tokio::spawn(Self::fan_out(out_rx)); Self { in_tx, out_tx } diff --git a/yazi-core/src/mgr/yanked.rs b/yazi-core/src/mgr/yanked.rs index 5d068a40..0d16bb4c 100644 --- a/yazi-core/src/mgr/yanked.rs +++ b/yazi-core/src/mgr/yanked.rs @@ -2,6 +2,7 @@ use std::{collections::HashSet, ops::Deref}; use yazi_dds::Pubsub; use yazi_fs::FilesOp; +use yazi_macro::err; use yazi_shared::url::Url; #[derive(Debug, Default)] @@ -65,7 +66,7 @@ impl Yanked { } self.version = self.revision; - Pubsub::pub_from_yank(self.cut, &self.urls); + err!(Pubsub::pub_from_yank(self.cut, &self.urls)); true } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 9bae669e..4a417747 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -5,7 +5,7 @@ use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use yazi_config::popup::InputCfg; use yazi_dds::Pubsub; use yazi_fs::{File, FilesOp, expand_path}; -use yazi_macro::render; +use yazi_macro::{err, render}; use yazi_proxy::{CmpProxy, InputProxy, MgrProxy, TabProxy}; use yazi_shared::{Debounce, errors::InputError, event::CmdCow, url::Url}; @@ -73,7 +73,7 @@ impl Tab { self.parent = Some(self.history.remove_or(&parent)); } - Pubsub::pub_from_cd(self.id, self.cwd()); + err!(Pubsub::pub_from_cd(self.id, self.cwd())); self.hover(None); MgrProxy::refresh(); diff --git a/yazi-core/src/tab/commands/hover.rs b/yazi-core/src/tab/commands/hover.rs index 074dce9d..18ba2c18 100644 --- a/yazi-core/src/tab/commands/hover.rs +++ b/yazi-core/src/tab/commands/hover.rs @@ -1,5 +1,5 @@ use yazi_dds::Pubsub; -use yazi_macro::render; +use yazi_macro::{err, render}; use yazi_shared::{event::CmdCow, url::{Url, Urn}}; use crate::tab::Tab; @@ -25,7 +25,7 @@ impl Tab { } // Publish through DDS - Pubsub::pub_from_hover(self.id, self.hovered().map(|h| &h.url)); + err!(Pubsub::pub_from_hover(self.id, self.hovered().map(|h| &h.url))); } fn hover_do(&mut self, url: Url) { diff --git a/yazi-core/src/tab/folder.rs b/yazi-core/src/tab/folder.rs index 67fd7e09..9f149ef3 100644 --- a/yazi-core/src/tab/folder.rs +++ b/yazi-core/src/tab/folder.rs @@ -3,6 +3,7 @@ use std::mem; use yazi_config::{LAYOUT, YAZI}; use yazi_dds::Pubsub; use yazi_fs::{File, Files, FilesOp, FolderStage, Step, cha::Cha}; +use yazi_macro::err; use yazi_proxy::MgrProxy; use yazi_shared::{Id, url::{Url, Urn, UrnBuf}}; @@ -88,7 +89,7 @@ impl Folder { if !self.update(op) { return false; } else if self.stage != old { - Pubsub::pub_from_load(tab, &self.url, self.stage); + err!(Pubsub::pub_from_load(tab, &self.url, self.stage)); } true } diff --git a/yazi-dds/src/client.rs b/yazi-dds/src/client.rs index 972e5392..4b7234ff 100644 --- a/yazi-dds/src/client.rs +++ b/yazi-dds/src/client.rs @@ -5,6 +5,7 @@ use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time}; use tracing::error; +use yazi_macro::try_format; use yazi_shared::{Id, RoCell}; use crate::{ClientReader, ClientWriter, Payload, Pubsub, Server, Stream, body::{Body, BodyBye, BodyHi}}; @@ -55,7 +56,7 @@ impl Client { continue; } else if line.starts_with("hey,") { Self::handle_hey(&line); - } else if let Err(e) = Payload::from_str(&line).map(|p| p.emit()) { + } else if let Err(e) = Payload::from_str(&line).and_then(|p| p.emit()) { error!("Could not parse payload:\n{line}\n\nError:\n{e}"); } } @@ -68,11 +69,11 @@ impl Client { pub async fn shot(kind: &str, receiver: Id, body: &str) -> Result<()> { Body::validate(kind)?; - let payload = format!( + let payload = try_format!( "{}\n{kind},{receiver},{ID},{body}\n{}\n", Payload::new(BodyHi::borrowed(Default::default())), Payload::new(BodyBye::owned()) - ); + )?; let (mut lines, mut writer) = Stream::connect().await?; writer.write_all(payload.as_bytes()).await?; @@ -129,7 +130,7 @@ impl Client { async fn make(kinds: &HashSet<&str>) -> Result { let (lines, mut writer) = Stream::connect().await?; let hi = Payload::new(BodyHi::borrowed(kinds.clone())); - writer.write_all(format!("{hi}\n").as_bytes()).await?; + writer.write_all(try_format!("{hi}\n")?.as_bytes()).await?; writer.flush().await?; Ok(lines) } @@ -155,8 +156,8 @@ impl Client { } #[inline] - pub(super) fn push<'a>(payload: impl Into>) { - QUEUE_TX.send(format!("{}\n", payload.into())).ok(); + pub(super) fn push<'a>(payload: impl Into>) -> Result<()> { + Ok(QUEUE_TX.send(try_format!("{}\n", payload.into())?)?) } #[inline] diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index 321bee61..0286ccff 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -17,9 +17,12 @@ pub struct Payload<'a> { impl<'a> Payload<'a> { pub(super) fn new(body: Body<'a>) -> Self { Self { receiver: Id(0), sender: *ID, body } } - pub(super) fn flush(&self) { writeln!(std::io::stdout(), "{self}").ok(); } + pub(super) fn flush(&self) -> Result<()> { + writeln!(std::io::stdout(), "{self}")?; + Ok(()) + } - pub(super) fn try_flush(&self) { + pub(super) fn try_flush(&self) -> Result<()> { let b = if self.receiver == 0 { BOOT.remote_events.contains(self.body.kind()) } else if let Body::Custom(b) = &self.body { @@ -27,10 +30,7 @@ impl<'a> Payload<'a> { } else { false }; - - if b { - self.flush(); - } + if b { self.flush() } else { Ok(()) } } pub(super) fn with_receiver(mut self, receiver: Id) -> Self { @@ -45,9 +45,10 @@ impl<'a> Payload<'a> { } impl Payload<'static> { - pub(super) fn emit(self) { - self.try_flush(); + pub(super) fn emit(self) -> Result<()> { + self.try_flush()?; emit!(Call(Cmd::new("app:accept_payload").with_any("payload", self))); + Ok(()) } } diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index 424aab3c..40caa0ac 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; +use anyhow::Result; use mlua::Function; use parking_lot::RwLock; use yazi_boot::BOOT; @@ -62,159 +63,172 @@ impl Pubsub { unsub!(REMOTE)(plugin, kind) && Self::pub_from_hi() } - pub fn r#pub(body: Body<'static>) { body.with_receiver(*ID).emit(); } + pub fn r#pub(body: Body<'static>) -> Result<()> { body.with_receiver(*ID).emit() } - pub fn pub_to(receiver: Id, body: Body<'static>) { + pub fn pub_to(receiver: Id, body: Body<'static>) -> Result<()> { if receiver == *ID { return Self::r#pub(body); } let kind = body.kind(); if receiver == 0 && Self::any_remote_own(kind) { - Client::push(body); + Client::push(body)?; } else if PEERS.read().get(&receiver).is_some_and(|c| c.able(kind)) { - Client::push(body.with_receiver(receiver)); + Client::push(body.with_receiver(receiver))?; } + Ok(()) } pub fn pub_from_hi() -> bool { let abilities = REMOTE.read().keys().cloned().collect(); let abilities = BOOT.remote_events.union(&abilities).map(|s| s.as_str()).collect(); - Client::push(BodyHi::borrowed(abilities)); + // FIXME: handle error + Client::push(BodyHi::borrowed(abilities)).ok(); true } - pub fn pub_from_tab(idx: Id) { + pub fn pub_from_tab(idx: Id) -> Result<()> { if LOCAL.read().contains_key("tab") { - Self::r#pub(BodyTab::owned(idx)); + Self::r#pub(BodyTab::owned(idx))?; } if PEERS.read().values().any(|p| p.able("tab")) { - Client::push(BodyTab::owned(idx)); + Client::push(BodyTab::owned(idx))?; } if BOOT.local_events.contains("tab") { - BodyTab::owned(idx).with_receiver(*ID).flush(); + BodyTab::owned(idx).with_receiver(*ID).flush()?; } + Ok(()) } - pub fn pub_from_cd(tab: Id, url: &Url) { + pub fn pub_from_cd(tab: Id, url: &Url) -> Result<()> { if LOCAL.read().contains_key("cd") { - Self::r#pub(BodyCd::dummy(tab)); + Self::r#pub(BodyCd::dummy(tab))?; } if PEERS.read().values().any(|p| p.able("cd")) { - Client::push(BodyCd::borrowed(tab, url)); + Client::push(BodyCd::borrowed(tab, url))?; } if BOOT.local_events.contains("cd") { - BodyCd::borrowed(tab, url).with_receiver(*ID).flush(); + BodyCd::borrowed(tab, url).with_receiver(*ID).flush()?; } + Ok(()) } - pub fn pub_from_load(tab: Id, url: &Url, stage: FolderStage) { + pub fn pub_from_load(tab: Id, url: &Url, stage: FolderStage) -> Result<()> { if LOCAL.read().contains_key("load") { - Self::r#pub(BodyLoad::dummy(tab, url, stage)); + Self::r#pub(BodyLoad::dummy(tab, url, stage))?; } if PEERS.read().values().any(|p| p.able("load")) { - Client::push(BodyLoad::borrowed(tab, url, stage)); + Client::push(BodyLoad::borrowed(tab, url, stage))?; } if BOOT.local_events.contains("load") { - BodyLoad::borrowed(tab, url, stage).with_receiver(*ID).flush(); + BodyLoad::borrowed(tab, url, stage).with_receiver(*ID).flush()?; } + Ok(()) } - pub fn pub_from_hover(tab: Id, url: Option<&Url>) { + pub fn pub_from_hover(tab: Id, url: Option<&Url>) -> Result<()> { if LOCAL.read().contains_key("hover") { - Self::r#pub(BodyHover::dummy(tab)); + Self::r#pub(BodyHover::dummy(tab))?; } if PEERS.read().values().any(|p| p.able("hover")) { - Client::push(BodyHover::borrowed(tab, url)); + Client::push(BodyHover::borrowed(tab, url))?; } if BOOT.local_events.contains("hover") { - BodyHover::borrowed(tab, url).with_receiver(*ID).flush(); + BodyHover::borrowed(tab, url).with_receiver(*ID).flush()?; } + Ok(()) } - pub fn pub_from_rename(tab: Id, from: &Url, to: &Url) { + pub fn pub_from_rename(tab: Id, from: &Url, to: &Url) -> Result<()> { if LOCAL.read().contains_key("rename") { - Self::r#pub(BodyRename::dummy(tab, from, to)); + Self::r#pub(BodyRename::dummy(tab, from, to))?; } if PEERS.read().values().any(|p| p.able("rename")) { - Client::push(BodyRename::borrowed(tab, from, to)); + Client::push(BodyRename::borrowed(tab, from, to))?; } if BOOT.local_events.contains("rename") { - BodyRename::borrowed(tab, from, to).with_receiver(*ID).flush(); + BodyRename::borrowed(tab, from, to).with_receiver(*ID).flush()?; } + Ok(()) } - pub fn pub_from_bulk(changes: HashMap<&Url, &Url>) { + pub fn pub_from_bulk(changes: HashMap<&Url, &Url>) -> Result<()> { if LOCAL.read().contains_key("bulk") { - Self::r#pub(BodyBulk::owned(&changes)); + Self::r#pub(BodyBulk::owned(&changes))?; } if PEERS.read().values().any(|p| p.able("bulk")) { - Client::push(BodyBulk::borrowed(&changes)); + Client::push(BodyBulk::borrowed(&changes))?; } if BOOT.local_events.contains("bulk") { - BodyBulk::borrowed(&changes).with_receiver(*ID).flush(); + BodyBulk::borrowed(&changes).with_receiver(*ID).flush()?; } + Ok(()) } - pub fn pub_from_yank(cut: bool, urls: &HashSet) { + pub fn pub_from_yank(cut: bool, urls: &HashSet) -> Result<()> { if LOCAL.read().contains_key("@yank") { - Self::r#pub(BodyYank::dummy()); + Self::r#pub(BodyYank::dummy())?; } if Self::any_remote_own("@yank") { - Client::push(BodyYank::borrowed(cut, urls)); + Client::push(BodyYank::borrowed(cut, urls))?; } if BOOT.local_events.contains("@yank") { - BodyYank::borrowed(cut, urls).with_receiver(*ID).flush(); + BodyYank::borrowed(cut, urls).with_receiver(*ID).flush()?; } + Ok(()) } - pub(super) fn pub_from_move(items: Vec) { + pub(super) fn pub_from_move(items: Vec) -> Result<()> { if PEERS.read().values().any(|p| p.able("move")) { - Client::push(BodyMove::borrowed(&items)); + Client::push(BodyMove::borrowed(&items))?; } if BOOT.local_events.contains("move") { - BodyMove::borrowed(&items).with_receiver(*ID).flush(); + BodyMove::borrowed(&items).with_receiver(*ID).flush()?; } if LOCAL.read().contains_key("move") { - Self::r#pub(BodyMove::owned(items)); + Self::r#pub(BodyMove::owned(items))?; } + Ok(()) } - pub(super) fn pub_from_trash(urls: Vec) { + pub(super) fn pub_from_trash(urls: Vec) -> Result<()> { if PEERS.read().values().any(|p| p.able("trash")) { - Client::push(BodyTrash::borrowed(&urls)); + Client::push(BodyTrash::borrowed(&urls))?; } if BOOT.local_events.contains("trash") { - BodyTrash::borrowed(&urls).with_receiver(*ID).flush(); + BodyTrash::borrowed(&urls).with_receiver(*ID).flush()?; } if LOCAL.read().contains_key("trash") { - Self::r#pub(BodyTrash::owned(urls)); + Self::r#pub(BodyTrash::owned(urls))?; } + Ok(()) } - pub(super) fn pub_from_delete(urls: Vec) { + pub(super) fn pub_from_delete(urls: Vec) -> Result<()> { if PEERS.read().values().any(|p| p.able("delete")) { - Client::push(BodyDelete::borrowed(&urls)); + Client::push(BodyDelete::borrowed(&urls))?; } if BOOT.local_events.contains("delete") { - BodyDelete::borrowed(&urls).with_receiver(*ID).flush(); + BodyDelete::borrowed(&urls).with_receiver(*ID).flush()?; } if LOCAL.read().contains_key("delete") { - Self::r#pub(BodyDelete::owned(urls)); + Self::r#pub(BodyDelete::owned(urls))?; } + Ok(()) } - pub fn pub_from_mount() { + pub fn pub_from_mount() -> Result<()> { if LOCAL.read().contains_key("mount") { - Self::r#pub(BodyMount::owned()); + Self::r#pub(BodyMount::owned())?; } if PEERS.read().values().any(|p| p.able("mount")) { - Client::push(BodyMount::owned()); + Client::push(BodyMount::owned())?; } if BOOT.local_events.contains("mount") { - BodyMount::owned().with_receiver(*ID).flush(); + BodyMount::owned().with_receiver(*ID).flush()?; } + Ok(()) } #[inline] diff --git a/yazi-dds/src/pump.rs b/yazi-dds/src/pump.rs index 335ae521..6d0def49 100644 --- a/yazi-dds/src/pump.rs +++ b/yazi-dds/src/pump.rs @@ -4,6 +4,7 @@ use parking_lot::Mutex; use tokio::{pin, select, sync::mpsc}; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use tokio_util::sync::CancellationToken; +use yazi_macro::err; use yazi_shared::{RoCell, url::Url}; use crate::{Pubsub, body::BodyMoveItem}; @@ -61,9 +62,9 @@ impl Pump { loop { select! { - Some(items) = move_rx.next() => Pubsub::pub_from_move(items), - Some(urls) = trash_rx.next() => Pubsub::pub_from_trash(urls), - Some(urls) = delete_rx.next() => Pubsub::pub_from_delete(urls), + Some(items) = move_rx.next() => err!(Pubsub::pub_from_move(items)), + Some(urls) = trash_rx.next() => err!(Pubsub::pub_from_trash(urls)), + Some(urls) = delete_rx.next() => err!(Pubsub::pub_from_delete(urls)), else => { CT.cancel(); break; diff --git a/yazi-dds/src/server.rs b/yazi-dds/src/server.rs index ab6bbb9a..3ee47fa2 100644 --- a/yazi-dds/src/server.rs +++ b/yazi-dds/src/server.rs @@ -3,6 +3,7 @@ use std::{collections::HashMap, str::FromStr, time::Duration}; use anyhow::Result; use parking_lot::RwLock; use tokio::{io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle, time}; +use yazi_macro::try_format; use yazi_shared::{Id, RoCell}; use crate::{Client, ClientWriter, Payload, Peer, STATE, Stream, body::{Body, BodyBye, BodyHey}}; @@ -109,13 +110,12 @@ impl Server { } fn handle_hey(clients: &HashMap) { - let payload = format!( - "{}\n", - Payload::new(BodyHey::owned( - clients.values().map(|c| (c.id, Peer::new(&c.abilities))).collect() - )) - ); - clients.values().for_each(|c| _ = c.tx.send(payload.clone())); + let payload = Payload::new(BodyHey::owned( + clients.values().map(|c| (c.id, Peer::new(&c.abilities))).collect(), + )); + if let Ok(s) = try_format!("{payload}\n") { + clients.values().for_each(|c| _ = c.tx.send(s.clone())); + } } async fn handle_bye(id: Id, mut rx: UnboundedReceiver, mut writer: ClientWriter) { @@ -125,10 +125,10 @@ impl Server { } } - _ = writer - .write_all(BodyBye::owned().with_receiver(id).with_sender(Id(0)).to_string().as_bytes()) - .await; - - writer.flush().await.ok(); + let bye = BodyBye::owned().with_receiver(id).with_sender(Id(0)); + if let Ok(s) = try_format!("{bye}") { + writer.write_all(s.as_bytes()).await.ok(); + writer.flush().await.ok(); + } } } diff --git a/yazi-fs/src/mounts/macos.rs b/yazi-fs/src/mounts/macos.rs index a24501b7..82dcebd5 100644 --- a/yazi-fs/src/mounts/macos.rs +++ b/yazi-fs/src/mounts/macos.rs @@ -12,7 +12,10 @@ use yazi_shared::natsort; use super::{Locked, Partition, Partitions}; impl Partitions { - pub fn monitor(me: Locked, cb: fn()) { + pub fn monitor(me: Locked, cb: F) + where + F: Fn() + Copy + Send + 'static, + { tokio::task::spawn_blocking(move || { let session = unsafe { DASessionCreate(kCFAllocatorDefault) }; if session.is_null() { @@ -41,7 +44,7 @@ impl Partitions { if mem::replace(&mut me.write().need_update, true) { return; } - Self::update(me.clone(), cb); + Self::update(me.clone(), move || _ = cb()); }); Box::into_raw(Box::new(boxed)) as *mut c_void }; diff --git a/yazi-macro/src/fmt.rs b/yazi-macro/src/fmt.rs new file mode 100644 index 00000000..cc12ba0d --- /dev/null +++ b/yazi-macro/src/fmt.rs @@ -0,0 +1,9 @@ +#[macro_export] +macro_rules! try_format { + ($($arg:tt)*) => {{ + use std::fmt::Write; + + let mut output = String::new(); + output.write_fmt(format_args!($($arg)*)).map(|_| output) + }} +} diff --git a/yazi-macro/src/lib.rs b/yazi-macro/src/lib.rs index 39658539..ed825ad7 100644 --- a/yazi-macro/src/lib.rs +++ b/yazi-macro/src/lib.rs @@ -1,5 +1,6 @@ mod asset; mod event; +mod fmt; mod log; mod module; mod platform; diff --git a/yazi-macro/src/log.rs b/yazi-macro/src/log.rs index 3770bfeb..0fe08c64 100644 --- a/yazi-macro/src/log.rs +++ b/yazi-macro/src/log.rs @@ -17,3 +17,18 @@ macro_rules! time { } }}; } + +#[macro_export] +macro_rules! err { + ($expr:expr) => { + $crate::err!(stringify!($expr), $expr) + }; + ($label:expr, $expr:expr) => { + $crate::err!($expr, "{}", $label) + }; + ($expr:expr, $fmt:expr, $($args:tt)*) => {{ + if let Err(e) = $expr { + tracing::error!("{} failed: {e}", format_args!($fmt, $($args)*)); + } + }}; +} diff --git a/yazi-plugin/src/pubsub/pubsub.rs b/yazi-plugin/src/pubsub/pubsub.rs index 5f44b344..a3132923 100644 --- a/yazi-plugin/src/pubsub/pubsub.rs +++ b/yazi-plugin/src/pubsub/pubsub.rs @@ -9,15 +9,13 @@ pub struct Pubsub; impl Pubsub { pub(super) fn r#pub(lua: &Lua) -> mlua::Result { lua.create_function(|_, (kind, value): (mlua::String, Value)| { - yazi_dds::Pubsub::r#pub(Body::from_lua(&kind.to_str()?, value)?); - Ok(()) + yazi_dds::Pubsub::r#pub(Body::from_lua(&kind.to_str()?, value)?).into_lua_err() }) } pub(super) fn pub_to(lua: &Lua) -> mlua::Result { lua.create_function(|_, (receiver, kind, value): (Id, mlua::String, Value)| { - yazi_dds::Pubsub::pub_to(*receiver, Body::from_lua(&kind.to_str()?, value)?); - Ok(()) + yazi_dds::Pubsub::pub_to(*receiver, Body::from_lua(&kind.to_str()?, value)?).into_lua_err() }) }