use std::io::Write;
pub fn osc52_copy(text: &str) {
let sequence = osc52_sequence(text);
let mut out = std::io::stdout();
let _ = out.write_all(sequence.as_bytes());
let _ = out.flush();
}
fn osc52_sequence(text: &str) -> String {
format!("\x1b]52;c;{}\x07", base64_encode(text.as_bytes()))
}
fn base64_encode(input: &[u8]) -> String {
const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
for chunk in input.chunks(3) {
let b0 = chunk[0] as u32;
let b1 = chunk.get(1).copied().unwrap_or(0) as u32;
let b2 = chunk.get(2).copied().unwrap_or(0) as u32;
let triple = (b0 << 16) | (b1 << 8) | b2;
out.push(ALPHABET[(triple >> 18 & 0x3f) as usize] as char);
out.push(ALPHABET[(triple >> 12 & 0x3f) as usize] as char);
out.push(if chunk.len() > 1 {
ALPHABET[(triple >> 6 & 0x3f) as usize] as char
} else {
'='
});
out.push(if chunk.len() > 2 {
ALPHABET[(triple & 0x3f) as usize] as char
} else {
'='
});
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn base64_matches_known_vectors() {
assert_eq!(base64_encode(b""), "");
assert_eq!(base64_encode(b"f"), "Zg==");
assert_eq!(base64_encode(b"fo"), "Zm8=");
assert_eq!(base64_encode(b"foo"), "Zm9v");
assert_eq!(base64_encode(b"M"), "TQ==");
assert_eq!(base64_encode(b"Ma"), "TWE=");
assert_eq!(base64_encode(b"Man"), "TWFu");
}
#[test]
fn osc52_sequence_is_framed() {
let seq = osc52_sequence("Man");
assert_eq!(seq, "\x1b]52;c;TWFu\x07");
assert!(seq.starts_with("\x1b]52;c;"));
assert!(seq.ends_with('\x07'));
}
}