use std::fmt;
pub(crate) fn display_safe(s: &str) -> DisplaySafe<'_> {
DisplaySafe(s)
}
pub(crate) struct DisplaySafe<'a>(&'a str);
impl fmt::Display for DisplaySafe<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for c in self.0.chars() {
match c {
'\n' => f.write_str(r"\n")?,
'\r' => f.write_str(r"\r")?,
'\t' => f.write_str(r"\t")?,
'\\' => f.write_str(r"\\")?,
c if (c as u32) < 0x20 || c == '\x7f' => write!(f, "\\x{:02x}", c as u32)?,
c if matches!(c as u32, 0x80..=0x9f) || c == '\u{2028}' || c == '\u{2029}' => {
write!(f, "\\u{{{:04x}}}", c as u32)?
}
c => f.write_fmt(format_args!("{c}"))?,
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::display_safe;
#[test]
fn plain_ascii_is_unchanged() {
assert_eq!(format!("{}", display_safe("alice")), "alice");
}
#[test]
fn newline_is_escaped() {
let rendered = format!("{}", display_safe("foo\nbar"));
assert_eq!(rendered, r"foo\nbar");
assert!(!rendered.contains('\n'));
}
#[test]
fn carriage_return_and_tab_are_escaped() {
assert_eq!(format!("{}", display_safe("a\rb\tc")), r"a\rb\tc");
}
#[test]
fn backslash_is_escaped_so_round_trip_does_not_re_interpret() {
assert_eq!(format!("{}", display_safe(r"raw\n")), r"raw\\n");
}
#[test]
fn ansi_escape_sequence_cannot_clear_terminal() {
let hostile = "\x1b[2J\x1b[Halice";
let rendered = format!("{}", display_safe(hostile));
assert!(!rendered.contains('\x1b'));
assert!(rendered.contains(r"\x1b"));
assert!(rendered.ends_with("alice"));
}
#[test]
fn del_and_nul_are_escaped() {
assert_eq!(format!("{}", display_safe("\x7f")), r"\x7f");
assert_eq!(format!("{}", display_safe("\0")), r"\x00");
}
#[test]
fn unicode_identifiers_render_as_is() {
assert_eq!(format!("{}", display_safe("用户-α")), "用户-α");
}
#[test]
fn c1_controls_and_unicode_line_separators_are_escaped() {
let rendered = format!("{}", display_safe("a\u{0085}b\u{2028}c\u{2029}d"));
assert!(!rendered.contains('\u{0085}'));
assert!(!rendered.contains('\u{2028}'));
assert!(!rendered.contains('\u{2029}'));
assert_eq!(rendered, r"a\u{0085}b\u{2028}c\u{2029}d");
}
#[test]
fn other_c1_controls_are_escaped() {
let rendered = format!("{}", display_safe("\u{009b}[2J"));
assert!(!rendered.contains('\u{009b}'));
assert_eq!(rendered, r"\u{009b}[2J");
}
}