feat: split ya send into ya pub and ya pub-static to make it more ergonomic (#933)

This commit is contained in:
三咲雅 · Misaki Masa 2024-04-21 09:25:38 +08:00 committed by GitHub
parent 55da9e342c
commit 68da8998aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 129 additions and 56 deletions

1
Cargo.lock generated
View file

@ -2734,6 +2734,7 @@ dependencies = [
"clap_complete", "clap_complete",
"clap_complete_fig", "clap_complete_fig",
"clap_complete_nushell", "clap_complete_nushell",
"serde_json",
"tokio", "tokio",
"yazi-dds", "yazi-dds",
] ]

View file

@ -17,18 +17,18 @@ pub struct Args {
pub chooser_file: Option<PathBuf>, pub chooser_file: Option<PathBuf>,
/// Clear the cache directory /// Clear the cache directory
#[arg(long, action)] #[arg(long)]
pub clear_cache: bool, pub clear_cache: bool,
/// Report the specified local events to stdout /// Report the specified local events to stdout
#[arg(long, action)] #[arg(long)]
pub local_events: Option<String>, pub local_events: Option<String>,
/// Report the specified remote events to stdout /// Report the specified remote events to stdout
#[arg(long, action)] #[arg(long)]
pub remote_events: Option<String>, pub remote_events: Option<String>,
/// Print debug information /// Print debug information
#[arg(long, action)] #[arg(long)]
pub debug: bool, pub debug: bool,
/// Print version /// Print version

View file

@ -12,15 +12,18 @@ repository = "https://github.com/sxyazi/yazi"
yazi-dds = { path = "../yazi-dds", version = "0.2.4" } yazi-dds = { path = "../yazi-dds", version = "0.2.4" }
# External dependencies # External dependencies
anyhow = "1.0.82" anyhow = "1.0.82"
clap = { version = "4.5.4", features = [ "derive" ] } clap = { version = "4.5.4", features = [ "derive" ] }
tokio = { version = "1.37.0", features = [ "full" ] } serde_json = "1.0.116"
tokio = { version = "1.37.0", features = [ "full" ] }
[build-dependencies] [build-dependencies]
anyhow = "1.0.82"
clap = { version = "4.5.4", features = [ "derive" ] } clap = { version = "4.5.4", features = [ "derive" ] }
clap_complete = "4.5.2" clap_complete = "4.5.2"
clap_complete_nushell = "4.5.1"
clap_complete_fig = "4.5.0" clap_complete_fig = "4.5.0"
clap_complete_nushell = "4.5.1"
serde_json = "1.0.116"
[[bin]] [[bin]]
name = "ya" name = "ya"

View file

@ -1,7 +1,10 @@
use std::borrow::Cow;
use anyhow::{bail, Result};
use clap::{command, Parser, Subcommand}; use clap::{command, Parser, Subcommand};
#[derive(Parser)] #[derive(Parser)]
#[command(name = "ya",version, about, long_about = None)] #[command(name = "ya", version, about, long_about = None)]
#[command(propagate_version = true)] #[command(propagate_version = true)]
pub(super) struct Args { pub(super) struct Args {
#[command(subcommand)] #[command(subcommand)]
@ -10,11 +13,66 @@ pub(super) struct Args {
#[derive(Subcommand)] #[derive(Subcommand)]
pub(super) enum Command { pub(super) enum Command {
/// Send a message to remote instances. /// Publish a message to remote instance(s).
Send(CommandSend), Pub(CommandPub),
/// Publish a static message to all remote instances.
PubStatic(CommandPubStatic),
} }
#[derive(clap::Args)] #[derive(clap::Args)]
pub(super) struct CommandSend { pub(super) struct CommandPub {
pub(super) message: String, /// The receiver ID.
#[arg(index = 1)]
pub(super) receiver: u64,
/// The kind of message.
#[arg(index = 2)]
pub(super) kind: String,
/// Send the message with a string body.
#[arg(long)]
pub(super) str: Option<String>,
/// Send the message with a JSON body.
#[arg(long)]
pub(super) json: Option<String>,
}
impl CommandPub {
#[allow(dead_code)]
pub(super) fn body(&self) -> Result<Cow<str>> {
if let Some(json) = &self.json {
Ok(json.into())
} else if let Some(str) = &self.str {
Ok(serde_json::to_string(str)?.into())
} else {
bail!("No body provided");
}
}
}
#[derive(clap::Args)]
pub(super) struct CommandPubStatic {
/// The severity of the message.
#[arg(index = 1)]
pub(super) severity: u16,
/// The kind of message.
#[arg(index = 2)]
pub(super) kind: String,
/// Send the message with a string body.
#[arg(long)]
pub(super) str: Option<String>,
/// Send the message with a JSON body.
#[arg(long)]
pub(super) json: Option<String>,
}
impl CommandPubStatic {
#[allow(dead_code)]
pub(super) fn body(&self) -> Result<Cow<str>> {
if let Some(json) = &self.json {
Ok(json.into())
} else if let Some(str) = &self.str {
Ok(serde_json::to_string(str)?.into())
} else {
bail!("No body provided");
}
}
} }

View file

@ -8,9 +8,16 @@ async fn main() -> anyhow::Result<()> {
let args = Args::parse(); let args = Args::parse();
match &args.command { match &args.command {
Command::Send(cmd) => { Command::Pub(cmd) => {
yazi_dds::init(); yazi_dds::init();
if let Err(e) = yazi_dds::Client::shot(&cmd.message).await { if let Err(e) = yazi_dds::Client::shot(&cmd.kind, cmd.receiver, None, &cmd.body()?).await {
eprintln!("Cannot send message: {e}");
std::process::exit(1);
}
}
Command::PubStatic(cmd) => {
yazi_dds::init();
if let Err(e) = yazi_dds::Client::shot(&cmd.kind, 0, Some(cmd.severity), &cmd.body()?).await {
eprintln!("Cannot send message: {e}"); eprintln!("Cannot send message: {e}");
std::process::exit(1); std::process::exit(1);
} }

View file

@ -38,7 +38,7 @@ tab_width = 1
# Count # Count
count_copied = { fg = "white", bg = "green" } count_copied = { fg = "white", bg = "green" }
count_cut = { fg = "white", bg = "red" } count_cut = { fg = "white", bg = "red" }
count_selected = { fg = "white", bg = "blue" } count_selected = { fg = "white", bg = "yellow" }
# Border # Border
border_symbol = "│" border_symbol = "│"

View file

@ -1,4 +1,4 @@
use anyhow::Result; use anyhow::{bail, Result};
use mlua::{ExternalResult, IntoLua, Lua, Value}; use mlua::{ExternalResult, IntoLua, Lua, Value};
use serde::Serialize; use serde::Serialize;
@ -40,15 +40,9 @@ impl Body<'static> {
}) })
} }
pub fn from_lua(kind: &str, value: Value) -> Result<Self> { pub fn from_lua(kind: &str, value: Value) -> mlua::Result<Self> {
Ok(match kind { Self::validate(kind).into_lua_err()?;
"hi" | "hey" | "bye" | "cd" | "hover" | "rename" | "bulk" | "yank" | "move" | "trash" BodyCustom::from_lua(kind, value)
| "delete" => Err("Cannot construct system event").into_lua_err()?,
_ if !kind.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-') => {
Err("Kind must be alphanumeric with dashes").into_lua_err()?
}
_ => BodyCustom::from_lua(kind, value)?,
})
} }
pub fn tab(kind: &str, body: &str) -> usize { pub fn tab(kind: &str, body: &str) -> usize {
@ -65,6 +59,27 @@ impl Body<'static> {
_ => 0, _ => 0,
} }
} }
pub fn validate(kind: &str) -> Result<()> {
if matches!(
kind,
"hi"
| "hey" | "bye"
| "cd" | "hover"
| "rename"
| "bulk" | "yank"
| "move" | "trash"
| "delete"
) {
bail!("Cannot construct system event");
}
if !kind.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-') {
bail!("Kind must be alphanumeric with dashes");
}
Ok(())
}
} }
impl<'a> Body<'a> { impl<'a> Body<'a> {

View file

@ -1,6 +1,6 @@
use std::{collections::{HashMap, HashSet}, mem, str::FromStr}; use std::{collections::{HashMap, HashSet}, mem, str::FromStr};
use anyhow::{bail, Result}; use anyhow::Result;
use parking_lot::RwLock; use parking_lot::RwLock;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time}; use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time};
@ -62,16 +62,13 @@ impl Client {
}); });
} }
pub async fn shot(s: &str) -> Result<()> { pub async fn shot(kind: &str, receiver: u64, severity: Option<u16>, body: &str) -> Result<()> {
let (kind, receiver, sender, body) = Payload::split(s)?; Body::validate(kind)?;
if receiver != 0 && sender <= u16::MAX as u64 {
bail!("Sender must be greater than 65535 if receiver is non-zero");
}
let sender = severity.map(Into::into).unwrap_or(*ID);
let payload = format!( let payload = format!(
"{}\n{kind},{receiver},{sender},{}\n{}\n", "{}\n{kind},{receiver},{sender},{body}\n{}\n",
Payload::new(BodyHi::borrowed(Default::default())), Payload::new(BodyHi::borrowed(Default::default())),
serde_json::to_string(body)?,
Payload::new(BodyBye::borrowed()) Payload::new(BodyBye::borrowed())
); );
@ -81,7 +78,7 @@ impl Client {
drop(writer); drop(writer);
while let Ok(Some(s)) = lines.next_line().await { while let Ok(Some(s)) = lines.next_line().await {
if matches!(Payload::split(&s), Ok((kind, ..)) if kind == "bye") { if matches!(s.split(',').next(), Some(kind) if kind == "bye") {
break; break;
} }
} }

View file

@ -49,7 +49,16 @@ impl<'a> Payload<'a> {
} }
impl Payload<'static> { impl Payload<'static> {
pub fn split(s: &str) -> Result<(&str, u64, u64, &str)> { pub(super) fn emit(self) {
self.try_flush();
emit!(Call(Cmd::new("accept_payload").with_any("payload", self), Layer::App));
}
}
impl FromStr for Payload<'static> {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.splitn(4, ','); let mut parts = s.splitn(4, ',');
let kind = parts.next().ok_or_else(|| anyhow!("empty kind"))?; let kind = parts.next().ok_or_else(|| anyhow!("empty kind"))?;
@ -62,20 +71,6 @@ impl Payload<'static> {
let body = parts.next().ok_or_else(|| anyhow!("empty body"))?; let body = parts.next().ok_or_else(|| anyhow!("empty body"))?;
Ok((kind, receiver, sender, body))
}
pub(super) fn emit(self) {
self.try_flush();
emit!(Call(Cmd::new("accept_payload").with_any("payload", self), Layer::App));
}
}
impl FromStr for Payload<'static> {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (kind, receiver, sender, body) = Self::split(s)?;
Ok(Self { receiver, sender, body: Body::from_str(kind, body)? }) Ok(Self { receiver, sender, body: Body::from_str(kind, body)? })
} }
} }

View file

@ -12,7 +12,7 @@ impl Pubsub {
ps.raw_set( ps.raw_set(
"pub", "pub",
lua.create_function(|_, (kind, value): (mlua::String, Value)| { lua.create_function(|_, (kind, value): (mlua::String, Value)| {
yazi_dds::Pubsub::pub_(Body::from_lua(kind.to_str()?, value).into_lua_err()?); yazi_dds::Pubsub::pub_(Body::from_lua(kind.to_str()?, value)?);
Ok(()) Ok(())
})?, })?,
)?; )?;
@ -20,7 +20,7 @@ impl Pubsub {
ps.raw_set( ps.raw_set(
"pub_to", "pub_to",
lua.create_function(|_, (receiver, kind, value): (u64, mlua::String, Value)| { lua.create_function(|_, (receiver, kind, value): (u64, mlua::String, Value)| {
yazi_dds::Pubsub::pub_to(receiver, Body::from_lua(kind.to_str()?, value).into_lua_err()?); yazi_dds::Pubsub::pub_to(receiver, Body::from_lua(kind.to_str()?, value)?);
Ok(()) Ok(())
})?, })?,
)?; )?;
@ -28,10 +28,7 @@ impl Pubsub {
ps.raw_set( ps.raw_set(
"pub_static", "pub_static",
lua.create_function(|_, (severity, kind, value): (u16, mlua::String, Value)| { lua.create_function(|_, (severity, kind, value): (u16, mlua::String, Value)| {
yazi_dds::Pubsub::pub_static( yazi_dds::Pubsub::pub_static(severity, Body::from_lua(kind.to_str()?, value)?);
severity,
Body::from_lua(kind.to_str()?, value).into_lua_err()?,
);
Ok(()) Ok(())
})?, })?,
)?; )?;