//! 把 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 { #[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") } }