64 lines
2.7 KiB
Rust
64 lines
2.7 KiB
Rust
//! 把 UTF-8 文本读写适配到当前平台的系统剪贴板命令。
|
|
//! 外部命令失败作为普通错误交给调用方处理;这里不解析或执行剪贴板中的程序文本。
|
|
//!
|
|
//! Clipboard text is always UTF-8, including Finder/LaunchServices launches without LANG.
|
|
use anyhow::{Result, bail};
|
|
#[cfg(target_os = "macos")]
|
|
/// 构造固定 UTF-8 环境的系统命令;本函数不启动进程,退出状态由 read/write 检查。
|
|
fn command(program: &str) -> std::process::Command {
|
|
let mut cmd = std::process::Command::new(program);
|
|
// 从 Finder 等无 LANG 的环境启动时也显式指定 UTF-8,防止系统工具按其他编码转换中文。
|
|
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")]
|
|
{
|
|
// 直接启动固定路径程序并传递独立参数,不经过 shell;-Prefer txt 要求文本表示。
|
|
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())?;
|
|
// 写完后先关闭管道发送 EOF,让 pbcopy 知道输入结束;之后等待退出状态,不能仅以写管道成功作为完成。
|
|
drop(stdin);
|
|
if !child.wait()?.success() {
|
|
bail!("system clipboard write failed");
|
|
}
|
|
Ok(())
|
|
}
|
|
#[cfg(not(target_os = "macos"))]
|
|
{
|
|
// 非 macOS 当前没有实现适配器,显式报错而不伪装成写入成功。
|
|
let _ = value;
|
|
bail!("system clipboard adapter is not available on this platform")
|
|
}
|
|
}
|