@@ -30,6 +30,7 @@ use crate::input::OpenedInput;
3030use crate::line_range::RangeCheckResult;
3131use crate::preprocessor::{expand_tabs, replace_nonprintable};
3232use crate::terminal::{as_terminal_escaped, to_ansi_color};
33+use crate::vscreen::AnsiStyle;
3334use crate::wrapping::WrappingMode;
3435
3536pub(crate) trait Printer {
@@ -118,7 +119,7 @@ pub(crate) struct InteractivePrinter<'a> {
118119 config: &'a Config<'a>,
119120 decorations: Vec<Box<dyn Decoration>>,
120121 panel_width: usize,
121− ansi_prefix_sgr: String,
122+ ansi_style: AnsiStyle,
122123 content_type: Option<ContentType>,
123124 #[cfg(feature = "git")]
124125 pub line_changes: &'a Option<LineChanges>,
@@ -202,7 +203,7 @@ impl<'a> InteractivePrinter<'a> {
202203 config,
203204 decorations,
204205 content_type: input.reader.content_type,
205− ansi_prefix_sgr: String::new(),
206+ ansi_style: AnsiStyle::new(),
206207 #[cfg(feature = "git")]
207208 line_changes,
208209 highlighter_from_set,
@@ -444,35 +445,51 @@ impl<'a> Printer for InteractivePrinter<'a> {
444445 let italics = self.config.use_italic_text;
445446
446447 for &(style, region) in ®ions {
447− let text = &*self.preprocess(region, &mut cursor_total);
448− let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n');
449− write!(
450− handle,
451− "{}",
452− as_terminal_escaped(
453− style,
454− text_trimmed,
455− true_color,
456− colored_output,
457− italics,
458− background_color
459− )
460− )?;
448+ let ansi_iterator = AnsiCodeIterator::new(region);
449+ for chunk in ansi_iterator {
450+ match chunk {
451+ // ANSI escape passthrough.
452+ (ansi, true) => {
453+ self.ansi_style.update(ansi);
454+ write!(handle, "{}", ansi)?;
455+ }
461456
462− if text.len() != text_trimmed.len() {
463− if let Some(background_color) = background_color {
464− let ansi_style = Style {
465− background: to_ansi_color(background_color, true_color),
466− ..Default::default()
467− };
468− let width = if cursor_total <= cursor_max {
469− cursor_max - cursor_total + 1
470− } else {
471− 0
472− };
473− write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?;
457+ // Regular text.
458+ (text, false) => {
459+ let text = &*self.preprocess(text, &mut cursor_total);
460+ let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n');
461+
462+ write!(
463+ handle,
464+ "{}",
465+ as_terminal_escaped(
466+ style,
467+ &format!("{}{}", self.ansi_style, text_trimmed),
468+ true_color,
469+ colored_output,
470+ italics,
471+ background_color
472+ )
473+ )?;
474+
475+ if text.len() != text_trimmed.len() {
476+ if let Some(background_color) = background_color {
477+ let ansi_style = Style {
478+ background: to_ansi_color(background_color, true_color),
479+ ..Default::default()
480+ };
481+
482+ let width = if cursor_total <= cursor_max {
483+ cursor_max - cursor_total + 1
484+ } else {
485+ 0
486+ };
487+ write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?;
488+ }
489+ write!(handle, "{}", &text[text_trimmed.len()..])?;
490+ }
491+ }
474492 }
475− write!(handle, "{}", &text[text_trimmed.len()..])?;
476493 }
477494 }
478495
@@ -482,31 +499,12 @@ impl<'a> Printer for InteractivePrinter<'a> {
482499 } else {
483500 for &(style, region) in ®ions {
484501 let ansi_iterator = AnsiCodeIterator::new(region);
485− let mut ansi_prefix: String = String::new();
486502 for chunk in ansi_iterator {
487503 match chunk {
488504 // ANSI escape passthrough.
489− (text, true) => {
490− let is_ansi_csi = text.starts_with("\x1B[");
491−
492− if is_ansi_csi && text.ends_with('m') {
493− // It's an ANSI SGR sequence.
494− // We should be mostly safe to just append these together.
495− ansi_prefix.push_str(text);
496− if text == "\x1B[0m" {
497− self.ansi_prefix_sgr = "\x1B[0m".to_owned();
498− } else {
499− self.ansi_prefix_sgr.push_str(text);
500− }
501− } else if is_ansi_csi {
502− // It's a regular CSI sequence.
503− // We should be mostly safe to just append these together.
504− ansi_prefix.push_str(text);
505− } else {
506− // It's probably a VT100 code.
507− // Passing it through is the safest bet.
508− write!(handle, "{}", text)?;
509− }
505+ (ansi, true) => {
506+ self.ansi_style.update(ansi);
507+ write!(handle, "{}", ansi)?;
510508 }
511509
512510 // Regular text.
@@ -556,10 +554,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
556554 "{}\n{}",
557555 as_terminal_escaped(
558556 style,
559− &*format!(
560− "{}{}{}",
561− self.ansi_prefix_sgr, ansi_prefix, line_buf
562− ),
557+ &*format!("{}{}", self.ansi_style, line_buf),
563558 self.config.true_color,
564559 self.config.colored_output,
565560 self.config.use_italic_text,
@@ -585,19 +580,13 @@ impl<'a> Printer for InteractivePrinter<'a> {
585580 "{}",
586581 as_terminal_escaped(
587582 style,
588− &*format!(
589− "{}{}{}",
590− self.ansi_prefix_sgr, ansi_prefix, line_buf
591− ),
583+ &*format!("{}{}", self.ansi_style, line_buf),
592584 self.config.true_color,
593585 self.config.colored_output,
594586 self.config.use_italic_text,
595587 background_color
596588 )
597589 )?;
598−
599− // Clear the ANSI prefix buffer.
600− ansi_prefix.clear();
601590 }
602591 }
603592 }