diff --git a/src/core.rs b/src/core.rs index 3b23f25..09785e3 100644 --- a/src/core.rs +++ b/src/core.rs @@ -46,13 +46,28 @@ const ANSI_FINAL_BYTE: std::ops::RangeInclusive = '\x40'..='\x7e'; /// modified if `ch` is the start of an ANSI escape sequence. #[inline] pub(crate) fn skip_ansi_escape_sequence>(ch: char, chars: &mut I) -> bool { - if ch == CSI.0 && chars.next() == Some(CSI.1) { - // We have found the start of an ANSI escape code, typically - // used for colored terminal text. We skip until we find a - // "final byte" in the range 0x40–0x7E. - for ch in chars { - if ANSI_FINAL_BYTE.contains(&ch) { - return true; + if ch == CSI.0 { + let next = chars.next(); + if next == Some(CSI.1) { + // We have found the start of an ANSI escape code, typically + // used for colored terminal text. We skip until we find a + // "final byte" in the range 0x40–0x7E. + for ch in chars { + if ANSI_FINAL_BYTE.contains(&ch) { + return true; + } + } + } else if next == Some(']') { + // We have found the start of an Operating System Command, which + // extends until the next sequence "\x1b\\" (the String Terminator + // sequence) or the BEL character. The BEL character is non-standard, + // but it is still used quite often, for example, by GNU ls. + let mut last = ']'; + for new in chars { + if new == '\x07' || (new == '\\' && last == CSI.0) { + return true; + } + last = new; } } } @@ -90,6 +105,7 @@ fn ch_width(ch: char) -> usize { /// /// assert_eq!(display_width("Café Plain"), 10); /// assert_eq!(display_width("\u{1b}[31mCafé Rouge\u{1b}[0m"), 10); +/// assert_eq!(display_width("\x1b]8;;http://example.com\x1b\\This is a link\x1b]8;;\x1b\\"), 14); /// ``` /// /// **Note:** When the `unicode-width` Cargo feature is disabled, the @@ -404,6 +420,10 @@ mod tests { assert_eq!("Café Plain".len(), 11); // “é” is two bytes assert_eq!(display_width("Café Plain"), 10); assert_eq!(display_width("\u{1b}[31mCafé Rouge\u{1b}[0m"), 10); + assert_eq!( + display_width("\x1b]8;;http://example.com\x1b\\This is a link\x1b]8;;\x1b\\"), + 14 + ); } #[test]