use std::io::Write;
pub fn copy(text: &str) {
if let Ok(path) = std::env::var("ROOTLE_CLIPBOARD") {
let outcome = std::fs::write(path, text);
rootle_trace::record_with(rootle_trace::EventKind::ExternalCommand, || {
serde_json::json!({"operation":"clipboard_file", "phase":"finished", "bytes":text.len(),
"success":outcome.is_ok(),
"error_kind":outcome.as_ref().err().map(|error|format!("{:?}",error.kind()))})
});
return;
}
osc52(text);
local_tool(text);
}
fn osc52(text: &str) {
use base64::Engine;
let encoded = base64::engine::general_purpose::STANDARD.encode(text);
let mut out = std::io::stdout();
let written = write!(out, "\x1b]52;c;{encoded}\x07");
let flushed = out.flush();
rootle_trace::record_with(rootle_trace::EventKind::ExternalCommand, || {
serde_json::json!({"operation":"clipboard_osc52", "phase":"written", "bytes":text.len(),
"success":written.is_ok() && flushed.is_ok(),
"error_kind":written.as_ref().err().or_else(||flushed.as_ref().err()).map(|error|format!("{:?}",error.kind()))})
});
}
fn local_tool(text: &str) {
use std::process::{Command, Stdio};
for (program, flag) in [
("wl-copy", None),
("xclip", Some("-selection")),
("xsel", Some("--clipboard")),
] {
let mut cmd = Command::new(program);
if let Some(flag) = flag {
cmd.arg(flag);
if program == "xclip" {
cmd.arg("clipboard");
}
}
let outcome = cmd
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.and_then(|mut child| {
let written = child.stdin.as_mut().expect("piped").write_all(text.as_bytes());
rootle_trace::record_with(rootle_trace::EventKind::ExternalCommand, || {
serde_json::json!({"operation":"clipboard_tool", "program":program, "phase":"input",
"bytes":text.len(), "success":written.is_ok(),
"error_kind":written.as_ref().err().map(|error|format!("{:?}",error.kind()))})
});
child.wait()
});
rootle_trace::record_with(rootle_trace::EventKind::ExternalCommand, || {
serde_json::json!({"operation":"clipboard_tool", "program":program, "phase":"finished",
"success":outcome.as_ref().is_ok_and(|status|status.success()),
"exit_code":outcome.as_ref().ok().and_then(|status|status.code()),
"error_kind":outcome.as_ref().err().map(|error|format!("{:?}",error.kind()))})
});
if outcome.is_ok() {
return; }
}
}