refactor: pull DDS events out into a macro (#2977)

This commit is contained in:
三咲雅 misaki masa 2025-07-11 08:55:56 +08:00 committed by GitHub
parent 18795320bb
commit c9c85130e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 168 additions and 253 deletions

29
Cargo.lock generated
View file

@ -388,9 +388,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
dependencies = [
"clap_builder",
"clap_derive",
@ -398,9 +398,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
dependencies = [
"anstream",
"anstyle",
@ -410,9 +410,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.54"
version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677"
checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a"
dependencies = [
"clap",
]
@ -429,9 +429,9 @@ dependencies = [
[[package]]
name = "clap_complete_nushell"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb8335b398d197fb3176efe9400c6c053a41733c26794316c73423d212b2f3d"
checksum = "0a0c951694691e65bf9d421d597d68416c22de9632e884c28412cb8cd8b73dce"
dependencies = [
"clap",
"clap_complete",
@ -439,9 +439,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
dependencies = [
"heck",
"proc-macro2",
@ -2739,9 +2739,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f271e09bde39ab52250160a67e88577e0559ad77e9085de6e9051a2c4353f8f8"
checksum = "0207d6ed1852c2a124c1fbec61621acb8330d2bf969a5d0643131e9affd985a5"
dependencies = [
"indexmap",
"serde",
@ -3544,7 +3544,7 @@ dependencies = [
"serde",
"serde_json",
"tokio",
"toml 0.9.0",
"toml 0.9.1",
"twox-hash",
"vergen-gitcl",
"yazi-boot",
@ -3575,7 +3575,7 @@ dependencies = [
"ratatui",
"regex",
"serde",
"toml 0.9.0",
"toml 0.9.1",
"tracing",
"yazi-codegen",
"yazi-fs",
@ -3627,6 +3627,7 @@ dependencies = [
"mlua",
"ordered-float 5.0.0",
"parking_lot",
"paste",
"serde",
"serde_json",
"tokio",

View file

@ -24,7 +24,7 @@ ansi-to-tui = "7.0.0"
anyhow = "1.0.98"
base64 = "0.22.1"
bitflags = "2.9.1"
clap = { version = "4.5.40", features = [ "derive" ] }
clap = { version = "4.5.41", features = [ "derive" ] }
core-foundation-sys = "0.8.7"
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
dirs = "6.0.0"
@ -48,7 +48,7 @@ syntect = { version = "5.2.0", default-features = false, features =
tokio = { version = "1.46.1", features = [ "full" ] }
tokio-stream = "0.1.17"
tokio-util = "0.7.15"
toml = { version = "0.9.0" }
toml = { version = "0.9.1" }
tracing = { version = "0.1.41", features = [ "max_level_debug", "release_max_level_debug" ] }
twox-hash = { version = "2.1.1", default-features = false, features = [ "std", "random", "xxhash3_128" ] }
unicode-width = { version = "0.2.0", default-features = false }

View file

@ -25,7 +25,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.6.11" }
# External dependencies
clap = { workspace = true }
clap_complete = "4.5.54"
clap_complete = "4.5.55"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.7"
clap_complete_nushell = "4.5.8"
vergen-gitcl = { version = "1.0.8", features = [ "build", "rustc" ] }

View file

@ -41,9 +41,9 @@ yazi-shared = { path = "../yazi-shared", version = "25.6.11" }
# External build dependencies
anyhow = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.54"
clap_complete = "4.5.55"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.7"
clap_complete_nushell = "4.5.8"
serde_json = { workspace = true }
vergen-gitcl = { version = "1.0.8", features = [ "build" ] }

View file

@ -103,8 +103,8 @@ impl Mgr {
}
if !succeeded.is_empty() {
let map = succeeded.iter().map(|(o, n)| (o, &n.url)).collect();
err!(Pubsub::pub_from_bulk(map));
let it = succeeded.iter().map(|(o, n)| (o, &n.url));
err!(Pubsub::pub_after_bulk(it));
FilesOp::rename(succeeded);
}
drop(permit);

View file

@ -74,7 +74,7 @@ impl Mgr {
}
TabProxy::reveal(&new);
err!(Pubsub::pub_from_rename(tab, &old, &new));
err!(Pubsub::pub_after_rename(tab, &old, &new));
Ok(())
}

View file

@ -40,7 +40,7 @@ impl Tabs {
self.cursor = idx;
MgrProxy::refresh();
MgrProxy::peek(true);
err!(Pubsub::pub_from_tab(self.active().id));
err!(Pubsub::pub_after_tab(self.active().id));
}
}

View file

@ -44,7 +44,7 @@ impl Watcher {
#[cfg(any(target_os = "linux", target_os = "macos"))]
yazi_fs::mounts::Partitions::monitor(yazi_fs::mounts::PARTITIONS.clone(), || {
yazi_macro::err!(yazi_dds::Pubsub::pub_from_mount())
yazi_macro::err!(yazi_dds::Pubsub::pub_after_mount())
});
tokio::spawn(Self::fan_out(out_rx));

View file

@ -66,7 +66,7 @@ impl Yanked {
}
self.version = self.revision;
err!(Pubsub::pub_from_yank(self.cut, &self.urls));
err!(Pubsub::pub_after_yank(self.cut, &self.urls));
true
}
}

View file

@ -54,7 +54,7 @@ impl Tab {
self.parent = Some(self.history.remove_or(&parent));
}
err!(Pubsub::pub_from_cd(self.id, self.cwd()));
err!(Pubsub::pub_after_cd(self.id, self.cwd()));
self.hover(None);
MgrProxy::refresh();

View file

@ -15,7 +15,7 @@ impl Tab {
}
// Publish through DDS
err!(Pubsub::pub_from_hover(self.id, self.hovered().map(|h| &h.url)));
err!(Pubsub::pub_after_hover(self.id, self.hovered().map(|h| &h.url)));
}
fn hover_do(&mut self, url: Url) {

View file

@ -90,7 +90,7 @@ impl Folder {
if !self.update(op) {
return false;
} else if self.stage != old {
err!(Pubsub::pub_from_load(tab, &self.url, self.stage));
err!(Pubsub::pub_after_load(tab, &self.url, self.stage));
}
true
}

View file

@ -24,6 +24,7 @@ anyhow = { workspace = true }
mlua = { workspace = true }
ordered-float = { workspace = true }
parking_lot = { workspace = true }
paste = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }

View file

@ -12,23 +12,21 @@ pub struct BodyBulk<'a> {
}
impl<'a> BodyBulk<'a> {
#[inline]
pub fn borrowed(changes: &HashMap<&'a Url, &'a Url>) -> Body<'a> {
let iter = changes.iter().map(|(&from, &to)| (Cow::Borrowed(from), Cow::Borrowed(to)));
Self { changes: iter.collect() }.into()
pub fn borrowed<I>(changes: I) -> Body<'a>
where
I: Iterator<Item = (&'a Url, &'a Url)>,
{
Self { changes: changes.map(|(from, to)| (from.into(), to.into())).collect() }.into()
}
}
impl BodyBulk<'static> {
#[inline]
pub fn owned(changes: &HashMap<&Url, &Url>) -> Body<'static> {
let changes = changes
.iter()
.map(|(&from, &to)| (Cow::Owned(from.clone()), Cow::Owned(to.clone())))
.collect();
Self { changes }.into()
pub fn owned<'a, I>(changes: I) -> Body<'static>
where
I: Iterator<Item = (&'a Url, &'a Url)>,
{
Self { changes: changes.map(|(from, to)| (from.clone().into(), to.clone().into())).collect() }
.into()
}
}

View file

@ -7,7 +7,6 @@ use super::Body;
pub struct BodyBye;
impl BodyBye {
#[inline]
pub fn owned() -> Body<'static> { Self.into() }
}

View file

@ -15,15 +15,13 @@ pub struct BodyCd<'a> {
}
impl<'a> BodyCd<'a> {
#[inline]
pub fn borrowed(tab: Id, url: &'a Url) -> Body<'a> {
Self { tab, url: Cow::Borrowed(url), dummy: false }.into()
Self { tab, url: url.into(), dummy: false }.into()
}
}
impl BodyCd<'static> {
#[inline]
pub fn dummy(tab: Id) -> Body<'static> {
pub fn owned(tab: Id, _: &Url) -> Body<'static> {
Self { tab, url: Default::default(), dummy: true }.into()
}
}
@ -34,14 +32,11 @@ impl<'a> From<BodyCd<'a>> for Body<'a> {
impl IntoLua for BodyCd<'static> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
if let Some(Cow::Owned(url)) = Some(self.url).filter(|_| !self.dummy) {
lua.create_table_from([
lua
.create_table_from([
("tab", self.tab.get().into_lua(lua)?),
("url", yazi_binding::Url::new(url).into_lua(lua)?),
("url", Some(self.url).filter(|_| !self.dummy).map(yazi_binding::Url::new).into_lua(lua)?),
])?
} else {
lua.create_table_from([("tab", self.tab.get())])?
}
.into_lua(lua)
.into_lua(lua)
}
}

View file

@ -12,12 +12,10 @@ pub struct BodyCustom {
}
impl BodyCustom {
#[inline]
pub fn from_str(kind: &str, data: &str) -> anyhow::Result<Body<'static>> {
Ok(Self { kind: kind.to_owned(), data: serde_json::from_str(data)? }.into())
}
#[inline]
pub fn from_lua(kind: &str, data: Value) -> mlua::Result<Body<'static>> {
Ok(Self { kind: kind.to_owned(), data: Sendable::value_to_data(data)? }.into())
}

View file

@ -12,12 +12,10 @@ pub struct BodyDelete<'a> {
}
impl<'a> BodyDelete<'a> {
#[inline]
pub fn borrowed(urls: &'a Vec<Url>) -> Body<'a> { Self { urls: Cow::Borrowed(urls) }.into() }
}
impl BodyDelete<'static> {
#[inline]
pub fn owned(urls: Vec<Url>) -> Body<'static> { Self { urls: Cow::Owned(urls) }.into() }
}

View file

@ -7,6 +7,7 @@ use yazi_shared::{Id, SStr};
use super::{Body, BodyHi};
use crate::Peer;
/// Server handshake
#[derive(Debug, Serialize, Deserialize)]
pub struct BodyHey {
pub peers: HashMap<Id, Peer>,
@ -14,7 +15,6 @@ pub struct BodyHey {
}
impl BodyHey {
#[inline]
pub fn owned(peers: HashMap<Id, Peer>) -> Body<'static> {
Self { peers, version: BodyHi::version().into() }.into()
}

View file

@ -6,25 +6,22 @@ use yazi_shared::SStr;
use super::Body;
/// The client handshake
/// Client handshake
#[derive(Debug, Serialize, Deserialize)]
pub struct BodyHi<'a> {
/// Specifies the kinds of events that the client can handle
/// Kinds of events the client can handle
pub abilities: HashSet<Cow<'a, str>>,
pub version: SStr,
}
impl<'a> BodyHi<'a> {
#[inline]
pub fn borrowed(abilities: HashSet<&'a str>) -> Body<'a> {
Self {
abilities: abilities.into_iter().map(Cow::Borrowed).collect(),
version: Self::version().into(),
}
.into()
pub fn borrowed<I>(abilities: I) -> Body<'a>
where
I: Iterator<Item = &'a str>,
{
Self { abilities: abilities.map(Into::into).collect(), version: Self::version().into() }.into()
}
#[inline]
pub fn version() -> &'static str {
concat!(env!("CARGO_PKG_VERSION"), " ", env!("VERGEN_GIT_SHA"))
}

View file

@ -13,15 +13,13 @@ pub struct BodyHover<'a> {
}
impl<'a> BodyHover<'a> {
#[inline]
pub fn borrowed(tab: Id, url: Option<&'a Url>) -> Body<'a> {
Self { tab, url: url.map(Cow::Borrowed) }.into()
Self { tab, url: url.map(Into::into) }.into()
}
}
impl BodyHover<'static> {
#[inline]
pub fn dummy(tab: Id) -> Body<'static> { Self { tab, url: None }.into() }
pub fn owned(tab: Id, _: Option<&Url>) -> Body<'static> { Self { tab, url: None }.into() }
}
impl<'a> From<BodyHover<'a>> for Body<'a> {
@ -30,14 +28,11 @@ impl<'a> From<BodyHover<'a>> for Body<'a> {
impl IntoLua for BodyHover<'static> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
if let Some(Cow::Owned(url)) = self.url {
lua.create_table_from([
lua
.create_table_from([
("tab", self.tab.get().into_lua(lua)?),
("url", yazi_binding::Url::new(url).into_lua(lua)?),
("url", self.url.map(yazi_binding::Url::new).into_lua(lua)?),
])?
} else {
lua.create_table_from([("tab", self.tab.get())])?
}
.into_lua(lua)
.into_lua(lua)
}
}

View file

@ -15,16 +15,14 @@ pub struct BodyLoad<'a> {
}
impl<'a> BodyLoad<'a> {
#[inline]
pub fn borrowed(tab: Id, url: &'a Url, stage: FolderStage) -> Body<'a> {
Self { tab, url: Cow::Borrowed(url), stage }.into()
Self { tab, url: url.into(), stage }.into()
}
}
impl BodyLoad<'static> {
#[inline]
pub fn dummy(tab: Id, url: &Url, stage: FolderStage) -> Body<'static> {
Self { tab, url: Cow::Owned(url.clone()), stage }.into()
pub fn owned(tab: Id, url: &Url, stage: FolderStage) -> Body<'static> {
Self { tab, url: url.clone().into(), stage }.into()
}
}
@ -37,7 +35,7 @@ impl IntoLua for BodyLoad<'static> {
lua
.create_table_from([
("tab", self.tab.get().into_lua(lua)?),
("url", yazi_binding::Url::new(self.url.into_owned()).into_lua(lua)?),
("url", yazi_binding::Url::new(self.url).into_lua(lua)?),
("stage", yazi_binding::FolderStage::new(self.stage).into_lua(lua)?),
])?
.into_lua(lua)

View file

@ -7,8 +7,9 @@ use super::Body;
pub struct BodyMount;
impl BodyMount {
#[inline]
pub fn owned() -> Body<'static> { Self.into() }
pub fn borrowed() -> Body<'static> { Self::owned() }
}
impl From<BodyMount> for Body<'_> {

View file

@ -12,14 +12,12 @@ pub struct BodyMove<'a> {
}
impl<'a> BodyMove<'a> {
#[inline]
pub fn borrowed(items: &'a Vec<BodyMoveItem>) -> Body<'a> {
Self { items: Cow::Borrowed(items) }.into()
}
}
impl BodyMove<'static> {
#[inline]
pub fn owned(items: Vec<BodyMoveItem>) -> Body<'static> {
Self { items: Cow::Owned(items) }.into()
}

View file

@ -14,16 +14,14 @@ pub struct BodyRename<'a> {
}
impl<'a> BodyRename<'a> {
#[inline]
pub fn borrowed(tab: Id, from: &'a Url, to: &'a Url) -> Body<'a> {
Self { tab, from: Cow::Borrowed(from), to: Cow::Borrowed(to) }.into()
Self { tab, from: from.into(), to: to.into() }.into()
}
}
impl BodyRename<'static> {
#[inline]
pub fn dummy(tab: Id, from: &Url, to: &Url) -> Body<'static> {
Self { tab, from: Cow::Owned(from.clone()), to: Cow::Owned(to.clone()) }.into()
pub fn owned(tab: Id, from: &Url, to: &Url) -> Body<'static> {
Self { tab, from: from.clone().into(), to: to.clone().into() }.into()
}
}
@ -36,8 +34,8 @@ impl IntoLua for BodyRename<'static> {
lua
.create_table_from([
("tab", self.tab.get().into_lua(lua)?),
("from", yazi_binding::Url::new(self.from.into_owned()).into_lua(lua)?),
("to", yazi_binding::Url::new(self.to.into_owned()).into_lua(lua)?),
("from", yazi_binding::Url::new(self.from).into_lua(lua)?),
("to", yazi_binding::Url::new(self.to).into_lua(lua)?),
])?
.into_lua(lua)
}

View file

@ -10,8 +10,9 @@ pub struct BodyTab {
}
impl BodyTab {
#[inline]
pub fn owned(id: Id) -> Body<'static> { Self { id }.into() }
pub fn borrowed(id: Id) -> Body<'static> { Self::owned(id) }
}
impl From<BodyTab> for Body<'_> {

View file

@ -12,12 +12,10 @@ pub struct BodyTrash<'a> {
}
impl<'a> BodyTrash<'a> {
#[inline]
pub fn borrowed(urls: &'a Vec<Url>) -> Body<'a> { Self { urls: Cow::Borrowed(urls) }.into() }
}
impl BodyTrash<'static> {
#[inline]
pub fn owned(urls: Vec<Url>) -> Body<'static> { Self { urls: Cow::Owned(urls) }.into() }
}

View file

@ -15,16 +15,14 @@ pub struct BodyYank<'a> {
}
impl<'a> BodyYank<'a> {
#[inline]
pub fn borrowed(cut: bool, urls: &'a HashSet<Url>) -> Body<'a> {
Self { cut, urls: Cow::Borrowed(urls), dummy: false }.into()
}
}
impl BodyYank<'static> {
#[inline]
pub fn dummy() -> Body<'static> {
Self { cut: false, urls: Default::default(), dummy: true }.into()
pub fn owned(cut: bool, _: &HashSet<Url>) -> Body<'static> {
Self { cut, urls: Default::default(), dummy: true }.into()
}
}

View file

@ -1,4 +1,4 @@
use std::{collections::{HashMap, HashSet}, mem, str::FromStr};
use std::{collections::{HashMap, HashSet}, iter, mem, str::FromStr};
use anyhow::{Context, Result, bail};
use parking_lot::RwLock;
@ -71,7 +71,7 @@ impl Client {
let payload = try_format!(
"{}\n{kind},{receiver},{ID},{body}\n{}\n",
Payload::new(BodyHi::borrowed(Default::default())),
Payload::new(BodyHi::borrowed(iter::empty())),
Payload::new(BodyBye::owned())
)?;
@ -129,7 +129,7 @@ impl Client {
pub async fn draw(kinds: HashSet<&str>) -> Result<()> {
async fn make(kinds: &HashSet<&str>) -> Result<ClientReader> {
let (lines, mut writer) = Stream::connect().await?;
let hi = Payload::new(BodyHi::borrowed(kinds.clone()));
let hi = Payload::new(BodyHi::borrowed(kinds.iter().copied()));
writer.write_all(try_format!("{hi}\n")?.as_bytes()).await?;
writer.flush().await?;
Ok(lines)
@ -167,7 +167,7 @@ impl Client {
let mut first = true;
loop {
if let Ok(conn) = Stream::connect().await {
Pubsub::pub_from_hi();
Pubsub::pub_inner_hi();
return conn;
}

View file

@ -7,7 +7,7 @@ use yazi_boot::BOOT;
use yazi_fs::FolderStage;
use yazi_shared::{Id, RoCell, url::Url};
use crate::{Client, ID, PEERS, body::{Body, BodyBulk, BodyCd, BodyDelete, BodyHi, BodyHover, BodyLoad, BodyMount, BodyMove, BodyMoveItem, BodyRename, BodyTab, BodyTrash, BodyYank}};
use crate::{Client, ID, PEERS, body::{Body, BodyBulk, BodyHi, BodyMoveItem}};
pub static LOCAL: RoCell<RwLock<HashMap<String, HashMap<String, Function>>>> = RoCell::new();
@ -48,19 +48,53 @@ macro_rules! unsub {
};
}
macro_rules! pub_after {
(&impl $name:ident ($($param:ident: $param_ty:ty),*), ($($borrowed:expr),*), ($($owned:expr),*), $static:literal) => {
paste::paste! {
pub fn [<pub_after_ $name>]($($param: $param_ty),*) -> Result<()> {
use crate::body::[<Body $name:camel>] as B;
let n = if $static { concat!("@", stringify!($name)) } else { stringify!($name) };
if BOOT.local_events.contains(n) {
B::borrowed($($borrowed),*).with_receiver(*ID).flush()?;
}
if ($static && Self::any_remote_own(n)) || (!$static && PEERS.read().values().any(|p| p.able(n))) {
Client::push(B::borrowed($($borrowed),*))?;
}
if LOCAL.read().contains_key(n) {
Self::r#pub(B::owned($($owned),*))?;
}
Ok(())
}
}
};
($name:ident ($($param:ident: $param_ty:ty),*), ($($borrowed:expr),*)) => {
pub_after!(&impl $name($($param: $param_ty),*), ($($borrowed),*), ($($borrowed),*), false);
};
($name:ident ($($param:ident: $param_ty:ty),*), ($($borrowed:expr),*), ($($owned:expr),*)) => {
pub_after!(&impl $name($($param: $param_ty),*), ($($borrowed),*), ($($owned),*), false);
};
(@ $name:ident ($($param:ident: $param_ty:ty),*), ($($borrowed:expr),*)) => {
pub_after!(&impl $name($($param: $param_ty),*), ($($borrowed),*), ($($borrowed),*), true);
};
(@ $name:ident ($($param:ident: $param_ty:ty),*), ($($borrowed:expr),*), ($($owned:expr),*)) => {
pub_after!(&impl $name($($param: $param_ty),*), ($($borrowed),*), ($($owned),*), true);
};
}
pub struct Pubsub;
impl Pubsub {
pub fn sub(plugin: &str, kind: &str, f: Function) -> bool { sub!(LOCAL)(plugin, kind, f) }
pub fn sub_remote(plugin: &str, kind: &str, f: Function) -> bool {
sub!(REMOTE)(plugin, kind, f) && Self::pub_from_hi()
sub!(REMOTE)(plugin, kind, f) && Self::pub_inner_hi()
}
pub fn unsub(plugin: &str, kind: &str) -> bool { unsub!(LOCAL)(plugin, kind) }
pub fn unsub_remote(plugin: &str, kind: &str) -> bool {
unsub!(REMOTE)(plugin, kind) && Self::pub_from_hi()
unsub!(REMOTE)(plugin, kind) && Self::pub_inner_hi()
}
pub fn r#pub(body: Body<'static>) -> Result<()> { body.with_receiver(*ID).emit() }
@ -79,162 +113,57 @@ impl Pubsub {
Ok(())
}
pub fn pub_from_hi() -> bool {
pub fn pub_inner_hi() -> bool {
let abilities = REMOTE.read().keys().cloned().collect();
let abilities = BOOT.remote_events.union(&abilities).map(|s| s.as_str()).collect();
let abilities = BOOT.remote_events.union(&abilities).map(AsRef::as_ref);
// FIXME: handle error
Client::push(BodyHi::borrowed(abilities)).ok();
true
}
pub fn pub_from_tab(idx: Id) -> Result<()> {
if LOCAL.read().contains_key("tab") {
Self::r#pub(BodyTab::owned(idx))?;
}
if PEERS.read().values().any(|p| p.able("tab")) {
Client::push(BodyTab::owned(idx))?;
}
if BOOT.local_events.contains("tab") {
BodyTab::owned(idx).with_receiver(*ID).flush()?;
}
Ok(())
}
pub fn pub_from_cd(tab: Id, url: &Url) -> Result<()> {
if LOCAL.read().contains_key("cd") {
Self::r#pub(BodyCd::dummy(tab))?;
}
if PEERS.read().values().any(|p| p.able("cd")) {
Client::push(BodyCd::borrowed(tab, url))?;
}
if BOOT.local_events.contains("cd") {
BodyCd::borrowed(tab, url).with_receiver(*ID).flush()?;
}
Ok(())
}
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))?;
}
if PEERS.read().values().any(|p| p.able("load")) {
Client::push(BodyLoad::borrowed(tab, url, stage))?;
}
if BOOT.local_events.contains("load") {
BodyLoad::borrowed(tab, url, stage).with_receiver(*ID).flush()?;
}
Ok(())
}
pub fn pub_from_hover(tab: Id, url: Option<&Url>) -> Result<()> {
if LOCAL.read().contains_key("hover") {
Self::r#pub(BodyHover::dummy(tab))?;
}
if PEERS.read().values().any(|p| p.able("hover")) {
Client::push(BodyHover::borrowed(tab, url))?;
}
if BOOT.local_events.contains("hover") {
BodyHover::borrowed(tab, url).with_receiver(*ID).flush()?;
}
Ok(())
}
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))?;
}
if PEERS.read().values().any(|p| p.able("rename")) {
Client::push(BodyRename::borrowed(tab, from, to))?;
}
if BOOT.local_events.contains("rename") {
BodyRename::borrowed(tab, from, to).with_receiver(*ID).flush()?;
}
Ok(())
}
pub fn pub_from_bulk(changes: HashMap<&Url, &Url>) -> Result<()> {
if LOCAL.read().contains_key("bulk") {
Self::r#pub(BodyBulk::owned(&changes))?;
pub fn pub_after_bulk<'a, I>(changes: I) -> Result<()>
where
I: Iterator<Item = (&'a Url, &'a Url)> + Clone,
{
if BOOT.local_events.contains("bulk") {
BodyBulk::borrowed(changes.clone()).with_receiver(*ID).flush()?;
}
if PEERS.read().values().any(|p| p.able("bulk")) {
Client::push(BodyBulk::borrowed(&changes))?;
Client::push(BodyBulk::borrowed(changes.clone()))?;
}
if BOOT.local_events.contains("bulk") {
BodyBulk::borrowed(&changes).with_receiver(*ID).flush()?;
}
Ok(())
}
pub fn pub_from_yank(cut: bool, urls: &HashSet<Url>) -> Result<()> {
if LOCAL.read().contains_key("@yank") {
Self::r#pub(BodyYank::dummy())?;
}
if Self::any_remote_own("@yank") {
Client::push(BodyYank::borrowed(cut, urls))?;
}
if BOOT.local_events.contains("@yank") {
BodyYank::borrowed(cut, urls).with_receiver(*ID).flush()?;
}
Ok(())
}
pub(super) fn pub_from_move(items: Vec<BodyMoveItem>) -> Result<()> {
if PEERS.read().values().any(|p| p.able("move")) {
Client::push(BodyMove::borrowed(&items))?;
}
if BOOT.local_events.contains("move") {
BodyMove::borrowed(&items).with_receiver(*ID).flush()?;
}
if LOCAL.read().contains_key("move") {
Self::r#pub(BodyMove::owned(items))?;
}
Ok(())
}
pub(super) fn pub_from_trash(urls: Vec<Url>) -> Result<()> {
if PEERS.read().values().any(|p| p.able("trash")) {
Client::push(BodyTrash::borrowed(&urls))?;
}
if BOOT.local_events.contains("trash") {
BodyTrash::borrowed(&urls).with_receiver(*ID).flush()?;
}
if LOCAL.read().contains_key("trash") {
Self::r#pub(BodyTrash::owned(urls))?;
}
Ok(())
}
pub(super) fn pub_from_delete(urls: Vec<Url>) -> Result<()> {
if PEERS.read().values().any(|p| p.able("delete")) {
Client::push(BodyDelete::borrowed(&urls))?;
}
if BOOT.local_events.contains("delete") {
BodyDelete::borrowed(&urls).with_receiver(*ID).flush()?;
}
if LOCAL.read().contains_key("delete") {
Self::r#pub(BodyDelete::owned(urls))?;
}
Ok(())
}
pub fn pub_from_mount() -> Result<()> {
if LOCAL.read().contains_key("mount") {
Self::r#pub(BodyMount::owned())?;
}
if PEERS.read().values().any(|p| p.able("mount")) {
Client::push(BodyMount::owned())?;
}
if BOOT.local_events.contains("mount") {
BodyMount::owned().with_receiver(*ID).flush()?;
if LOCAL.read().contains_key("bulk") {
Self::r#pub(BodyBulk::owned(changes))?;
}
Ok(())
}
#[inline]
fn any_remote_own(kind: &str) -> bool {
REMOTE.read().contains_key(kind) // Owned abilities
REMOTE.read().contains_key(kind) // Own remote abilities
|| PEERS.read().values().any(|p| p.able(kind)) // Remote peers' abilities
|| BOOT.remote_events.contains(kind) // Owned abilities from the command-line argument
|| BOOT.remote_events.contains(kind) // Own abilities from the command-line argument
}
}
impl Pubsub {
pub_after!(tab(idx: Id), (idx));
pub_after!(cd(tab: Id, url: &Url), (tab, url));
pub_after!(load(tab: Id, url: &Url, stage: FolderStage), (tab, url, stage));
pub_after!(hover(tab: Id, url: Option<&Url>), (tab, url));
pub_after!(rename(tab: Id, from: &Url, to: &Url), (tab, from, to));
pub_after!(@yank(cut: bool, urls: &HashSet<Url>), (cut, urls));
pub_after!(move(items: Vec<BodyMoveItem>), (&items), (items));
pub_after!(trash(urls: Vec<Url>), (&urls), (urls));
pub_after!(delete(urls: Vec<Url>), (&urls), (urls));
pub_after!(mount(), ());
}

View file

@ -62,9 +62,9 @@ impl Pump {
loop {
select! {
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)),
Some(items) = move_rx.next() => err!(Pubsub::pub_after_move(items)),
Some(urls) = trash_rx.next() => err!(Pubsub::pub_after_trash(urls)),
Some(urls) = delete_rx.next() => err!(Pubsub::pub_after_delete(urls)),
else => {
CT.cancel();
break;

View file

@ -122,6 +122,18 @@ impl From<&Url> for String {
fn from(url: &Url) -> Self { url.to_string() }
}
impl<'a> From<&'a Url> for Cow<'a, Url> {
fn from(url: &'a Url) -> Self { Cow::Borrowed(url) }
}
impl From<Url> for Cow<'_, Url> {
fn from(url: Url) -> Self { Cow::Owned(url) }
}
impl From<Cow<'static, Url>> for Url {
fn from(url: Cow<'static, Url>) -> Self { url.into_owned() }
}
impl Url {
#[inline]
pub fn join(&self, path: impl AsRef<Path>) -> Self {