use std::io::Write;
pub fn osc52(text: &str) -> String {
format!("\x1b]52;c;{}\x07", base64(text.as_bytes()))
}
pub fn base64(bytes: &[u8]) -> String {
const TABLE: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut out = String::with_capacity(bytes.len().div_ceil(3) * 4);
for chunk in bytes.chunks(3) {
let b = [
chunk[0],
*chunk.get(1).unwrap_or(&0),
*chunk.get(2).unwrap_or(&0),
];
let n = (u32::from(b[0]) << 16) | (u32::from(b[1]) << 8) | u32::from(b[2]);
out.push(TABLE[(n >> 18) as usize & 63] as char);
out.push(TABLE[(n >> 12) as usize & 63] as char);
out.push(if chunk.len() > 1 {
TABLE[(n >> 6) as usize & 63] as char
} else {
'='
});
out.push(if chunk.len() > 2 {
TABLE[n as usize & 63] as char
} else {
'='
});
}
out
}
#[cfg(feature = "clipboard")]
fn system(text: &str) -> Result<(), String> {
let mut cb = arboard::Clipboard::new().map_err(|e| e.to_string())?;
cb.set_text(text.to_string()).map_err(|e| e.to_string())
}
#[cfg(not(feature = "clipboard"))]
fn system(_text: &str) -> Result<(), String> {
Err("built without the clipboard feature".to_string())
}
pub fn copy(out: &mut impl Write, text: &str) -> Result<&'static str, String> {
match system(text) {
Ok(()) => Ok("the clipboard"),
Err(system_err) => {
out.write_all(osc52(text).as_bytes())
.and_then(|_| out.flush())
.map_err(|e| format!("{system_err}; OSC 52 failed too: {e}"))?;
Ok("the terminal clipboard (OSC 52)")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn base64_matches_the_standard() {
assert_eq!(base64(b""), "");
assert_eq!(base64(b"f"), "Zg==");
assert_eq!(base64(b"fo"), "Zm8=");
assert_eq!(base64(b"foo"), "Zm9v");
assert_eq!(base64(b"foobar"), "Zm9vYmFy");
assert_eq!(base64("héllo".as_bytes()), "aMOpbGxv");
}
#[test]
fn osc52_shape() {
assert_eq!(osc52("hi"), "\x1b]52;c;aGk=\x07");
}
}