@@ -6,6 +6,8 @@ use ansi_term::Style;
6
6
7
7
use bytesize:: ByteSize ;
8
8
9
+ use console:: AnsiCodeIterator ;
10
+
9
11
use syntect:: easy:: HighlightLines ;
10
12
use syntect:: highlighting:: Color ;
11
13
use syntect:: highlighting:: Theme ;
@@ -31,6 +33,7 @@ use crate::line_range::RangeCheckResult;
31
33
use crate :: preprocessor:: { expand_tabs, replace_nonprintable} ;
32
34
use crate :: style:: StyleComponent ;
33
35
use crate :: terminal:: { as_terminal_escaped, to_ansi_color} ;
36
+ use crate :: vscreen:: AnsiStyle ;
34
37
use crate :: wrapping:: WrappingMode ;
35
38
36
39
pub ( crate ) trait Printer {
@@ -119,6 +122,7 @@ pub(crate) struct InteractivePrinter<'a> {
119
122
config : & ' a Config < ' a > ,
120
123
decorations : Vec < Box < dyn Decoration > > ,
121
124
panel_width : usize ,
125
+ ansi_style : AnsiStyle ,
122
126
content_type : Option < ContentType > ,
123
127
#[ cfg( feature = "git" ) ]
124
128
pub line_changes : & ' a Option < LineChanges > ,
@@ -202,6 +206,7 @@ impl<'a> InteractivePrinter<'a> {
202
206
config,
203
207
decorations,
204
208
content_type : input. reader . content_type ,
209
+ ansi_style : AnsiStyle :: new ( ) ,
205
210
#[ cfg( feature = "git" ) ]
206
211
line_changes,
207
212
highlighter_from_set,
@@ -480,7 +485,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
480
485
self . config . highlighted_lines . 0 . check ( line_number) == RangeCheckResult :: InRange ;
481
486
482
487
if highlight_this_line && self . config . theme == "ansi" {
483
- write ! ( handle , " \x1B [4m") ? ;
488
+ self . ansi_style . update ( "^ [4m") ;
484
489
}
485
490
486
491
let background_color = self
@@ -507,37 +512,51 @@ impl<'a> Printer for InteractivePrinter<'a> {
507
512
let italics = self . config . use_italic_text ;
508
513
509
514
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
+ }
525
523
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
+ }
539
559
}
540
- write ! ( handle, "{}" , & text[ text_trimmed. len( ) ..] ) ?;
541
560
}
542
561
}
543
562
@@ -546,82 +565,98 @@ impl<'a> Printer for InteractivePrinter<'a> {
546
565
}
547
566
} else {
548
567
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) ?;
584
575
}
585
576
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
+ }
607
642
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
+ }
609
659
}
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
- ) ?;
625
660
}
626
661
627
662
if let Some ( background_color) = background_color {
@@ -640,6 +675,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
640
675
}
641
676
642
677
if highlight_this_line && self . config . theme == "ansi" {
678
+ self . ansi_style . update ( "^[24m" ) ;
643
679
write ! ( handle, "\x1B [24m" ) ?;
644
680
}
645
681
0 commit comments