use std::{fmt::{self, Display}, str}; use base64::Engine; use yazi_shim::BASE64_SANE; use super::traits::Mimelist; /// Enable drag support: `OSC 72 ; t=o:x=1 ; machine id ST` pub struct EnableDrag<'a>(pub &'a str); impl Display for EnableDrag<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\x1b]72;t=o:x=1;{}\x1b\\", self.0) } } /// Enable drop support: `OSC 72 ; t=a ; MIME list ST` pub struct EnableDrop(pub M); impl Display for EnableDrop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\x1b]72;t=a;{}\x1b\\", ListDndMimes(self.0.clone())) } } /// Disable drag support: `OSC 72 ; t=o:x=2 ST` pub struct DisableDrag; impl Display for DisableDrag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("\x1b]72;t=o:x=2\x1b\\") } } /// Disable drop support: `OSC 72 ; t=A ST` pub struct DisableDrop; impl Display for DisableDrop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("\x1b]72;t=A\x1b\\") } } /// Agree drag: `OSC 72 ; t=o:o=operation ST` pub enum AgreeDrag { Copy(M), Move(M), Either(M), } impl Display for AgreeDrag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Copy(mimes) => write!(f, "\x1b]72;t=o:o=1;{}\x1b\\", ListDndMimes(mimes.clone())), Self::Move(mimes) => write!(f, "\x1b]72;t=o:o=2;{}\x1b\\", ListDndMimes(mimes.clone())), Self::Either(mimes) => write!(f, "\x1b]72;t=o:o=3;{}\x1b\\", ListDndMimes(mimes.clone())), } } } /// Agree drop: `OSC 72 ; t=m:o=O ; MIME list ST` pub enum AgreeDrop { Reject, Copy(M), Move(M), } impl Display for AgreeDrop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Reject => write!(f, "\x1b]72;t=m:o=0\x1b\\"), Self::Copy(mimes) => write!(f, "\x1b]72;t=m:o=1;{}\x1b\\", ListDndMimes(mimes.clone())), Self::Move(mimes) => write!(f, "\x1b]72;t=m:o=2;{}\x1b\\", ListDndMimes(mimes.clone())), } } } /// Start dragging: `OSC 72 ; t=P:x=-1 ST` pub struct StartDrag; impl Display for StartDrag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("\x1b]72;t=P:x=-1\x1b\\") } } /// Start requesting dropped data: `OSC 72 ; t=r:x=idx ST` pub struct StartDrop(pub u8); impl Display for StartDrop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\x1b]72;t=r:x={}\x1b\\", self.0) } } /// Present drag data: `OSC 72 ; t=p:x=idx ; base64 encoded data ST` pub struct PresentDrag<'a>(pub u8, pub &'a [u8]); impl Display for PresentDrag<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let b64 = BASE64_SANE.encode(self.1).into_bytes(); let chunks = b64.len().div_ceil(4096); for (i, chunk) in b64.chunks(4096).enumerate() { let s = unsafe { str::from_utf8_unchecked(chunk) }; if i == 0 { write!(f, "\x1b]72;t=p:x={}:m={};{s}\x1b\\", self.0, (chunks > 1) as u8)?; } else { write!(f, "\x1b]72;m={};{s}\x1b\\", (i + 1 < chunks) as u8)?; } } write!(f, "\x1b]72;t=p:x={}\x1b\\", self.0) } } /// Present drag icon data: /// `OSC 72 ; t=p:x=-1:y=fmt:X=width:Y=height:o=opacity ; base64 payload ST` pub struct PresentDragIcon<'a> { pub format: u8, pub opacity: u16, pub width: u32, pub height: u32, pub data: &'a [u8], } impl Display for PresentDragIcon<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let b64 = BASE64_SANE.encode(self.data).into_bytes(); let chunks = b64.len().div_ceil(4096); for (i, chunk) in b64.chunks(4096).enumerate() { let s = unsafe { str::from_utf8_unchecked(chunk) }; if i == 0 { write!( f, "\x1b]72;t=p:x=-1:y={}:X={}:Y={}:o={}:m={};{s}\x1b\\", self.format, self.width, self.height, self.opacity, (chunks > 1) as u8 )?; } else { write!(f, "\x1b]72;m={};{s}\x1b\\", (i + 1 < chunks) as u8)?; } } Ok(()) } } /// Finish requesting dropped data: `OSC 72 ; t=r:o=operation ST` #[derive(Clone, Copy)] pub enum FinishDrop { Copy = 1, Move = 2, } impl Display for FinishDrop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\x1b]72;t=r:o={}\x1b\\", *self as u8) } } /// Write MIME types separated by spaces. struct ListDndMimes(pub M); impl Display for ListDndMimes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (i, m) in self.0.clone().into_iter().enumerate() { if i != 0 { write!(f, " ")?; } write!(f, "{m}")?; } Ok(()) } }