Skip to main content

stynx_code_tui/
clipboard.rs

1use std::path::PathBuf;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4/// Outcome of a Ctrl+V paste attempt.
5pub enum PasteOutcome {
6    /// Clipboard held a bitmap; saved at `path`.
7    Image { path: PathBuf },
8    /// Clipboard held text.
9    Text(String),
10    /// Clipboard was empty or unreadable.
11    Empty,
12}
13
14/// Try to pull an image first; if there isn't one, try text.
15pub fn read_clipboard() -> PasteOutcome {
16    let Ok(mut cb) = arboard::Clipboard::new() else { return PasteOutcome::Empty; };
17
18    if let Ok(img) = cb.get_image() {
19        match save_image_to_temp(&img) {
20            Ok(path) => return PasteOutcome::Image { path },
21            Err(e) => {
22                tracing::warn!("failed to save pasted image: {e}");
23            }
24        }
25    }
26
27    if let Ok(text) = cb.get_text() {
28        if !text.is_empty() {
29            return PasteOutcome::Text(text);
30        }
31    }
32
33    PasteOutcome::Empty
34}
35
36fn save_image_to_temp(img: &arboard::ImageData) -> Result<PathBuf, String> {
37    use image::ImageEncoder;
38
39    let now = SystemTime::now()
40        .duration_since(UNIX_EPOCH)
41        .map(|d| d.as_millis())
42        .unwrap_or(0);
43
44    let dir = std::env::temp_dir().join("stynx-pastes");
45    std::fs::create_dir_all(&dir).map_err(|e| format!("mkdir: {e}"))?;
46    let path = dir.join(format!("paste-{now}.png"));
47
48    let file = std::fs::File::create(&path).map_err(|e| format!("create: {e}"))?;
49    let writer = std::io::BufWriter::new(file);
50    let encoder = image::codecs::png::PngEncoder::new(writer);
51    encoder
52        .write_image(
53            &img.bytes,
54            img.width as u32,
55            img.height as u32,
56            image::ExtendedColorType::Rgba8,
57        )
58        .map_err(|e| format!("encode: {e}"))?;
59    Ok(path)
60}