返回 CodeWhale
primary.rs
根目录 / crates / tui / src / tui / clipboard / primary.rs
1 //! One bounded native PRIMARY transport. Keeping the handle alive preserves
2 //! X11/Wayland ownership; display I/O never runs on the TUI thread.
3
4 use std::sync::mpsc::{self, SyncSender};
5 use std::time::Duration;
6
7 use anyhow::{Result, anyhow};
8 use arboard::{Clipboard, GetExtLinux, LinuxClipboardKind, SetExtLinux};
9
10 enum Request {
11 Write(String),
12 Read(SyncSender<Option<String>>),
13 }
14
15 pub(super) struct PrimarySelection {
16 sender: SyncSender<Request>,
17 }
18
19 impl PrimarySelection {
20 pub(super) fn spawn() -> Result<Self> {
21 // At most one queued operation, even when a display server stalls.
22 let (sender, receiver) = mpsc::sync_channel(1);
23 std::thread::Builder::new()
24 .name("primary-selection".into())
25 .spawn(move || {
26 let mut clipboard = Clipboard::new().ok();
27 while let Ok(request) = receiver.recv() {
28 match request {
29 Request::Write(text) => {
30 if let Some(clipboard) = &mut clipboard {
31 let _ = clipboard
32 .set()
33 .clipboard(LinuxClipboardKind::Primary)
34 .text(text);
35 }
36 }
37 Request::Read(reply) => {
38 let text = clipboard
39 .as_mut()
40 .and_then(|clipboard| {
41 clipboard
42 .get()
43 .clipboard(LinuxClipboardKind::Primary)
44 .text()
45 .ok()
46 })
47 .filter(|text| {
48 !text.is_empty() && text.len() <= super::PRIMARY_MAX_BYTES
49 });
50 let _ = reply.try_send(text);
51 }
52 }
53 }
54 })?;
55 Ok(Self { sender })
56 }
57
58 pub(super) fn write(&self, text: &str) -> Result<()> {
59 self.sender
60 .try_send(Request::Write(text.to_string()))
61 .map_err(|_| anyhow!("PRIMARY selection busy or unavailable"))
62 }
63
64 pub(super) fn read(&self) -> Option<String> {
65 let (sender, receiver) = mpsc::sync_channel(1);
66 self.sender.try_send(Request::Read(sender)).ok()?;
67 // A late reply is discarded, never inserted into a subsequently edited
68 // composer. Clipboard failure stays quiet and cannot submit a command.
69 receiver
70 .recv_timeout(Duration::from_millis(250))
71 .ok()
72 .flatten()
73 }
74 }
75
75 lines RUST