11'use strict' ;
2- var logUpdate = require ( 'log-update' ) ;
3- var colors = require ( '../colors' ) ;
2+ var cliCursor = require ( 'cli-cursor' ) ;
3+ var lastLineTracker = require ( 'last-line-stream/tracker' ) ;
4+ var StringDecoder = require ( 'string_decoder' ) . StringDecoder ;
45var plur = require ( 'plur' ) ;
6+ var colors = require ( '../colors' ) ;
57var beautifyStack = require ( '../beautify-stack' ) ;
68
79function MiniReporter ( ) {
@@ -14,7 +16,11 @@ function MiniReporter() {
1416 this . skipCount = 0 ;
1517 this . rejectionCount = 0 ;
1618 this . exceptionCount = 0 ;
17- this . finished = false ;
19+ this . currentStatus = '' ;
20+ this . statusLineCount = 0 ;
21+ this . lastLineTracker = lastLineTracker ( ) ;
22+ this . stream = process . stderr ;
23+ this . stringDecoder = new StringDecoder ( ) ;
1824}
1925
2026module . exports = MiniReporter ;
@@ -24,7 +30,7 @@ MiniReporter.prototype.start = function () {
2430} ;
2531
2632MiniReporter . prototype . test = function ( test ) {
27- var status = '\n ' ;
33+ var status = '' ;
2834 var title ;
2935
3036 if ( test . skip ) {
@@ -61,9 +67,7 @@ MiniReporter.prototype.unhandledError = function (err) {
6167} ;
6268
6369MiniReporter . prototype . finish = function ( ) {
64- this . finished = true ;
65-
66- var status = '\n' ;
70+ var status = '' ;
6771
6872 if ( this . passCount > 0 ) {
6973 status += ' ' + colors . pass ( this . passCount , 'passed' ) ;
@@ -134,9 +138,76 @@ MiniReporter.prototype.finish = function () {
134138} ;
135139
136140MiniReporter . prototype . write = function ( str ) {
137- logUpdate . stderr ( str ) ;
141+ cliCursor . hide ( ) ;
142+ this . currentStatus = str + '\n' ;
143+ this . _update ( ) ;
144+ this . statusLineCount = this . currentStatus . split ( '\n' ) . length ;
145+ } ;
146+
147+ MiniReporter . prototype . stdout = MiniReporter . prototype . stderr = function ( data ) {
148+ this . _update ( data ) ;
149+ } ;
150+
151+ MiniReporter . prototype . _update = function ( data ) {
152+ var str = '' ;
153+ var ct = this . statusLineCount ;
154+ var columns = process . stdout . columns ;
155+ var lastLine = this . lastLineTracker . lastLine ( ) ;
156+
157+ // Terminals automatically wrap text. We only need the last log line as seen on the screen.
158+ lastLine = lastLine . substring ( lastLine . length - ( lastLine . length % columns ) ) ;
159+
160+ // Don't delete the last log line if it's completely empty.
161+ if ( lastLine . length ) {
162+ ct ++ ;
163+ }
164+
165+ // Erase the existing status message, plus the last log line.
166+ str += eraseLines ( ct ) ;
167+
168+ // Rewrite the last log line.
169+ str += lastLine ;
138170
139- if ( this . finished ) {
140- logUpdate . stderr . done ( ) ;
171+ if ( str . length ) {
172+ this . stream . write ( str ) ;
173+ }
174+
175+ if ( data ) {
176+ // send new log data to the terminal, and update the last line status.
177+ this . lastLineTracker . update ( this . stringDecoder . write ( data ) ) ;
178+ this . stream . write ( data ) ;
179+ }
180+
181+ var currentStatus = this . currentStatus ;
182+ if ( currentStatus . length ) {
183+ lastLine = this . lastLineTracker . lastLine ( ) ;
184+ // We need a newline at the end of the last log line, before the status message.
185+ // However, if the last log line is the exact width of the terminal a newline is implied,
186+ // and adding a second will cause problems.
187+ if ( lastLine . length % columns ) {
188+ currentStatus = '\n' + currentStatus ;
189+ }
190+ // rewrite the status message.
191+ this . stream . write ( currentStatus ) ;
141192 }
142193} ;
194+
195+ // TODO(@jamestalamge): This should be fixed in log-update and ansi-escapes once we are confident it's a good solution.
196+ var CSI = '\u001b[' ;
197+ var ERASE_LINE = CSI + '2K' ;
198+ var CURSOR_TO_COLUMN_0 = CSI + '0G' ;
199+ var CURSOR_UP = CSI + '1A' ;
200+
201+ // Returns a string that will erase `count` lines from the end of the terminal.
202+ function eraseLines ( count ) {
203+ var clear = '' ;
204+
205+ for ( var i = 0 ; i < count ; i ++ ) {
206+ clear += ERASE_LINE + ( i < count - 1 ? CURSOR_UP : '' ) ;
207+ }
208+ if ( count ) {
209+ clear += CURSOR_TO_COLUMN_0 ;
210+ }
211+
212+ return clear ;
213+ }
0 commit comments