pub(crate) fn clipboard_info_fingerprint(info: &str) -> u64 {
use std::hash::{Hash, Hasher};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
info.split_whitespace()
.collect::<Vec<_>>()
.hash(&mut hasher);
hasher.finish()
}
const IMAGE_CLASS_MARKERS: &[&str] = &[
"PNGf", "picture", "TIFF", "JPEG", "GIF", "BMP", "jp2", "AVIF", "8BPS", "TPIC", "PICT",
];
const TEXT_CLASS_MARKERS: &[&str] = &["string", "utf8", "ut16", "utxt", "Unicode text"];
pub(crate) fn clipboard_info_is_image_only(info: &str) -> bool {
clipboard_info_has_image(info) && !clipboard_info_has_text(info)
}
pub(crate) fn clipboard_info_has_image(info: &str) -> bool {
IMAGE_CLASS_MARKERS.iter().any(|m| info.contains(m))
}
pub(crate) fn clipboard_info_has_text(info: &str) -> bool {
TEXT_CLASS_MARKERS.iter().any(|m| info.contains(m))
}
pub(crate) fn read_clipboard_info() -> Option<String> {
#[cfg(target_os = "macos")]
{
use std::process::Command;
match Command::new("osascript")
.arg("-e")
.arg("clipboard info")
.output()
{
Ok(out) if out.status.success() => {
let text = String::from_utf8(out.stdout).ok()?;
(!text.is_empty()).then_some(text)
}
Ok(out) => {
tracing::debug!(
stderr = %String::from_utf8_lossy(&out.stderr),
"clipboard info probe failed"
);
None
}
Err(e) => {
tracing::debug!("clipboard info probe could not run: {e}");
None
}
}
}
#[cfg(not(target_os = "macos"))]
{
None
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ClipboardRoute<'a> {
Text(&'a str),
Image,
}
pub(crate) fn route_for_clipboard_text(text: Option<&str>) -> ClipboardRoute<'_> {
match text {
Some(t) if !t.trim().is_empty() => ClipboardRoute::Text(t),
_ => ClipboardRoute::Image,
}
}