tree-tui 0.1.3

An interactive terminal UI for visualizing directories: code, size, and git stats.
//! Best-effort system-clipboard copy via the OSC 52 terminal escape.
//!
//! Writes `ESC ] 52 ; c ; <base64> BEL` to stdout; a capable terminal — and
//! tmux/SSH that forward it — places the text on the host's system clipboard.
//! No system dependency and it works over SSH. Failures are swallowed: copying
//! must never abort the TUI.

use std::io::Write;

/// Copy `text` to the system clipboard using OSC 52. Best-effort.
pub fn osc52_copy(text: &str) {
    let sequence = osc52_sequence(text);
    let mut out = std::io::stdout();
    let _ = out.write_all(sequence.as_bytes());
    let _ = out.flush();
}

/// The OSC 52 escape sequence that copies `text` to the clipboard.
fn osc52_sequence(text: &str) -> String {
    format!("\x1b]52;c;{}\x07", base64_encode(text.as_bytes()))
}

/// Standard-alphabet base64 with `=` padding. Hand-rolled to avoid a
/// dependency for this single call site.
fn base64_encode(input: &[u8]) -> String {
    const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
    for chunk in input.chunks(3) {
        let b0 = chunk[0] as u32;
        let b1 = chunk.get(1).copied().unwrap_or(0) as u32;
        let b2 = chunk.get(2).copied().unwrap_or(0) as u32;
        let triple = (b0 << 16) | (b1 << 8) | b2;
        out.push(ALPHABET[(triple >> 18 & 0x3f) as usize] as char);
        out.push(ALPHABET[(triple >> 12 & 0x3f) as usize] as char);
        out.push(if chunk.len() > 1 {
            ALPHABET[(triple >> 6 & 0x3f) as usize] as char
        } else {
            '='
        });
        out.push(if chunk.len() > 2 {
            ALPHABET[(triple & 0x3f) as usize] as char
        } else {
            '='
        });
    }
    out
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn base64_matches_known_vectors() {
        assert_eq!(base64_encode(b""), "");
        assert_eq!(base64_encode(b"f"), "Zg==");
        assert_eq!(base64_encode(b"fo"), "Zm8=");
        assert_eq!(base64_encode(b"foo"), "Zm9v");
        assert_eq!(base64_encode(b"M"), "TQ==");
        assert_eq!(base64_encode(b"Ma"), "TWE=");
        assert_eq!(base64_encode(b"Man"), "TWFu");
    }

    #[test]
    fn osc52_sequence_is_framed() {
        let seq = osc52_sequence("Man");
        assert_eq!(seq, "\x1b]52;c;TWFu\x07");
        assert!(seq.starts_with("\x1b]52;c;"));
        assert!(seq.ends_with('\x07'));
    }
}