Skip to content

Commit 5c90eca

Browse files
committed
Strip OSC sequences before printing
This commit strips OSC (Operating System Command) sequences before printing lines. Eventually when time permits, I want to add back support for printing OSC sequences (and improve it to treat hyperlinks like an attribute). Until then, this should help prevent garbled output :)
1 parent 2e1ea1e commit 5c90eca

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

src/printer.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::line_range::RangeCheckResult;
3333
use crate::preprocessor::{expand_tabs, replace_nonprintable};
3434
use crate::style::StyleComponent;
3535
use crate::terminal::{as_terminal_escaped, to_ansi_color};
36-
use crate::vscreen::AnsiStyle;
36+
use crate::vscreen::{AnsiStyle, strip_problematic_sequences};
3737
use crate::wrapping::WrappingMode;
3838

3939
pub(crate) trait Printer {
@@ -520,7 +520,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
520520
let italics = self.config.use_italic_text;
521521

522522
for &(style, region) in &regions {
523-
let ansi_iterator = AnsiCodeIterator::new(region);
523+
let text = strip_problematic_sequences(region);
524+
let ansi_iterator = AnsiCodeIterator::new(&text);
524525
for chunk in ansi_iterator {
525526
match chunk {
526527
// ANSI escape passthrough.
@@ -573,7 +574,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
573574
}
574575
} else {
575576
for &(style, region) in &regions {
576-
let ansi_iterator = AnsiCodeIterator::new(region);
577+
let text = strip_problematic_sequences(region);
578+
let ansi_iterator = AnsiCodeIterator::new(&text);
577579
for chunk in ansi_iterator {
578580
match chunk {
579581
// ANSI escape passthrough.

src/vscreen.rs

+54-1
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,54 @@ impl<'a> Iterator for EscapeSequenceOffsetsIterator<'a> {
452452
}
453453
}
454454

455+
/// Strips problematic ANSI escape sequences from a string.
456+
///
457+
/// Ideally, this will be replaced with something that uses [[Attributes]] to create a table of char offsets
458+
/// -> absolute styles and style deltas. Something like that would let us simplify the printer (and support
459+
/// re-printing OSC hyperlink commands).
460+
pub fn strip_problematic_sequences(text: &str) -> String {
461+
use EscapeSequenceOffsets::*;
462+
463+
let mut buffer = String::with_capacity(text.len());
464+
for seq in EscapeSequenceOffsetsIterator::new(text) {
465+
match seq {
466+
Text { start, end } => buffer.push_str(&text[start..end]),
467+
Unknown { start, end } => buffer.push_str(&text[start..end]),
468+
469+
NF {
470+
start_sequence: start,
471+
start: _,
472+
end,
473+
} => buffer.push_str(&text[start..end]),
474+
475+
CSI {
476+
start_sequence: start,
477+
start_parameters: _,
478+
start_intermediates: _,
479+
start_final_byte: _,
480+
end,
481+
} => buffer.push_str(&text[start..end]),
482+
483+
OSC {
484+
start_sequence: _,
485+
start_command: _,
486+
start_terminator: _,
487+
end: _,
488+
} => {
489+
// TODO(eth-p): Support re-printing hyperlinks.
490+
// In the meantime, strip these.
491+
}
492+
}
493+
}
494+
495+
buffer
496+
}
497+
455498
#[cfg(test)]
456499
mod tests {
457-
use crate::vscreen::{EscapeSequenceOffsets, EscapeSequenceOffsetsIterator};
500+
use crate::vscreen::{
501+
strip_problematic_sequences, EscapeSequenceOffsets, EscapeSequenceOffsetsIterator,
502+
};
458503

459504
#[test]
460505
fn test_escape_sequence_offsets_iterator_parses_text() {
@@ -677,4 +722,12 @@ mod tests {
677722
);
678723
assert_eq!(iter.next(), None);
679724
}
725+
726+
#[test]
727+
fn test_strip_problematic_sequences() {
728+
assert_eq!(
729+
strip_problematic_sequences("text\x1B[33m\x1B]OSC\x1B\\\x1B(0"),
730+
"text\x1B[33m\x1B(0"
731+
);
732+
}
680733
}

0 commit comments

Comments
 (0)