@@ -500,6 +500,9 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
500
500
// We can never split RTL text, as it ruins the rendering
501
501
tokens = splitLargeTokens ( lineContent , tokens , ! input . isBasicASCII || input . fontLigatures ) ;
502
502
}
503
+ if ( input . renderControlCharacters && ! input . isBasicASCII ) {
504
+ tokens = extractControlCharacters ( lineContent , tokens ) ;
505
+ }
503
506
504
507
return new ResolvedRenderLineInput (
505
508
input . useMonospaceOptimizations ,
@@ -621,6 +624,67 @@ function splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces:
621
624
return result ;
622
625
}
623
626
627
+ function isControlCharacter ( charCode : number ) : boolean {
628
+ if ( charCode < 32 ) {
629
+ return ( charCode !== CharCode . Tab ) ;
630
+ }
631
+ if ( charCode === 127 ) {
632
+ // DEL
633
+ return true ;
634
+ }
635
+
636
+ if (
637
+ ( charCode >= 0x202A && charCode <= 0x202E )
638
+ || ( charCode >= 0x2066 && charCode <= 0x2069 )
639
+ || ( charCode >= 0x200E && charCode <= 0x200F )
640
+ || charCode === 0x061C
641
+ ) {
642
+ // Unicode Directional Formatting Characters
643
+ // LRE U+202A LEFT-TO-RIGHT EMBEDDING
644
+ // RLE U+202B RIGHT-TO-LEFT EMBEDDING
645
+ // PDF U+202C POP DIRECTIONAL FORMATTING
646
+ // LRO U+202D LEFT-TO-RIGHT OVERRIDE
647
+ // RLO U+202E RIGHT-TO-LEFT OVERRIDE
648
+ // LRI U+2066 LEFT‑TO‑RIGHT ISOLATE
649
+ // RLI U+2067 RIGHT‑TO‑LEFT ISOLATE
650
+ // FSI U+2068 FIRST STRONG ISOLATE
651
+ // PDI U+2069 POP DIRECTIONAL ISOLATE
652
+ // LRM U+200E LEFT-TO-RIGHT MARK
653
+ // RLM U+200F RIGHT-TO-LEFT MARK
654
+ // ALM U+061C ARABIC LETTER MARK
655
+ return true ;
656
+ }
657
+
658
+ return false ;
659
+ }
660
+
661
+ function extractControlCharacters ( lineContent : string , tokens : LinePart [ ] ) : LinePart [ ] {
662
+ let result : LinePart [ ] = [ ] ;
663
+ let lastLinePart : LinePart = new LinePart ( 0 , '' , 0 ) ;
664
+ let charOffset = 0 ;
665
+ for ( const token of tokens ) {
666
+ const tokenEndIndex = token . endIndex ;
667
+ for ( ; charOffset < tokenEndIndex ; charOffset ++ ) {
668
+ const charCode = lineContent . charCodeAt ( charOffset ) ;
669
+ if ( isControlCharacter ( charCode ) ) {
670
+ if ( charOffset > lastLinePart . endIndex ) {
671
+ // emit previous part if it has text
672
+ lastLinePart = new LinePart ( charOffset , token . type , token . metadata ) ;
673
+ result . push ( lastLinePart ) ;
674
+ }
675
+ lastLinePart = new LinePart ( charOffset + 1 , 'mtkcontrol' , token . metadata ) ;
676
+ result . push ( lastLinePart ) ;
677
+ }
678
+ }
679
+ if ( charOffset > lastLinePart . endIndex ) {
680
+ // emit previous part if it has text
681
+ lastLinePart = new LinePart ( tokenEndIndex , token . type , token . metadata ) ;
682
+ result . push ( lastLinePart ) ;
683
+ }
684
+ }
685
+ return result ;
686
+ }
687
+
624
688
/**
625
689
* Whitespace is rendered by "replacing" tokens with a special-purpose `mtkw` type that is later recognized in the rendering phase.
626
690
* Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (→ or ·) do not have the same width as .
@@ -1005,6 +1069,11 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
1005
1069
} else if ( renderControlCharacters && charCode === 127 ) {
1006
1070
// DEL
1007
1071
sb . write1 ( 9249 ) ;
1072
+ } else if ( renderControlCharacters && isControlCharacter ( charCode ) ) {
1073
+ sb . appendASCIIString ( '[U+' ) ;
1074
+ sb . appendASCIIString ( to4CharHex ( charCode ) ) ;
1075
+ sb . appendASCIIString ( ']' ) ;
1076
+ producedCharacters = 8 ;
1008
1077
} else {
1009
1078
sb . write1 ( charCode ) ;
1010
1079
}
@@ -1049,3 +1118,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
1049
1118
1050
1119
return new RenderLineOutput ( characterMapping , containsRTL , containsForeignElements ) ;
1051
1120
}
1121
+
1122
+ function to4CharHex ( n : number ) : string {
1123
+ return n . toString ( 16 ) . toUpperCase ( ) . padStart ( 4 , '0' ) ;
1124
+ }
0 commit comments