use pnc_engine::clipboard::Clipboard;
use pnc_engine::error::PncError;
use std::io::Write;
use std::process::{Command, Stdio};
pub fn copy(text: &str) -> Result<(), String> {
let tools: &[(&str, &[&str])] = &[
("xclip", &["-selection", "clipboard"]),
("xsel", &["--clipboard", "--input"]),
("wl-copy", &[]),
("pbcopy", &[]),
];
for (tool, args) in tools {
if let Ok(mut child) = Command::new(tool)
.args(*args)
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
{
if let Some(stdin) = child.stdin.as_mut() {
let _ = stdin.write_all(text.as_bytes());
}
if child.wait().map(|s| s.success()).unwrap_or(false) {
return Ok(());
}
}
}
let encoded = base64_encode(text);
let seq = format!("\x1b]52;c;{}\x07", encoded);
let _ = write!(std::io::stdout(), "{}", seq);
let _ = std::io::stdout().flush();
Ok(())
}
pub fn paste() -> Result<String, String> {
let tools: &[(&str, &[&str])] = &[
("xclip", &["-selection", "clipboard", "-o"]),
("xsel", &["--clipboard", "--output"]),
("wl-paste", &[]),
("pbpaste", &[]),
];
for (tool, args) in tools {
if let Ok(out) = Command::new(tool).args(*args).output() {
if out.status.success() {
return Ok(String::from_utf8_lossy(&out.stdout).to_string());
}
}
}
Err("clipboard unavailable".to_string())
}
fn base64_encode(input: &str) -> String {
const TABLE: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let bytes = input.as_bytes();
let mut out = String::new();
for chunk in bytes.chunks(3) {
let b0 = chunk[0] as usize;
let b1 = chunk.get(1).copied().unwrap_or(0) as usize;
let b2 = chunk.get(2).copied().unwrap_or(0) as usize;
out.push(TABLE[b0 >> 2] as char);
out.push(TABLE[((b0 & 3) << 4) | (b1 >> 4)] as char);
if chunk.len() > 1 {
out.push(TABLE[((b1 & 15) << 2) | (b2 >> 6)] as char);
} else {
out.push('=');
}
if chunk.len() > 2 {
out.push(TABLE[b2 & 63] as char);
} else {
out.push('=');
}
}
out
}
pub struct SystemClipboard;
impl Clipboard for SystemClipboard {
fn get(&mut self) -> Result<String, PncError> {
paste().map_err(|_| PncError::ClipboardUnavailable)
}
fn set(&mut self, text: String) -> Result<(), PncError> {
copy(&text).map_err(|_| PncError::ClipboardUnavailable)
}
}