@@ -6,6 +6,8 @@ use ansi_term::Style;
66
77use bytesize:: ByteSize ;
88
9+ use console:: AnsiCodeIterator ;
10+
911use syntect:: easy:: HighlightLines ;
1012use syntect:: highlighting:: Color ;
1113use syntect:: highlighting:: Theme ;
@@ -31,6 +33,7 @@ use crate::line_range::RangeCheckResult;
3133use crate :: preprocessor:: { expand_tabs, replace_nonprintable} ;
3234use crate :: style:: StyleComponent ;
3335use crate :: terminal:: { as_terminal_escaped, to_ansi_color} ;
36+ use crate :: vscreen:: AnsiStyle ;
3437use crate :: wrapping:: WrappingMode ;
3538
3639pub ( crate ) trait Printer {
@@ -119,6 +122,7 @@ pub(crate) struct InteractivePrinter<'a> {
119122 config : & ' a Config < ' a > ,
120123 decorations : Vec < Box < dyn Decoration > > ,
121124 panel_width : usize ,
125+ ansi_style : AnsiStyle ,
122126 content_type : Option < ContentType > ,
123127 #[ cfg( feature = "git" ) ]
124128 pub line_changes : & ' a Option < LineChanges > ,
@@ -202,6 +206,7 @@ impl<'a> InteractivePrinter<'a> {
202206 config,
203207 decorations,
204208 content_type : input. reader . content_type ,
209+ ansi_style : AnsiStyle :: new ( ) ,
205210 #[ cfg( feature = "git" ) ]
206211 line_changes,
207212 highlighter_from_set,
@@ -480,7 +485,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
480485 self . config . highlighted_lines . 0 . check ( line_number) == RangeCheckResult :: InRange ;
481486
482487 if highlight_this_line && self . config . theme == "ansi" {
483- write ! ( handle , " \x1B [4m") ? ;
488+ self . ansi_style . update ( "^ [4m") ;
484489 }
485490
486491 let background_color = self
@@ -507,37 +512,51 @@ impl<'a> Printer for InteractivePrinter<'a> {
507512 let italics = self . config . use_italic_text ;
508513
509514 for & ( style, region) in & regions {
510- let text = & * self . preprocess ( region, & mut cursor_total) ;
511- let text_trimmed = text. trim_end_matches ( |c| c == '\r' || c == '\n' ) ;
512-
513- write ! (
514- handle,
515- "{}" ,
516- as_terminal_escaped(
517- style,
518- text_trimmed,
519- true_color,
520- colored_output,
521- italics,
522- background_color
523- )
524- ) ?;
515+ let ansi_iterator = AnsiCodeIterator :: new ( region) ;
516+ for chunk in ansi_iterator {
517+ match chunk {
518+ // ANSI escape passthrough.
519+ ( ansi, true ) => {
520+ self . ansi_style . update ( ansi) ;
521+ write ! ( handle, "{}" , ansi) ?;
522+ }
525523
526- if text. len ( ) != text_trimmed. len ( ) {
527- if let Some ( background_color) = background_color {
528- let ansi_style = Style {
529- background : to_ansi_color ( background_color, true_color) ,
530- ..Default :: default ( )
531- } ;
532-
533- let width = if cursor_total <= cursor_max {
534- cursor_max - cursor_total + 1
535- } else {
536- 0
537- } ;
538- write ! ( handle, "{}" , ansi_style. paint( " " . repeat( width) ) ) ?;
524+ // Regular text.
525+ ( text, false ) => {
526+ let text = & * self . preprocess ( text, & mut cursor_total) ;
527+ let text_trimmed = text. trim_end_matches ( |c| c == '\r' || c == '\n' ) ;
528+
529+ write ! (
530+ handle,
531+ "{}" ,
532+ as_terminal_escaped(
533+ style,
534+ & format!( "{}{}" , self . ansi_style, text_trimmed) ,
535+ true_color,
536+ colored_output,
537+ italics,
538+ background_color
539+ )
540+ ) ?;
541+
542+ if text. len ( ) != text_trimmed. len ( ) {
543+ if let Some ( background_color) = background_color {
544+ let ansi_style = Style {
545+ background : to_ansi_color ( background_color, true_color) ,
546+ ..Default :: default ( )
547+ } ;
548+
549+ let width = if cursor_total <= cursor_max {
550+ cursor_max - cursor_total + 1
551+ } else {
552+ 0
553+ } ;
554+ write ! ( handle, "{}" , ansi_style. paint( " " . repeat( width) ) ) ?;
555+ }
556+ write ! ( handle, "{}" , & text[ text_trimmed. len( ) ..] ) ?;
557+ }
558+ }
539559 }
540- write ! ( handle, "{}" , & text[ text_trimmed. len( ) ..] ) ?;
541560 }
542561 }
543562
@@ -546,82 +565,98 @@ impl<'a> Printer for InteractivePrinter<'a> {
546565 }
547566 } else {
548567 for & ( style, region) in & regions {
549- let text = self . preprocess (
550- region. trim_end_matches ( |c| c == '\r' || c == '\n' ) ,
551- & mut cursor_total,
552- ) ;
553-
554- let mut max_width = cursor_max - cursor;
555-
556- // line buffer (avoid calling write! for every character)
557- let mut line_buf = String :: with_capacity ( max_width * 4 ) ;
558-
559- // Displayed width of line_buf
560- let mut current_width = 0 ;
561-
562- for c in text. chars ( ) {
563- // calculate the displayed width for next character
564- let cw = c. width ( ) . unwrap_or ( 0 ) ;
565- current_width += cw;
566-
567- // if next character cannot be printed on this line,
568- // flush the buffer.
569- if current_width > max_width {
570- // Generate wrap padding if not already generated.
571- if panel_wrap. is_none ( ) {
572- panel_wrap = if self . panel_width > 0 {
573- Some ( format ! (
574- "{} " ,
575- self . decorations
576- . iter( )
577- . map( |d| d. generate( line_number, true , self ) . text)
578- . collect:: <Vec <String >>( )
579- . join( " " )
580- ) )
581- } else {
582- Some ( "" . to_string ( ) )
583- }
568+ let ansi_iterator = AnsiCodeIterator :: new ( region) ;
569+ for chunk in ansi_iterator {
570+ match chunk {
571+ // ANSI escape passthrough.
572+ ( ansi, true ) => {
573+ self . ansi_style . update ( ansi) ;
574+ write ! ( handle, "{}" , ansi) ?;
584575 }
585576
586- // It wraps.
587- write ! (
588- handle,
589- "{}\n {}" ,
590- as_terminal_escaped(
591- style,
592- & line_buf,
593- self . config. true_color,
594- self . config. colored_output,
595- self . config. use_italic_text,
596- background_color
597- ) ,
598- panel_wrap. clone( ) . unwrap( )
599- ) ?;
600-
601- cursor = 0 ;
602- max_width = cursor_max;
603-
604- line_buf. clear ( ) ;
605- current_width = cw;
606- }
577+ // Regular text.
578+ ( text, false ) => {
579+ let text = self . preprocess (
580+ text. trim_end_matches ( |c| c == '\r' || c == '\n' ) ,
581+ & mut cursor_total,
582+ ) ;
583+
584+ let mut max_width = cursor_max - cursor;
585+
586+ // line buffer (avoid calling write! for every character)
587+ let mut line_buf = String :: with_capacity ( max_width * 4 ) ;
588+
589+ // Displayed width of line_buf
590+ let mut current_width = 0 ;
591+
592+ for c in text. chars ( ) {
593+ // calculate the displayed width for next character
594+ let cw = c. width ( ) . unwrap_or ( 0 ) ;
595+ current_width += cw;
596+
597+ // if next character cannot be printed on this line,
598+ // flush the buffer.
599+ if current_width > max_width {
600+ // Generate wrap padding if not already generated.
601+ if panel_wrap. is_none ( ) {
602+ panel_wrap = if self . panel_width > 0 {
603+ Some ( format ! (
604+ "{} " ,
605+ self . decorations
606+ . iter( )
607+ . map( |d| d
608+ . generate( line_number, true , self )
609+ . text)
610+ . collect:: <Vec <String >>( )
611+ . join( " " )
612+ ) )
613+ } else {
614+ Some ( "" . to_string ( ) )
615+ }
616+ }
617+
618+ // It wraps.
619+ write ! (
620+ handle,
621+ "{}\n {}" ,
622+ as_terminal_escaped(
623+ style,
624+ & * format!( "{}{}" , self . ansi_style, line_buf) ,
625+ self . config. true_color,
626+ self . config. colored_output,
627+ self . config. use_italic_text,
628+ background_color
629+ ) ,
630+ panel_wrap. clone( ) . unwrap( )
631+ ) ?;
632+
633+ cursor = 0 ;
634+ max_width = cursor_max;
635+
636+ line_buf. clear ( ) ;
637+ current_width = cw;
638+ }
639+
640+ line_buf. push ( c) ;
641+ }
607642
608- line_buf. push ( c) ;
643+ // flush the buffer
644+ cursor += current_width;
645+ write ! (
646+ handle,
647+ "{}" ,
648+ as_terminal_escaped(
649+ style,
650+ & * format!( "{}{}" , self . ansi_style, line_buf) ,
651+ self . config. true_color,
652+ self . config. colored_output,
653+ self . config. use_italic_text,
654+ background_color
655+ )
656+ ) ?;
657+ }
658+ }
609659 }
610-
611- // flush the buffer
612- cursor += current_width;
613- write ! (
614- handle,
615- "{}" ,
616- as_terminal_escaped(
617- style,
618- & line_buf,
619- self . config. true_color,
620- self . config. colored_output,
621- self . config. use_italic_text,
622- background_color
623- )
624- ) ?;
625660 }
626661
627662 if let Some ( background_color) = background_color {
@@ -640,6 +675,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
640675 }
641676
642677 if highlight_this_line && self . config . theme == "ansi" {
678+ self . ansi_style . update ( "^[24m" ) ;
643679 write ! ( handle, "\x1B [24m" ) ?;
644680 }
645681
0 commit comments