use std::io::Write;
use std::process::{Command, Stdio};
use super::*;
pub(super) fn copy_clipboard(text: &str) -> Option<&'static str> {
let tools: [(&str, &[&str]); 5] = [
("wl-copy", &[]),
("xclip", &["-selection", "clipboard"]),
("xsel", &["--clipboard", "--input"]),
("pbcopy", &[]),
("clip.exe", &[]),
];
for (bin, args) in tools {
let Ok(mut child) = Command::new(bin)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
else {
continue;
};
if let Some(mut stdin) = child.stdin.take() {
let _ = stdin.write_all(text.as_bytes());
}
if child.wait().map(|s| s.success()).unwrap_or(false) {
return Some(bin);
}
}
let mut out = stdout();
if write!(out, "\x1b]52;c;{}\x07", base64(text.as_bytes()))
.and_then(|_| out.flush())
.is_ok()
{
return Some("osc52");
}
None
}
pub(super) fn base64(data: &[u8]) -> String {
const T: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut s = String::with_capacity(data.len().div_ceil(3) * 4);
for chunk in data.chunks(3) {
let b = [
chunk[0],
*chunk.get(1).unwrap_or(&0),
*chunk.get(2).unwrap_or(&0),
];
let n = (b[0] as u32) << 16 | (b[1] as u32) << 8 | b[2] as u32;
s.push(T[(n >> 18 & 63) as usize] as char);
s.push(T[(n >> 12 & 63) as usize] as char);
s.push(if chunk.len() > 1 {
T[(n >> 6 & 63) as usize] as char
} else {
'='
});
s.push(if chunk.len() > 2 {
T[(n & 63) as usize] as char
} else {
'='
});
}
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn base64_matches_known_vectors() {
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"WireGuard"), "V2lyZUd1YXJk");
}
}