@@ -6,6 +6,7 @@ interface ConsoleState {
6
6
foregroundColor : string | null ;
7
7
backgroundColor : string | null ;
8
8
carriageReturn : boolean ;
9
+ lines : string [ ] ;
9
10
secret : boolean ;
10
11
}
11
12
@@ -18,6 +19,7 @@ export class ColoredConsole {
18
19
foregroundColor : null ,
19
20
backgroundColor : null ,
20
21
carriageReturn : false ,
22
+ lines : [ ] ,
21
23
secret : false ,
22
24
} ;
23
25
@@ -27,26 +29,13 @@ export class ColoredConsole {
27
29
return this . targetElement . innerText ;
28
30
}
29
31
30
- addLine ( line : string ) {
32
+ processLine ( line : string ) : Element {
31
33
// @ts -expect-error
32
34
const re = / (?: \0 3 3 | \\ 0 3 3 ) (?: \[ ( .* ?) [ @ - ~ ] | \] .* ?(?: \0 0 7 | \0 3 3 \\ ) ) / g;
33
35
let i = 0 ;
34
36
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
-
47
37
const lineSpan = document . createElement ( "span" ) ;
48
38
lineSpan . classList . add ( "line" ) ;
49
- this . targetElement . appendChild ( lineSpan ) ;
50
39
51
40
const addSpan = ( content : string ) => {
52
41
if ( content === "" ) return ;
@@ -179,17 +168,52 @@ export class ColoredConsole {
179
168
}
180
169
}
181
170
}
171
+ addSpan ( line . substring ( i ) ) ;
172
+ return lineSpan ;
173
+ }
174
+
175
+ processLines ( ) {
182
176
const atBottom =
183
177
this . targetElement . scrollTop >
184
178
this . targetElement . scrollHeight - this . targetElement . offsetHeight - 50 ;
179
+ const prevCarriageReturn = this . state . carriageReturn ;
180
+ const fragment = document . createDocumentFragment ( ) ;
185
181
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 = [ ] ;
187
203
188
204
// Keep scroll at bottom
189
205
if ( atBottom ) {
190
206
this . targetElement . scrollTop = this . targetElement . scrollHeight ;
191
207
}
192
208
}
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
+ }
193
217
}
194
218
195
219
export const coloredConsoleStyles = `
0 commit comments