Skip to content

Commit 43fef4b

Browse files
committed
ansi: strip DCS sequences
Treat DCS as non-printing, including the DCS wrapper used by tmux passthrough. Adds a regression test for tmux-wrapped OSC 8 hyperlinks.
1 parent e7cf2f5 commit 43fef4b

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

src/ansi.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,41 @@ fn consume_osc_end_exclusive(it: &mut Peekable<CharIndices<'_>>, start: usize) -
3131
end
3232
}
3333

34+
fn consume_dcs_end_exclusive(it: &mut Peekable<CharIndices<'_>>, start: usize) -> usize {
35+
let mut end = start + 1;
36+
let Some((idx, 'P')) = it.next() else {
37+
return end;
38+
};
39+
end = idx + 1;
40+
41+
while let Some((idx, c)) = it.next() {
42+
end = idx + c.len_utf8();
43+
match c {
44+
'\u{9c}' => return end,
45+
'\u{1b}' => {
46+
let Some((next_idx, next)) = it.peek() else {
47+
return end;
48+
};
49+
match next {
50+
'\u{1b}' => {
51+
end = *next_idx + 1;
52+
it.next();
53+
}
54+
'\\' => {
55+
end = *next_idx + 1;
56+
it.next();
57+
return end;
58+
}
59+
_ => {}
60+
}
61+
}
62+
_ => {}
63+
}
64+
}
65+
66+
end
67+
}
68+
3469
fn find_dfa_end_exclusive_after_entry(it: &mut Peekable<CharIndices<'_>>) -> Option<usize> {
3570
let mut state = State::S1;
3671
let mut maybe_end = None;
@@ -197,6 +232,7 @@ fn find_ansi_code_exclusive(it: &mut Peekable<CharIndices>) -> Option<(usize, us
197232
it.next();
198233
match it.peek() {
199234
Some((_, ']')) => return Some((start, consume_osc_end_exclusive(it, start))),
235+
Some((_, 'P')) => return Some((start, consume_dcs_end_exclusive(it, start))),
200236
_ => {
201237
if let Some(end) = find_dfa_end_exclusive_after_entry(it) {
202238
return Some((start, end));
@@ -338,6 +374,7 @@ mod tests {
338374
Regex::new(concat!(
339375
r"(?s)(?:",
340376
r"\x1b\].*?(?:\x07|\x9c|\x1b\\|\z)|",
377+
r"\x1bP(?:[^\x1b\x9c]|\x1b\x1b|\x1b[^\x1b\\])*?(?:\x9c|\x1b\\|\x1b\z|\z)|",
341378
r"[\x1b\x9b]([()][012AB]|[\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?",
342379
r"[0-9A-PRZcf-nqry=><])",
343380
r")",
@@ -467,6 +504,13 @@ mod tests {
467504
assert_eq!(strip_ansi_codes(s).as_ref(), "hello");
468505
}
469506

507+
#[test]
508+
fn strip_tmux_passthrough_dcs() {
509+
let open = "\x1bPtmux;\x1b\x1b\x1b]8;;file:///tmp/test\x1b\x1b\\\x1b\\";
510+
let close = "\x1bPtmux;\x1b\x1b\x1b]8;;\x1b\x1b\\\x1b\\";
511+
assert_eq!(strip_ansi_codes(&format!("{open}hello{close}")).as_ref(), "hello");
512+
}
513+
470514
#[test]
471515
fn test_ansi_iter_re_vt100() {
472516
let s = "\x1b(0lpq\x1b)Benglish";

0 commit comments

Comments
 (0)