thoth_cli/
clipboard.rs

1use anyhow::Result;
2use arboard::{Clipboard, Error};
3use std::env;
4use std::process;
5use std::sync::{Arc, Mutex};
6
7#[cfg(target_os = "linux")]
8use arboard::SetExtLinux;
9
10use crate::DAEMONIZE_ARG;
11
12pub trait ClipboardTrait {
13    fn set_contents(&mut self, content: String) -> anyhow::Result<()>;
14    fn get_content(&self) -> anyhow::Result<String>;
15}
16
17pub struct EditorClipboard {
18    clipboard: Arc<Mutex<Clipboard>>,
19}
20
21impl EditorClipboard {
22    pub fn new() -> Result<EditorClipboard, Error> {
23        Clipboard::new().map(|c| EditorClipboard {
24            clipboard: Arc::new(Mutex::new(c)),
25        })
26    }
27
28    pub fn try_new() -> Option<EditorClipboard> {
29        Self::new().ok()
30    }
31
32    pub fn set_contents(&mut self, content: String) -> Result<(), Error> {
33        #[cfg(target_os = "linux")]
34        {
35            let is_wayland = std::env::var("WAYLAND_DISPLAY").is_ok()
36                || std::env::var("XDG_SESSION_TYPE")
37                    .map(|v| v == "wayland")
38                    .unwrap_or(false);
39
40            if is_wayland {
41                let mut clipboard = self
42                    .clipboard
43                    .lock()
44                    .map_err(|_e| arboard::Error::ContentNotAvailable)?;
45
46                let result = clipboard.set().wait().text(content);
47                result
48            } else if env::args().nth(1).as_deref() == Some(DAEMONIZE_ARG) {
49                let mut clipboard = self
50                    .clipboard
51                    .lock()
52                    .map_err(|_e| arboard::Error::ContentNotAvailable)?;
53                clipboard.set().wait().text(content)
54            } else {
55                if std::env::var("THOTH_DEBUG_CLIPBOARD").is_ok() {
56                    return Err(arboard::Error::ContentNotAvailable);
57                }
58
59                process::Command::new(env::current_exe().unwrap())
60                    .arg(DAEMONIZE_ARG)
61                    .arg(content)
62                    .stdin(process::Stdio::null())
63                    .stdout(process::Stdio::null())
64                    .stderr(process::Stdio::null())
65                    .current_dir("/")
66                    .spawn()
67                    .map_err(|_e| arboard::Error::ContentNotAvailable)?;
68                Ok(())
69            }
70        }
71
72        #[cfg(not(target_os = "linux"))]
73        {
74            let mut clipboard = self
75                .clipboard
76                .lock()
77                .map_err(|_e| arboard::Error::ContentNotAvailable)?;
78            clipboard.set_text(content)
79        }
80    }
81
82    pub fn get_content(&mut self) -> Result<String, Error> {
83        let mut clipboard = self.clipboard.lock().unwrap();
84        clipboard.get_text()
85    }
86
87    #[cfg(target_os = "linux")]
88    pub fn handle_daemon_args() -> Result<(), Error> {
89        if let Some(content) = env::args().nth(2) {
90            if env::args().nth(1).as_deref() == Some(DAEMONIZE_ARG) {
91                let mut clipboard = Self::new()?;
92                clipboard.set_contents(content)?;
93                std::process::exit(0);
94            }
95        }
96        Ok(())
97    }
98}