@@ -27,54 +27,74 @@ function getIcon(task: Task) {
27
27
}
28
28
}
29
29
30
- function render ( tasks : Task [ ] ) : string {
30
+ function render ( tasks : Task [ ] , width : number ) : string {
31
31
const all = getTests ( tasks )
32
- const output : string [ ] = [ ]
32
+ let currentIcon = pending
33
+ let currentTasks = 0
34
+ let previousLineWidth = 0
35
+ let output = ''
33
36
34
37
// The log-update uses various ANSI helper utilities, e.g. ansi-warp, ansi-slice,
35
38
// when printing. Passing it hundreds of single characters containing ANSI codes reduces
36
39
// performances. We can optimize it by reducing amount of ANSI codes, e.g. by coloring
37
40
// multiple tasks at once instead of each task separately.
38
- let currentIcon = pending
39
- let currentTasks = 0
40
-
41
- const addOutput = ( ) => output . push ( currentIcon . color ( currentIcon . char . repeat ( currentTasks ) ) )
41
+ const addOutput = ( ) => {
42
+ const { char, color } = currentIcon
43
+ const availableWidth = width - previousLineWidth
44
+ if ( availableWidth > currentTasks ) {
45
+ output += color ( char . repeat ( currentTasks ) )
46
+ previousLineWidth += currentTasks
47
+ }
48
+ else {
49
+ // We need to split the line otherwise it will mess up log-update's height calculation
50
+ // and spam the scrollback buffer with dots.
51
+
52
+ // Fill the current line first
53
+ let buf = `${ char . repeat ( availableWidth ) } \n`
54
+ const remaining = currentTasks - availableWidth
55
+
56
+ // Then fill as many full rows as possible
57
+ const fullRows = Math . floor ( remaining / width )
58
+ buf += `${ char . repeat ( width ) } \n` . repeat ( fullRows )
59
+
60
+ // Add remaining dots which don't make a full row
61
+ const partialRow = remaining % width
62
+ if ( partialRow > 0 ) {
63
+ buf += char . repeat ( partialRow )
64
+ previousLineWidth = partialRow
65
+ }
66
+ else {
67
+ previousLineWidth = 0
68
+ }
42
69
70
+ output += color ( buf )
71
+ }
72
+ }
43
73
for ( const task of all ) {
44
74
const icon = getIcon ( task )
45
- const isLast = all . indexOf ( task ) === all . length - 1
46
-
47
75
if ( icon === currentIcon ) {
48
76
currentTasks ++
49
-
50
- if ( isLast )
51
- addOutput ( )
52
-
53
77
continue
54
78
}
55
-
56
79
// Task mode/state has changed, add previous group to output
57
80
addOutput ( )
58
81
59
82
// Start tracking new group
60
83
currentTasks = 1
61
84
currentIcon = icon
62
-
63
- if ( isLast )
64
- addOutput ( )
65
85
}
66
-
67
- return output . join ( '' )
86
+ addOutput ( )
87
+ return output
68
88
}
69
89
70
90
export function createDotRenderer ( _tasks : Task [ ] , options : DotRendererOptions ) {
71
91
let tasks = _tasks
72
92
let timer : any
73
93
74
- const log = options . logger . logUpdate
94
+ const { logUpdate : log , outputStream } = options . logger
75
95
76
96
function update ( ) {
77
- log ( render ( tasks ) )
97
+ log ( render ( tasks , outputStream . columns ) )
78
98
}
79
99
80
100
return {
@@ -94,7 +114,7 @@ export function createDotRenderer(_tasks: Task[], options: DotRendererOptions) {
94
114
timer = undefined
95
115
}
96
116
log . clear ( )
97
- options . logger . log ( render ( tasks ) )
117
+ options . logger . log ( render ( tasks , outputStream . columns ) )
98
118
return this
99
119
} ,
100
120
clear ( ) {
0 commit comments