use aurora_core::{AuroraResult, Pipeline, Value};
use std::process::Command;
fn try_cmds(cmds: &[&[&str]]) -> Option<String> {
for args in cmds {
if let Ok(output) = Command::new(args[0]).args(&args[1..]).output() {
if output.status.success() {
let s = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !s.is_empty() {
return Some(s);
}
}
}
}
None
}
fn exec_cmd(args: &[&str]) -> AuroraResult<()> {
let result = Command::new(args[0])
.args(&args[1..])
.output()
.map_err(|e| aurora_core::AuroraError::ModuleError(
format!("clipboard command failed: {}", e)
))?;
if !result.status.success() {
let stderr = String::from_utf8_lossy(&result.stderr);
return Err(aurora_core::AuroraError::ModuleError(
format!("clipboard command failed: {}", stderr)
));
}
Ok(())
}
pub fn clip_get() -> AuroraResult<Pipeline> {
let content = try_cmds(&[
&["xclip", "-o", "-selection", "clipboard"],
&["wl-paste"],
&["pbpaste"],
&["powershell", "-Command", "Get-Clipboard"],
])
.unwrap_or_default();
Ok(Pipeline::table(
vec!["clipboard".into()],
vec![vec![Value::String(content)]],
))
}
pub fn clip_set(text: &[String]) -> AuroraResult<Pipeline> {
let input = text.join(" ");
let cmds: &[&[&str]] = &[
&["xclip", "-i", "-selection", "clipboard"],
&["wl-copy"],
&["pbcopy"],
];
let mut success = false;
for args in cmds {
let child = Command::new(args[0])
.args(&args[1..])
.stdin(std::process::Stdio::piped())
.spawn()
.ok();
if let Some(mut c) = child {
use std::io::Write;
if let Some(mut stdin) = c.stdin.take() {
let _ = stdin.write_all(input.as_bytes());
drop(stdin);
}
if let Ok(status) = c.wait() {
if status.success() {
success = true;
break;
}
}
}
}
if !success && cfg!(target_os = "windows") {
let escaped = input.replace('\'', "''");
exec_cmd(&["powershell", "-Command", &format!("Set-Clipboard '{}'", escaped)])?;
success = true;
}
if !success {
return Err(aurora_core::AuroraError::CommandNotFound(
"no clipboard tool found (install xclip, wl-clipboard, or pbcopy)".into()
));
}
Ok(Pipeline::table(
vec!["action".into(), "content".into()],
vec![vec![
Value::String("set".into()),
Value::String(input),
]],
))
}
pub fn clip_clear() -> AuroraResult<Pipeline> {
clip_set(&[String::new()])
}