Skip to main content

edtui/
clipboard.rs

1//! The editors clipboard
2//!
3//! ## Default clipboard
4//!
5//! `EdTUI` uses the arboard clipboard by default, which enables copy and paste
6//! operations between the system clipboard and the editor. However, if a lighter
7//! clipboard is desired, the "arboard" function flag can be deactivated. In this
8//! case, the internal clipboard is used, which only supports copying and pasting
9//! within the editor.
10//!
11//! ## Example: A custom global clipboard
12//!
13//! `EdTUI` allows you to set a custom clipboard. This is useful if you want to
14//! define a global clipboard for example:
15//!
16//!```ignore
17//! use once_cell::sync::Lazy;
18//! use std::sync::Mutex;
19//!
20//! static CLIPBOARD: Lazy<GlobalClipboard> = Lazy::new(|| GlobalClipboard::new());
21//!
22//! struct GlobalClipboard(Mutex<Clipboard>);
23//!
24//! impl GlobalClipboard {
25//!     pub fn new() -> Self {
26//!         Self(Mutex::new(arboard::Clipboard::new().unwrap()))
27//!     }
28//! }
29//!
30//! impl ClipboardTrait for &GlobalClipboard {
31//!     fn set_text(&mut self, text: String) {
32//!         if let Ok(mut clipboard) = self.0.lock() {
33//!             let _ = clipboard.set_text(text);
34//!         }
35//!     }
36//!
37//!     fn get_text(&mut self) -> String {
38//!         if let Ok(mut clipboard) = self.0.lock() {
39//!             return clipboard.get_text().unwrap_or_default();
40//!         }
41//!         String::new()
42//!     }
43//! }
44//!
45//! let mut state = EditorState::default();
46//! state.set_clipboard(Lazy::force(&CLIPBOARD));
47//!```
48#[cfg(feature = "arboard")]
49mod arboard;
50
51use std::{cell::RefCell, rc::Rc};
52
53/// Trait defining clipboard operations.
54pub trait ClipboardTrait {
55    /// Sets text to the clipboard.
56    fn set_text(&mut self, text: String);
57
58    /// Retrieves text from the clipboard.
59    fn get_text(&mut self) -> String;
60}
61
62/// A clipboard for the editor.
63///
64/// This struct can hold any type that implements [`ClipboardTrait`].
65#[derive(Clone)]
66pub struct Clipboard(Rc<RefCell<dyn ClipboardTrait>>);
67
68impl Clipboard {
69    /// Creates a new `Clipboard` instance with a provided clipboard implementation.
70    ///
71    /// ## Example
72    ///
73    /// ```
74    /// use edtui::clipboard::{Clipboard, ClipboardTrait};
75    ///
76    /// struct MyClipboard(String);
77    ///
78    /// impl ClipboardTrait for MyClipboard {
79    ///     fn set_text(&mut self, text: String) {
80    ///         self.0 = text;
81    ///     }
82    ///
83    ///     fn get_text(&mut self) -> String {
84    ///         self.0.clone()
85    ///     }
86    /// }
87    ///
88    /// let clipboard = MyClipboard(String::new());
89    /// let clipboard_wrapper = Clipboard::new(clipboard);
90    /// ```
91    #[must_use]
92    pub fn new(clipboard: impl ClipboardTrait + 'static) -> Self {
93        Clipboard(Rc::new(RefCell::new(clipboard)))
94    }
95}
96
97impl ClipboardTrait for Clipboard {
98    fn set_text(&mut self, text: String) {
99        self.0.borrow_mut().set_text(text);
100    }
101
102    fn get_text(&mut self) -> String {
103        self.0.borrow_mut().get_text()
104    }
105}
106
107#[derive(Default)]
108pub struct InternalClipboard(String);
109
110impl ClipboardTrait for InternalClipboard {
111    fn set_text(&mut self, text: String) {
112        self.0 = text;
113    }
114
115    fn get_text(&mut self) -> String {
116        self.0.clone()
117    }
118}
119
120#[cfg(not(feature = "arboard"))]
121impl Default for Clipboard {
122    /// Creates a new `Clipboard` with `InternalClipboard`.
123    /// The internal clipboard does not capture the systems clipboard.
124    fn default() -> Self {
125        Self::new(InternalClipboard::default())
126    }
127}