1use aurora_core::{AuroraResult, Pipeline, Value};
2use std::process::Command;
3
4fn try_cmds(cmds: &[&[&str]]) -> Option<String> {
5 for args in cmds {
6 if let Ok(output) = Command::new(args[0]).args(&args[1..]).output() {
7 if output.status.success() {
8 let s = String::from_utf8_lossy(&output.stdout).trim().to_string();
9 if !s.is_empty() {
10 return Some(s);
11 }
12 }
13 }
14 }
15 None
16}
17
18fn exec_cmd(args: &[&str]) -> AuroraResult<()> {
19 let result = Command::new(args[0])
20 .args(&args[1..])
21 .output()
22 .map_err(|e| aurora_core::AuroraError::ModuleError(
23 format!("clipboard command failed: {}", e)
24 ))?;
25 if !result.status.success() {
26 let stderr = String::from_utf8_lossy(&result.stderr);
27 return Err(aurora_core::AuroraError::ModuleError(
28 format!("clipboard command failed: {}", stderr)
29 ));
30 }
31 Ok(())
32}
33
34pub fn clip_get() -> AuroraResult<Pipeline> {
35 let content = try_cmds(&[
36 &["xclip", "-o", "-selection", "clipboard"],
37 &["wl-paste"],
38 &["pbpaste"],
39 &["powershell", "-Command", "Get-Clipboard"],
40 ])
41 .unwrap_or_default();
42
43 Ok(Pipeline::table(
44 vec!["clipboard".into()],
45 vec![vec![Value::String(content)]],
46 ))
47}
48
49pub fn clip_set(text: &[String]) -> AuroraResult<Pipeline> {
50 let input = text.join(" ");
51
52 let cmds: &[&[&str]] = &[
53 &["xclip", "-i", "-selection", "clipboard"],
54 &["wl-copy"],
55 &["pbcopy"],
56 ];
57
58 let mut success = false;
59 for args in cmds {
60 let child = Command::new(args[0])
61 .args(&args[1..])
62 .stdin(std::process::Stdio::piped())
63 .spawn()
64 .ok();
65
66 if let Some(mut c) = child {
67 use std::io::Write;
68 if let Some(mut stdin) = c.stdin.take() {
69 let _ = stdin.write_all(input.as_bytes());
70 drop(stdin);
71 }
72 if let Ok(status) = c.wait() {
73 if status.success() {
74 success = true;
75 break;
76 }
77 }
78 }
79 }
80
81 if !success && cfg!(target_os = "windows") {
82 let escaped = input.replace('\'', "''");
83 exec_cmd(&["powershell", "-Command", &format!("Set-Clipboard '{}'", escaped)])?;
84 success = true;
85 }
86
87 if !success {
88 return Err(aurora_core::AuroraError::CommandNotFound(
89 "no clipboard tool found (install xclip, wl-clipboard, or pbcopy)".into()
90 ));
91 }
92
93 Ok(Pipeline::table(
94 vec!["action".into(), "content".into()],
95 vec![vec![
96 Value::String("set".into()),
97 Value::String(input),
98 ]],
99 ))
100}
101
102pub fn clip_clear() -> AuroraResult<Pipeline> {
103 clip_set(&[String::new()])
104}