runemark 0.9.0

Opinionated terminal presentation for Rust command-line tools
Documentation
//! Snapshot testing utilities and ANSI stripping for golden CLI tests.

/// Strips ANSI escape sequences (colors, styling, OSC 8 links) from a rendered string.
pub fn strip_ansi(input: &str) -> String {
    let mut out = String::with_capacity(input.len());
    let mut chars = input.chars().peekable();

    while let Some(ch) = chars.next() {
        if ch == '\x1b' {
            match chars.peek() {
                Some(&'[') => {
                    chars.next(); // consume '['
                    // CSI sequence: parameters followed by command byte in 0x40..=0x7E
                    while let Some(&next) = chars.peek() {
                        chars.next();
                        if (0x40..=0x7E).contains(&(next as u32)) {
                            break;
                        }
                    }
                    continue;
                }
                Some(&']') => {
                    chars.next(); // consume ']'
                    // OSC sequence: terminated by BEL (\x07) or ST (\x1b\\)
                    while let Some(&next) = chars.peek() {
                        chars.next();
                        if next == '\x07' {
                            break;
                        }
                        if next == '\x1b' {
                            if let Some(&'\\') = chars.peek() {
                                chars.next();
                                break;
                            }
                        }
                    }
                    continue;
                }
                _ => {}
            }
        }

        out.push(ch);
    }

    out
}

/// Asserts that a rendered CLI component output matches the expected plain-text representation.
#[macro_export]
macro_rules! assert_plain_snapshot {
    ($actual:expr, $expected:expr) => {
        let plain = $crate::testing::strip_ansi(&$actual);
        assert_eq!(plain.trim(), $expected.trim());
    };
}

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

    #[test]
    fn test_strip_ansi_colors() {
        let colored = "\x1b[31mError\x1b[0m occurred";
        assert_eq!(strip_ansi(colored), "Error occurred");
    }

    #[test]
    fn test_strip_ansi_osc8_hyperlinks() {
        let linked = "\x1b]8;;https://example.com\x1b\\\x1b[36mexample\x1b[0m\x1b]8;;\x1b\\";
        assert_eq!(strip_ansi(linked), "example");
    }

    #[test]
    fn test_strip_ansi_osc8_bel_terminator() {
        let linked = "\x1b]8;;https://example.com\x07bel-link\x1b]8;;\x07";
        assert_eq!(strip_ansi(linked), "bel-link");
    }
}