summaryrefslogtreecommitdiffstats
path: root/src/clipboard.rs
blob: 61170fe22ace26e9a977c3e8de5f6b1c53f516e5 (plain)
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use anyhow::{anyhow, Result};
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use which::which;

fn exec_copy_with_args(
	command: &str,
	args: &[&str],
	text: &str,
) -> Result<()> {
	let binary = which(command)
		.ok()
		.unwrap_or_else(|| PathBuf::from(command));

	let mut process = Command::new(binary)
		.args(args)
		.stdin(Stdio::piped())
		.stdout(Stdio::null())
		.stderr(Stdio::piped())
		.spawn()
		.map_err(|e| anyhow!("`{:?}`: {}", command, e))?;

	process
		.stdin
		.as_mut()
		.ok_or_else(|| anyhow!("`{:?}`", command))?
		.write_all(text.as_bytes())
		.map_err(|e| anyhow!("`{:?}`: {}", command, e))?;

	let out = process
		.wait_with_output()
		.map_err(|e| anyhow!("`{:?}`: {}", command, e))?;

	if out.status.success() {
		Ok(())
	} else {
		let msg = if out.stderr.is_empty() {
			format!("{}", out.status).into()
		} else {
			String::from_utf8_lossy(&out.stderr)
		};
		Err(anyhow!("`{command:?}`: {msg}"))
	}
}

fn exec_copy(command: &str, text: &str) -> Result<()> {
	exec_copy_with_args(command, &[], text)
}

#[cfg(all(target_family = "unix", not(target_os = "macos")))]
pub fn copy_string(text: &str) -> Result<()> {
	if std::env::var("WAYLAND_DISPLAY").is_ok() {
		return exec_copy("wl-copy", text);
	}

	if exec_copy_with_args(
		"xclip",
		&["-selection", "clipboard"],
		text,
	)
	.is_err()
	{
		return exec_copy_with_args("xsel", &["--clipboard"], text);
	}

	Ok(())
}

#[cfg(target_os = "macos")]
pub fn copy_string(text: &str) -> Result<()> {
	exec_copy("pbcopy", text)
}

#[cfg(windows)]
pub fn copy_string(text: &str) -> Result<()> {
	exec_copy("clip", text)
}