99 window ,
1010} from "vscode" ;
1111
12- import * as Util from 'util' ;
13-
1412
1513// create a decorator type that we use to decorate small numbers
1614const resultDecorationType = window . createTextEditorDecorationType ( {
@@ -23,10 +21,7 @@ const colorOfType = {
2321 'Console' : '#457abb' ,
2422 'Error' : 'red' ,
2523}
26- // TODO: if Node's Version of VSCode >=9.9, use default option
27- const inspectOptions : NodeJS . InspectOptions = { depth : 20 } ;
28-
29- type Data = { line : number , type : 'Expression' | 'Terminal' , value : any } ;
24+ type Data = { line : number , value : string } ;
3025type Result = { line : number , type : 'Value of Expression' | 'Console' | 'Error' , text : string , value : string } ;
3126
3227export default class Decorator {
@@ -45,19 +40,48 @@ export default class Decorator {
4540 }
4641
4742 async update ( data : Data ) {
43+ if ( ! data ) return ;
44+
45+ let result = this . format ( data ) ;
46+
47+ this . outputChannel . appendLine ( ` ${ result . value } ` ) ;
48+
49+ if ( result . type === 'Console' ) {
50+ result = this . mergeConsoleOutput ( result ) ;
51+ }
52+ this . updateWith ( result ) ;
53+ this . decorateAll ( ) ;
54+ }
55+ private format ( { line, value } : Data ) : Result {
56+ let match : RegExpExecArray ;
4857
49- let result = ( data . type === 'Expression' )
50- ? await this . formatExpressionValue ( data )
51- : this . formatTerminalOutput ( data ) ;
58+ if ( ( match = / ( ( \w * E r r o r (?: \s \[ [ ^ \] ] + \] ) ? : \s .* ) (?: \n \s * a t \s [ \s \S ] + ) ? ) $ / . exec ( value ) ) != null ) {
59+ return { line, type : 'Error' , text : match [ 1 ] , value : match [ 2 ] } ;
60+ }
61+ else if ( ( match = / ^ ` \{ ( \d + ) \} ` ( [ \s \S ] * ) $ / . exec ( value ) ) != null ) {
62+ let value = match [ 2 ] || '' ;
63+ return { line : + match [ 1 ] , type : 'Console' , text : value . replace ( / \r ? \n / g, ' ' ) , value } ;
64+ }
65+ else {
66+ return { line, type : 'Value of Expression' , text : value . replace ( / \r ? \n / g, ' ' ) , value } ;
67+ }
68+ }
69+ private mergeConsoleOutput ( { line, text, value } : Result ) {
70+ let output = this . lineToOutput . get ( line ) ;
71+ if ( output == null ) {
72+ this . lineToOutput . set ( line , output = { line, type : 'Console' , text : '' , value : '' } ) ;
73+ }
5274
53- if ( ! result ) return ;
75+ output . text += ( output . text && ', ' ) + text ;
76+ output . value += ( output . value && '\n' ) + value ;
5477
78+ return output ;
79+ }
80+ private updateWith ( { line, type, text, value } : Result ) {
5581 let decorator : DecorationOptions ;
5682
57- if ( ( decorator = this . lineToDecorator . get ( result . line ) ) == null ) {
58- let line = result . line ,
59- length = this . editor . document . getText ( new Range ( new Position ( line , 0 ) , new Position ( line , 37768 ) ) ) . length + 1 ,
60- pos = new Position ( line , length ) ;
83+ if ( ( decorator = this . lineToDecorator . get ( line ) ) == null ) {
84+ let pos = new Position ( line , Number . MAX_SAFE_INTEGER ) ;
6185
6286 decorator = {
6387 renderOptions : { before : { margin : '0 0 0 1em' } } ,
@@ -67,79 +91,11 @@ export default class Decorator {
6791 this . decorators . push ( decorator ) ;
6892 }
6993
70- decorator . renderOptions . before . color = colorOfType [ result . type ] ;
71- decorator . renderOptions . before . contentText = ` ${ result . text } ` ;
94+ decorator . renderOptions . before . color = colorOfType [ type ] ;
95+ decorator . renderOptions . before . contentText = ` ${ text } ` ;
7296
73- decorator . hoverMessage = new MarkdownString ( result . type ) ;
74- decorator . hoverMessage . appendCodeblock ( result . value , result . type === 'Error' ? 'text' : 'javascript' ) ;
75-
76- this . decorateAll ( ) ;
77- }
78- private async formatExpressionValue ( data : Data ) : Promise < Result > {
79- let result = data . value ;
80- switch ( typeof result ) {
81- case 'undefined' :
82- return null ;
83-
84- case 'object' :
85- if ( result . constructor && result . constructor . name === 'Promise' && result . then ) {
86- try {
87- data . value = await ( < Promise < any > > result ) ;
88- return data . value ? this . formatExpressionValue ( data ) : null ;
89- } catch ( error ) {
90- return {
91- line : data . line ,
92- type : 'Error' ,
93- text : `${ error . name } : ${ error . message } ` ,
94- value : error . stack ,
95- }
96- }
97- }
98-
99- let string = Util . inspect ( result , inspectOptions ) ;
100- return {
101- line : data . line ,
102- type : 'Value of Expression' ,
103- text : string . replace ( / \n / g, ' ' ) ,
104- value : string ,
105- }
106-
107- default :
108- return {
109- line : data . line ,
110- type : 'Value of Expression' ,
111- text : result . toString ( ) . replace ( / \r ? \n / g, ' ' ) ,
112- value : result ,
113- }
114- }
115- }
116- private formatTerminalOutput ( data : Data ) : Result {
117- let out = data . value as string ;
118- let match : RegExpExecArray ;
119-
120- if ( ( match = / ^ ( \w * E r r o r (?: \[ [ ^ \] ] + \] ) ? : \s .* ) (?: \n \s * a t \s ) ? / . exec ( out ) ) != null ) {
121- this . outputChannel . appendLine ( ` ${ out } ` ) ;
122-
123- return { line : data . line , type : 'Error' , text : match [ 1 ] , value : out } ;
124- }
125- else if ( ( match = / ^ ` \{ ( \d + ) \} ` ( [ \s \S ] * ) $ / . exec ( out ) ) != null ) {
126- let line = + match [ 1 ] ;
127- let msg = match [ 2 ] || '' ;
128-
129- let output = this . lineToOutput . get ( line ) ;
130- if ( output == null ) {
131- this . lineToOutput . set ( line , output = { line, type : 'Console' , text : '' , value : '' } ) ;
132- }
133-
134- output . text += ( output . text && ', ' ) + msg . replace ( / \r ? \n / g, ' ' ) ;
135- output . value += ( output . value && '\n' ) + msg ;
136-
137- this . outputChannel . appendLine ( ` ${ msg } ` ) ;
138- return output ;
139- }
140- else {
141- this . outputChannel . appendLine ( ` ${ out } ` ) ;
142- }
97+ decorator . hoverMessage = new MarkdownString ( type )
98+ . appendCodeblock ( value , type === 'Error' ? 'text' : 'javascript' ) ;
14399 }
144100
145101 decorateAll ( ) {
0 commit comments