blob: cb92bce6de41f156861060e6050e0b072498a6ff (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
static CLIPBOARD: std::sync::LazyLock<std::sync::Mutex<Option<arboard::Clipboard>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(arboard::Clipboard::new().ok()));
/// Attempts to set text to clipboard with OSC52 escape sequence
/// Works in many modern terminals, including over SSH.
fn set_text_osc52(text: &str) -> anyhow::Result<()> {
let encoded = BASE64.encode(text);
let seq = format!("\x1b]52;c;{}\x07", encoded);
// Write to stdout:
if let Err(e) = std::io::Write::write_all(&mut std::io::stdout(), seq.as_bytes()) {
return Err(anyhow::anyhow!("Failed to send OSC52 sequence").context(e));
}
// Flush stdout:
if let Err(e) = std::io::Write::flush(&mut std::io::stdout()) {
return Err(anyhow::anyhow!("Failed to flush OSC52 sequence").context(e));
}
Ok(())
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
pub fn set_text(text: &str) -> anyhow::Result<()> {
// First try arboard:
let mut clipboard = CLIPBOARD.lock().unwrap();
if let Some(clipboard) = clipboard.as_mut() {
if let Ok(()) = clipboard.set_text(text) {
#[cfg(target_os = "linux")]
std::thread::sleep(std::time::Duration::from_millis(50));
return Ok(());
}
}
// If arboard failed, try OSC52:
match set_text_osc52(text) {
Ok(()) => Ok(()),
Err(osc_err) => Err(anyhow::anyhow!("No clipboard available")
.context(format!("Failed to copy (OSC52 error: {})", osc_err))),
}
}
#[cfg(any(target_os = "android", target_os = "emscripten"))]
pub fn set_text(_text: &str) -> anyhow::Result<()> {
Err(anyhow::anyhow!("No clipboard available").context("Failed to copy"))
}
|