Skip to main content

pacsea/util/
clipboard.rs

1//! Clipboard helpers for copying plain text via `wl-copy` or `xclip`.
2
3/// What: Copy plain text to the system clipboard without extra suffixes.
4///
5/// Inputs:
6/// - `text`: Exact bytes to place on the clipboard.
7///
8/// Output:
9/// - `Ok(())` when `wl-copy` or `xclip` accepted stdin.
10///
11/// # Errors
12/// - Returns `Err` with install guidance when neither clipboard tool could be spawned.
13///
14/// Details:
15/// - Prefers `wl-copy` when `WAYLAND_DISPLAY` is set, otherwise tries `xclip`.
16/// - Does not invoke a shell; uses `Command` argument lists only.
17pub fn copy_plain_text_to_clipboard(text: &str) -> Result<(), String> {
18    let payload = text.as_bytes();
19    if std::env::var("WAYLAND_DISPLAY").is_ok()
20        && let Ok(mut child) = std::process::Command::new("wl-copy")
21            .stdin(std::process::Stdio::piped())
22            .stdout(std::process::Stdio::null())
23            .stderr(std::process::Stdio::null())
24            .spawn()
25    {
26        if let Some(mut sin) = child.stdin.take() {
27            let _ = std::io::Write::write_all(&mut sin, payload);
28        }
29        let _ = child.wait();
30        return Ok(());
31    }
32
33    if let Ok(mut child) = std::process::Command::new("xclip")
34        .args(["-selection", "clipboard"])
35        .stdin(std::process::Stdio::piped())
36        .stdout(std::process::Stdio::null())
37        .stderr(std::process::Stdio::null())
38        .spawn()
39    {
40        if let Some(mut sin) = child.stdin.take() {
41            let _ = std::io::Write::write_all(&mut sin, payload);
42        }
43        let _ = child.wait();
44        return Ok(());
45    }
46
47    if std::env::var("WAYLAND_DISPLAY").is_ok() {
48        Err("Clipboard tool not found. Install 'wl-clipboard' (wl-copy) or 'xclip'.".to_string())
49    } else {
50        Err("Clipboard tool not found. Install 'xclip' or 'wl-clipboard' (wl-copy).".to_string())
51    }
52}