use std::{fmt::Display, io::Write, str::FromStr}; use anyhow::{Result, anyhow}; use mlua::{IntoLua, Lua, Value}; use yazi_boot::BOOT; use yazi_macro::{emit, impl_data_any, relay}; use yazi_shared::{event::ActionCow, id::Id}; use crate::{ID, ember::Ember}; #[derive(Clone, Debug)] pub struct Payload<'a> { pub receiver: Id, pub sender: Id, pub body: Ember<'a>, } impl_data_any!(Payload<'static>); impl<'a> Payload<'a> { pub fn new(body: Ember<'a>) -> Self { Self { receiver: Id::ZERO, sender: *ID, body } } pub(super) fn flush(&self) -> Result<()> { writeln!(std::io::stdout(), "{self}")?; Ok(()) } pub(super) fn try_flush(&self) -> Result<()> { let b = if self.receiver == 0 { BOOT.remote_events.contains(self.body.kind()) } else if let Ember::Custom(b) = &self.body { BOOT.local_events.contains(&b.kind) } else { false }; if b { self.flush() } else { Ok(()) } } pub(super) fn with_receiver(mut self, receiver: Id) -> Self { self.receiver = receiver; self } pub(super) fn with_sender(mut self, sender: Id) -> Self { self.sender = sender; self } } impl Payload<'static> { pub(super) fn emit(self) { emit!(Call(relay!(app:accept_payload).with_any("payload", self))); } } impl FromStr for Payload<'static> { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let mut parts = s.splitn(4, ','); let kind = parts.next().ok_or_else(|| anyhow!("empty kind"))?; let receiver = parts.next().and_then(|s| s.parse().ok()).ok_or_else(|| anyhow!("invalid receiver"))?; let sender = parts.next().and_then(|s| s.parse().ok()).ok_or_else(|| anyhow!("invalid sender"))?; let body = parts.next().ok_or_else(|| anyhow!("empty body"))?; Ok(Self { receiver, sender, body: Ember::from_str(kind, body)? }) } } impl<'a> From> for Payload<'a> { fn from(value: Ember<'a>) -> Self { Self::new(value) } } impl TryFrom for Payload<'_> { type Error = anyhow::Error; fn try_from(mut a: ActionCow) -> Result { a.take_any2("payload").ok_or_else(|| anyhow!("Missing 'payload' in Payload"))? } } impl Display for Payload<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let result = match &self.body { Ember::Hi(b) => serde_json::to_string(b), Ember::Hey(b) => serde_json::to_string(b), Ember::Bye(b) => serde_json::to_string(b), Ember::Cd(b) => serde_json::to_string(b), Ember::Load(b) => serde_json::to_string(b), Ember::Hover(b) => serde_json::to_string(b), Ember::Tab(b) => serde_json::to_string(b), Ember::Rename(b) => serde_json::to_string(b), Ember::BulkRename(b) => serde_json::to_string(b), Ember::Yank(b) => serde_json::to_string(b), Ember::Duplicate(b) => serde_json::to_string(b), Ember::Move(b) => serde_json::to_string(b), Ember::Trash(b) => serde_json::to_string(b), Ember::Delete(b) => serde_json::to_string(b), Ember::Download(b) => serde_json::to_string(b), Ember::Input(b) => serde_json::to_string(b), Ember::Mount(b) => serde_json::to_string(b), Ember::Custom(b) => serde_json::to_string(b), }; if let Ok(s) = result { write!(f, "{},{},{},{s}", self.body.kind(), self.receiver, self.sender) } else { Err(std::fmt::Error) } } } impl<'a> IntoLua for Payload<'a> { fn into_lua(self, lua: &Lua) -> mlua::Result { lua .create_table_from([ ("receiver", self.receiver.into_lua(lua)?), ("sender", self.sender.into_lua(lua)?), ("body", self.body.into_lua(lua)?), ])? .into_lua(lua) } }