@@ -6,6 +6,7 @@ interface ConsoleState {
66 foregroundColor : string | null ;
77 backgroundColor : string | null ;
88 carriageReturn : boolean ;
9+ lines : string [ ] ;
910 secret : boolean ;
1011}
1112
@@ -18,6 +19,7 @@ export class ColoredConsole {
1819 foregroundColor : null ,
1920 backgroundColor : null ,
2021 carriageReturn : false ,
22+ lines : [ ] ,
2123 secret : false ,
2224 } ;
2325
@@ -27,26 +29,13 @@ export class ColoredConsole {
2729 return this . targetElement . innerText ;
2830 }
2931
30- addLine ( line : string ) {
32+ processLine ( line : string ) : Element {
3133 // @ts -expect-error
3234 const re = / (?: \0 3 3 | \\ 0 3 3 ) (?: \[ ( .* ?) [ @ - ~ ] | \] .* ?(?: \0 0 7 | \0 3 3 \\ ) ) / g;
3335 let i = 0 ;
3436
35- if ( this . state . carriageReturn ) {
36- if ( line !== "\n" ) {
37- // don't remove if \r\n
38- this . targetElement . removeChild ( this . targetElement . lastChild ! ) ;
39- }
40- this . state . carriageReturn = false ;
41- }
42-
43- if ( line . includes ( "\r" ) ) {
44- this . state . carriageReturn = true ;
45- }
46-
4737 const lineSpan = document . createElement ( "span" ) ;
4838 lineSpan . classList . add ( "line" ) ;
49- this . targetElement . appendChild ( lineSpan ) ;
5039
5140 const addSpan = ( content : string ) => {
5241 if ( content === "" ) return ;
@@ -179,17 +168,52 @@ export class ColoredConsole {
179168 }
180169 }
181170 }
171+ addSpan ( line . substring ( i ) ) ;
172+ return lineSpan ;
173+ }
174+
175+ processLines ( ) {
182176 const atBottom =
183177 this . targetElement . scrollTop >
184178 this . targetElement . scrollHeight - this . targetElement . offsetHeight - 50 ;
179+ const prevCarriageReturn = this . state . carriageReturn ;
180+ const fragment = document . createDocumentFragment ( ) ;
185181
186- addSpan ( line . substring ( i ) ) ;
182+ if ( this . state . lines . length == 0 ) {
183+ return ;
184+ }
185+
186+ for ( const line of this . state . lines ) {
187+ if ( this . state . carriageReturn && line !== "\n" ) {
188+ if ( fragment . childElementCount ) {
189+ fragment . removeChild ( fragment . lastChild ! ) ;
190+ }
191+ }
192+ fragment . appendChild ( this . processLine ( line ) ) ;
193+ this . state . carriageReturn = line . includes ( "\r" ) ;
194+ }
195+
196+ if ( prevCarriageReturn && this . state . lines [ 0 ] !== "\n" ) {
197+ this . targetElement . replaceChild ( fragment , this . targetElement . lastChild ! ) ;
198+ } else {
199+ this . targetElement . appendChild ( fragment ) ;
200+ }
201+
202+ this . state . lines = [ ] ;
187203
188204 // Keep scroll at bottom
189205 if ( atBottom ) {
190206 this . targetElement . scrollTop = this . targetElement . scrollHeight ;
191207 }
192208 }
209+
210+ addLine ( line : string ) {
211+ // Processing of lines is deferred for performance reasons
212+ if ( this . state . lines . length == 0 ) {
213+ setTimeout ( ( ) => this . processLines ( ) , 0 ) ;
214+ }
215+ this . state . lines . push ( line ) ;
216+ }
193217}
194218
195219export const coloredConsoleStyles = `
0 commit comments