diff options
author | Peter Holloway <holloway.p.r@gmail.com> | 2024-01-18 18:08:55 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-18 18:08:55 +0000 |
commit | 8913d46dab2bc2f63773ab6a056fb0a032732c27 (patch) | |
tree | 7258915d2dfb589055ac2a8d2e9d9bb5fa7da096 /atuin-common | |
parent | 1ada8660581d93fecee5423949dc137fd82894a3 (diff) |
Escape control characters using caret notation (#1585)
Instead of using their equivalent hex codes.
Diffstat (limited to 'atuin-common')
-rw-r--r-- | atuin-common/src/utils.rs | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/atuin-common/src/utils.rs b/atuin-common/src/utils.rs index b6018fbb..87c4b14c 100644 --- a/atuin-common/src/utils.rs +++ b/atuin-common/src/utils.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::env; -use std::fmt::Write; use std::path::PathBuf; use rand::RngCore; @@ -119,7 +118,11 @@ pub trait Escapable: AsRef<str> { while let Some(i) = remaining.find(|c: char| c.is_ascii_control()) { // safe to index with `..i`, `i` and `i+1..` as part[i] is a single byte ascii char buf.push_str(&remaining[..i]); - let _ = write!(&mut buf, "\\x{:02x}", remaining.as_bytes()[i]); + buf.push('^'); + buf.push(match remaining.as_bytes()[i] { + 0x7F => '?', + code => char::from_u32(u32::from(code) + 64).unwrap(), + }); remaining = &remaining[i + 1..]; } buf.push_str(remaining); @@ -218,17 +221,17 @@ mod tests { fn escape_control_characters() { use super::Escapable; // CSI colour sequence - assert_eq!("\x1b[31mfoo".escape_control(), "\\x1b[31mfoo"); + assert_eq!("\x1b[31mfoo".escape_control(), "^[[31mfoo"); // Tabs count as control chars - assert_eq!("foo\tbar".escape_control(), "foo\\x09bar"); + assert_eq!("foo\tbar".escape_control(), "foo^Ibar"); // space is in control char range but should be excluded assert_eq!("two words".escape_control(), "two words"); // unicode multi-byte characters let s = "🐢\x1b[32m🦀"; - assert_eq!(s.escape_control(), s.replace("\x1b", "\\x1b")); + assert_eq!(s.escape_control(), s.replace("\x1b", "^[")); } #[test] |