Imagine building a progress indicator in Node. We could start with low level "print" calls
process.stdout.write('long message first')
This prints messages one after another on the same line
long message firstshort message
Hmm, not the best output, the words are printed on the same line. If we want to print the second message on the second line, we have to print "new line" character
process.stdout.write('long message first\n')
long message first
Note, this is what
console.log does by default - it adds
\n after each printed line.
But what if we send carriage return character
\r after the first message?
process.stdout.write('long message first\r')
Our output is garbled!
The second message is shorter and thus it overwrites only a part of the first line of text. We cannot have this; we need to clear the rest of the line every time we print it. We can print a string of spaces to clear the line - but we need to know how many spaces to print. Luckily there is a property
process.stdout.columns that tells us exactly how many characters are in the terminal. We can clear the current line by print an empty line +
\r before we print new text.
console.log('stdout width', process.stdout.columns)
stdout width 99
Then a second later the output becomes
stdout width 99
But what happens if our code runs in a terminal that is really feature-limited, like the output piped from the Docker build command? Here is a Docker file I will use
Status: Downloaded newer image for node:8
There is no
process.stdout.columns number, even if the carriage return works! So how do we show the second line? Well, we can take a shortcut and just do the "newline" instead!
const emptyLine = process.stdout.columns ? ''.padEnd(process.stdout.columns, ' ') : '\n'
and it works nicely in the terminal and in Docker
---> Running in 8d63833b96ac
Nice, except when you have progress bars ... which output thousands of messages when showing percentage increments for example. We have this problem when showing Cypress installation (see issue #1243) progress. The output log would just flood with thousands of identical lines like these
In this case we should treat using progress bars as an enhancement. By default the program should show only the text messages at the start and end of the action.
Installing Cypress (version: 1.4.2)
Only if we find that the terminal has
process.stdout.columns set, then we can use a more advanced printing and you can show progress indicators.
Note: the code is in repo bahmutov/test-line-return