use base64::Engine as _;
use super::super::{ClipboardTarget, Screen, ScreenEvent};
pub(in crate::screen) fn handle_set(screen: &mut Screen, params: &[&[u8]]) {
let pc = params.get(1).copied().unwrap_or(b"");
let pd = params.get(2).copied().unwrap_or(b"");
let targets = parse_targets(pc);
let cap = screen.host_profile.clipboard_max_bytes;
let event = if pd == b"?" {
ScreenEvent::ClipboardQuery { targets }
} else if pd.is_empty() {
ScreenEvent::ClipboardClear { targets }
} else if pd.len().saturating_mul(3) / 4 > cap {
ScreenEvent::ClipboardWriteRejected {
targets,
decoded_len: pd.len().saturating_mul(3) / 4,
}
} else {
match base64::engine::general_purpose::STANDARD.decode(pd) {
Ok(data) if data.len() > cap => ScreenEvent::ClipboardWriteRejected {
targets,
decoded_len: data.len(),
},
Ok(data) => ScreenEvent::ClipboardWrite { targets, data },
Err(err) => {
tracing::debug!(?err, "dropping OSC 52 write with invalid base64");
return;
}
}
};
screen.pending_events.push(event);
}
pub(in crate::screen) fn parse_targets(pc: &[u8]) -> Vec<ClipboardTarget> {
if pc.is_empty() {
return vec![ClipboardTarget::Select, ClipboardTarget::CutBuffer(0)];
}
let mut out: Vec<ClipboardTarget> = Vec::with_capacity(pc.len());
for &byte in pc {
let target = match byte {
b'c' => ClipboardTarget::Clipboard,
b'p' => ClipboardTarget::Primary,
b'q' => ClipboardTarget::Secondary,
b's' => ClipboardTarget::Select,
b'0'..=b'7' => ClipboardTarget::CutBuffer(byte - b'0'),
_ => continue,
};
if !out.contains(&target) {
out.push(target);
}
}
if out.is_empty() {
return vec![ClipboardTarget::Select, ClipboardTarget::CutBuffer(0)];
}
out
}