argui_platform/
clipboard.rs1use std::{error::Error, fmt};
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub struct ClipboardError(String);
5
6impl fmt::Display for ClipboardError {
7 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
8 formatter.write_str(&self.0)
9 }
10}
11
12impl Error for ClipboardError {}
13
14#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
15#[derive(Default)]
16pub struct Clipboard {
17 inner: Option<arboard::Clipboard>,
18}
19
20#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
21#[cfg_attr(coverage_nightly, coverage(off))]
22impl Clipboard {
23 #[must_use]
24 pub const fn new() -> Self {
25 Self { inner: None }
26 }
27
28 pub fn read_text(&mut self) -> Result<String, ClipboardError> {
29 self.inner()?.get_text().map_err(error)
30 }
31
32 pub fn write_text(&mut self, text: String) -> Result<(), ClipboardError> {
33 self.inner()?.set_text(text).map_err(error)
34 }
35
36 fn inner(&mut self) -> Result<&mut arboard::Clipboard, ClipboardError> {
37 if self.inner.is_none() {
38 self.inner = Some(arboard::Clipboard::new().map_err(error)?);
39 }
40 Ok(self.inner.as_mut().expect("clipboard was initialized"))
41 }
42}
43
44#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
45fn error(error: arboard::Error) -> ClipboardError {
46 ClipboardError(error.to_string())
47}
48
49#[cfg(all(
50 not(target_arch = "wasm32"),
51 not(any(target_os = "linux", target_os = "windows", target_os = "macos"))
52))]
53#[derive(Default)]
54pub struct Clipboard;
55
56#[cfg(all(
57 not(target_arch = "wasm32"),
58 not(any(target_os = "linux", target_os = "windows", target_os = "macos"))
59))]
60impl Clipboard {
61 #[must_use]
62 pub const fn new() -> Self {
63 Self
64 }
65
66 pub fn read_text(&mut self) -> Result<String, ClipboardError> {
67 Err(ClipboardError(
68 "clipboard integration is unavailable on this target".into(),
69 ))
70 }
71
72 pub fn write_text(&mut self, _text: String) -> Result<(), ClipboardError> {
73 Err(ClipboardError(
74 "clipboard integration is unavailable on this target".into(),
75 ))
76 }
77}
78
79#[cfg(target_arch = "wasm32")]
80#[derive(Default)]
81pub struct Clipboard;
82
83#[cfg(target_arch = "wasm32")]
84#[cfg_attr(coverage_nightly, coverage(off))]
85impl Clipboard {
86 #[must_use]
87 pub const fn new() -> Self {
88 Self
89 }
90
91 pub async fn read_text(&mut self) -> Result<String, ClipboardError> {
92 let clipboard = web_sys::window()
93 .ok_or_else(|| ClipboardError("browser window is unavailable".into()))?
94 .navigator()
95 .clipboard();
96 let value = wasm_bindgen_futures::JsFuture::from(clipboard.read_text())
97 .await
98 .map_err(|value| ClipboardError(format!("{value:?}")))?;
99 value
100 .as_string()
101 .ok_or_else(|| ClipboardError("clipboard returned non-text data".into()))
102 }
103
104 pub async fn write_text(&mut self, text: String) -> Result<(), ClipboardError> {
105 let clipboard = web_sys::window()
106 .ok_or_else(|| ClipboardError("browser window is unavailable".into()))?
107 .navigator()
108 .clipboard();
109 wasm_bindgen_futures::JsFuture::from(clipboard.write_text(&text))
110 .await
111 .map_err(|value| ClipboardError(format!("{value:?}")))?;
112 Ok(())
113 }
114}