use std::io::Write;
use std::process::{Command, Stdio};
pub fn copy(text: &str) -> Result<(), String> {
#[cfg(target_os = "macos")]
{
run_with_stdin("pbcopy", &[], text)
}
#[cfg(target_os = "linux")]
{
match run_with_stdin("wl-copy", &[], text) {
Ok(()) => Ok(()),
Err(_) => run_with_stdin("xclip", &["-selection", "clipboard"], text),
}
}
#[cfg(target_os = "windows")]
{
run_with_stdin("clip", &[], text)
}
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
{
let _ = text;
Err("clipboard not supported on this platform".to_string())
}
}
fn run_with_stdin(program: &str, args: &[&str], text: &str) -> Result<(), String> {
let mut child = match Command::new(program)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
{
Ok(c) => c,
Err(e) => {
tracing::debug!(error = %e, program, "clipboard tool not found");
return Err(format!("clipboard tool not found ({program})"));
}
};
if let Some(mut stdin) = child.stdin.take() {
if let Err(e) = stdin.write_all(text.as_bytes()) {
tracing::debug!(error = %e, program, "clipboard write failed");
return Err(format!("clipboard write failed: {e}"));
}
}
match child.wait() {
Ok(status) if status.success() => Ok(()),
Ok(status) => Err(format!("clipboard tool exited {status}")),
Err(e) => Err(format!("clipboard wait failed: {e}")),
}
}