tui_lipan/clipboard/
service.rs1use std::cell::RefCell;
2use std::rc::Rc;
3
4use crate::clipboard::error::ClipboardError;
5use crate::clipboard::provider::{ClipboardProvider, ImageContent};
6use crate::style::Style;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum PasteShiftInsertBehavior {
11 Clipboard,
13 PrimarySelection,
15}
16
17#[derive(Debug, Clone)]
18pub struct ClipboardConfig {
20 pub enable_performable_ctrl_c_copy: bool,
22 pub enable_primary_selection: bool,
24 pub paste_shift_insert_behavior: PasteShiftInsertBehavior,
26 pub paste_max_bytes: usize,
28 pub enable_osc52: bool,
30 pub paste_max_image_bytes: usize,
32 pub copy_feedback_duration_ms: u16,
34 pub copy_feedback_style: Style,
36}
37
38impl Default for ClipboardConfig {
39 fn default() -> Self {
40 let enable_primary_selection = cfg!(target_os = "linux")
41 && (std::env::var("DISPLAY").is_ok() || std::env::var("WAYLAND_DISPLAY").is_ok());
42 let paste_shift_insert_behavior = if enable_primary_selection {
43 PasteShiftInsertBehavior::PrimarySelection
44 } else {
45 PasteShiftInsertBehavior::Clipboard
46 };
47
48 Self {
49 enable_performable_ctrl_c_copy: true,
50 enable_primary_selection,
51 paste_shift_insert_behavior,
52 paste_max_bytes: 1_000_000,
53 enable_osc52: true,
54 paste_max_image_bytes: 10_000_000,
55 copy_feedback_duration_ms: 150,
56 copy_feedback_style: Style::new().lighten_by(0.35),
57 }
58 }
59}
60
61pub type ClipboardReporter = Rc<dyn Fn(ClipboardError) + 'static>;
62
63pub struct ClipboardService {
64 provider: RefCell<Box<dyn ClipboardProvider>>,
65 reporter: ClipboardReporter,
66}
67
68impl ClipboardService {
69 pub fn new(provider: Box<dyn ClipboardProvider>, reporter: ClipboardReporter) -> Self {
70 Self {
71 provider: RefCell::new(provider),
72 reporter,
73 }
74 }
75
76 pub fn read_clipboard_text(&self) -> Result<String, ClipboardError> {
77 self.provider.borrow_mut().read_clipboard_text()
78 }
79
80 pub fn write_clipboard_text(&self, text: &str) -> Result<(), ClipboardError> {
81 self.provider.borrow_mut().write_clipboard_text(text)
82 }
83
84 #[cfg(all(target_arch = "wasm32", feature = "web"))]
85 pub(crate) fn set_clipboard_text_cache(&self, text: String) {
86 self.provider.borrow_mut().set_clipboard_text_cache(text);
87 }
88
89 pub fn read_primary_selection_text(&self) -> Result<String, ClipboardError> {
90 self.provider.borrow_mut().read_primary_selection_text()
91 }
92
93 pub fn write_primary_selection_text(&self, text: &str) -> Result<(), ClipboardError> {
94 self.provider
95 .borrow_mut()
96 .write_primary_selection_text(text)
97 }
98
99 pub fn supports_primary_selection(&self) -> bool {
100 self.provider.borrow().supports_primary_selection()
101 }
102
103 pub fn read_clipboard_image(&self) -> Result<ImageContent, ClipboardError> {
104 self.provider.borrow_mut().read_clipboard_image()
105 }
106
107 pub(crate) fn write_clipboard_image(
108 &self,
109 content: &ImageContent,
110 ) -> Result<(), ClipboardError> {
111 self.provider.borrow_mut().write_clipboard_image(content)
112 }
113
114 pub fn report_error(&self, error: ClipboardError) {
115 (self.reporter)(error);
116 }
117
118 #[cfg(all(target_arch = "wasm32", feature = "web"))]
119 pub(crate) fn replace_provider(&self, provider: Box<dyn ClipboardProvider>) {
120 *self.provider.borrow_mut() = provider;
121 }
122}
123
124pub fn default_clipboard_reporter() -> ClipboardReporter {
125 Rc::new(|error| {
126 let op = error.operation();
127 let message = match error {
128 ClipboardError::Unsupported { .. } => "unsupported clipboard operation".to_string(),
129 ClipboardError::Provider { message, .. } => message.to_string(),
130 };
131 crate::debug::internal_log!("[tui-lipan] clipboard {:?}: {}", op, message);
132 })
133}