Files
endorphin-tessera-gui/src/shell/clipboard.rs

59 lines
2.0 KiB
Rust

//! 把 UTF-8 文本读写适配到当前平台的系统剪贴板命令。
//! 外部命令失败作为普通错误交给调用方处理;这里不解析或执行剪贴板中的程序文本。
//!
//! Clipboard text is always UTF-8, including Finder/LaunchServices launches without LANG.
use anyhow::{Result, bail};
#[cfg(target_os = "macos")]
/// 运行选定平台的剪贴板命令并检查其退出状态。
fn command(program: &str) -> std::process::Command {
let mut cmd = std::process::Command::new(program);
cmd.env("LC_ALL", "en_US.UTF-8")
.env("LC_CTYPE", "en_US.UTF-8")
.env("LANG", "en_US.UTF-8");
cmd
}
/// 取得系统剪贴板的 UTF-8 文本,失败作为可显示错误返回。
pub fn read() -> Result<String> {
#[cfg(target_os = "macos")]
{
let output = command("/usr/bin/pbpaste")
.arg("-Prefer")
.arg("txt")
.output()?;
if !output.status.success() {
bail!("system clipboard read failed");
}
// Never silently replace invalid bytes in the user's source.
Ok(String::from_utf8(output.stdout)?)
}
#[cfg(not(target_os = "macos"))]
{
bail!("system clipboard adapter is not available on this platform")
}
}
/// 将提供的文本交给系统剪贴板命令,不执行文本内容。
pub fn write(value: &str) -> Result<()> {
#[cfg(target_os = "macos")]
{
use std::io::Write;
let mut child = command("/usr/bin/pbcopy")
.stdin(std::process::Stdio::piped())
.spawn()?;
let mut stdin = child
.stdin
.take()
.ok_or_else(|| anyhow::anyhow!("clipboard stdin is unavailable"))?;
stdin.write_all(value.as_bytes())?;
drop(stdin);
if !child.wait()?.success() {
bail!("system clipboard write failed");
}
Ok(())
}
#[cfg(not(target_os = "macos"))]
{
let _ = value;
bail!("system clipboard adapter is not available on this platform")
}
}