yazi/yazi-tty/src/sequence/dnd.rs
2026-06-18 15:06:31 +08:00

173 lines
4.4 KiB
Rust

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<M>(pub M);
impl<M: Mimelist> Display for EnableDrop<M> {
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<M> {
Copy(M),
Move(M),
Either(M),
}
impl<M: Mimelist> Display for AgreeDrag<M> {
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<M> {
Reject,
Copy(M),
Move(M),
}
impl<M: Mimelist> Display for AgreeDrop<M> {
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<M>(pub M);
impl<M: Mimelist> Display for ListDndMimes<M> {
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(())
}
}