pub fn sanitize_terminal(input: &str) -> String {
let mut out = String::with_capacity(input.len());
let mut chars = input.chars().peekable();
while let Some(c) = chars.next() {
match c {
'\u{1b}' => match chars.peek() {
Some('[') => {
chars.next();
for tail in chars.by_ref() {
if ('\u{40}'..='\u{7e}').contains(&tail) {
break;
}
}
}
Some(']') => {
chars.next();
while let Some(&t) = chars.peek() {
if t == '\u{07}' {
chars.next();
break;
}
if t == '\u{1b}' {
chars.next();
if chars.peek() == Some(&'\\') {
chars.next();
}
break;
}
chars.next();
}
}
Some(_) => {
chars.next();
}
None => {}
},
c if (c as u32) < 0x20 || c as u32 == 0x7f || (0x80..=0x9f).contains(&(c as u32)) => {}
c => out.push(c),
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strips_csi_color_sequences() {
assert_eq!(sanitize_terminal("\x1b[31mred\x1b[0m"), "red");
assert_eq!(sanitize_terminal("a\x1b[1;33mb\x1b[0mc"), "abc");
}
#[test]
fn strips_osc_clipboard_write() {
assert_eq!(sanitize_terminal("a\x1b]52;c;ZXZpbA==\x07b"), "ab");
assert_eq!(sanitize_terminal("a\x1b]0;pwned\x1b\\b"), "ab");
}
#[test]
fn strips_c0_controls_and_del() {
assert_eq!(sanitize_terminal("line1\nline2\r\t\x08\x7fx"), "line1line2x");
}
#[test]
fn strips_c1_controls() {
assert_eq!(sanitize_terminal("a\u{9b}31mred"), "a31mred");
assert_eq!(sanitize_terminal("x\u{80}y\u{9f}z"), "xyz");
}
#[test]
fn preserves_plain_and_unicode_text() {
assert_eq!(sanitize_terminal("agent-7 working"), "agent-7 working");
assert_eq!(sanitize_terminal("héllo-β-世界-🚀"), "héllo-β-世界-🚀");
}
}