StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.
| 1 | use std::ops::Not; |
| 2 | |
| 3 | use arboard::{self, Clipboard as WindowsClipboardInner}; |
| 4 | |
| 5 | use crate::{clipboard::ClipboardContent, Clipboard}; |
| 6 | |
| 7 | pub struct WindowsClipboard { |
| 8 | inner: WindowsClipboardInner, |
| 9 | } |
| 10 | |
| 11 | impl WindowsClipboard { |
| 12 | pub fn new() -> Result<Self, arboard::Error> { |
| 13 | Ok(Self { |
| 14 | inner: WindowsClipboardInner::new()?, |
| 15 | }) |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | impl Clipboard for WindowsClipboard { |
| 20 | fn write(&mut self, contents: ClipboardContent) { |
| 21 | let set_result = if let Some(html) = &contents.html { |
| 22 | self.inner.set().html(html, Some(&contents.plain_text)) |
| 23 | } else { |
| 24 | self.inner.set().text(&contents.plain_text) |
| 25 | }; |
| 26 | |
| 27 | if let Err(err) = set_result { |
| 28 | if contents.html.is_some() { |
| 29 | log::warn!("Unable to set clipboard HTML: {err:?}"); |
| 30 | } else { |
| 31 | log::warn!("Unable to set clipboard text: {err:?}"); |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | fn read(&mut self) -> ClipboardContent { |
| 37 | let mut content = ClipboardContent { |
| 38 | plain_text: self.inner.get().text().unwrap_or_default(), |
| 39 | ..Default::default() |
| 40 | }; |
| 41 | |
| 42 | // Try to get HTML content |
| 43 | if let Ok(html) = self.inner.get().html() { |
| 44 | content.html = html.is_empty().not().then_some(html); |
| 45 | } |
| 46 | |
| 47 | // Some environments provide HTML but do not provide a plaintext representation. |
| 48 | // If that happens, derive a best-effort plaintext fallback from the HTML. |
| 49 | if content.plain_text.trim().is_empty() { |
| 50 | if let Some(html) = content.html.as_ref() { |
| 51 | let derived = crate::clipboard_utils::strip_html_to_plain_text(html); |
| 52 | if !derived.trim().is_empty() { |
| 53 | content.plain_text = derived; |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | // Get file paths. |
| 59 | content.paths = self.inner.get().file_list().ok().map(|list| { |
| 60 | list.into_iter() |
| 61 | .map(|p| p.to_string_lossy().to_string()) |
| 62 | .collect() |
| 63 | }); |
| 64 | |
| 65 | // Try to get image content from clipboard |
| 66 | content.images = crate::clipboard_utils::read_images_from_clipboard( |
| 67 | &mut self.inner, |
| 68 | &content.html, |
| 69 | &content.plain_text, |
| 70 | ); |
| 71 | |
| 72 | content |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | #[cfg(test)] |
| 77 | #[path = "clipboard_tests.rs"] |
| 78 | mod tests; |
| 79 |