UNPKG

@wwa/single-line-log

Version:

Keep writing to the same line in the terminal. Very useful when you write progress bars, or a status message during longer operations

82 lines (67 loc) 1.91 kB
const stringWidth = require('string-width').default; const MOVE_LEFT = '\u001b[1000D'; // Move cursor to start of line const MOVE_UP = '\u001b[1A'; // Move cursor up one line const CLEAR_LINE = '\u001b[0K'; // Clear line from cursor to end const CLEAR_CURRENT = MOVE_LEFT + CLEAR_LINE; /** * Creates a logger that overwrites previous output. * * @param {import('tty').WriteStream} stream The output stream (stdout or stderr) */ module.exports = function(stream) { if (!stream || typeof stream.write !== 'function') { throw new TypeError('Expected a writable stream'); } const write = stream.write; /** @var {string|null} */ let str; stream.write = function(data) { if (str && data !== str) { str = null; } return write.apply(this, arguments); }; if (stream === process.stderr || stream === process.stdout) { process.on('exit', function() { if (str !== null) { stream.write(''); } }); } let prevLineCount = 0; /** * Log function that overwrites previous output. * * @param {...unknown[]} args Arguments to log */ const log = function(...args) { str = ''; const nextStr = args.join(' '); if (stream.isTTY) { // Clear screen for (let i = 0; i < prevLineCount; ++i) { str += CLEAR_CURRENT + (i < prevLineCount - 1 ? MOVE_UP : ''); } } str += nextStr; stream.write(str); if (stream.isTTY && stream.columns) { const prevLines = nextStr.split('\n'); const { columns } = stream; prevLineCount = 0; let i = prevLines.length; while (i--) { const lineWidth = stringWidth(prevLines[i]); prevLineCount += Math.max(1, Math.ceil(lineWidth / columns)); } } else { prevLineCount = nextStr.split('\n').length; } }; log.clear = function() { stream.write(''); }; return log; }; module.exports.stdout = module.exports(process.stdout); module.exports.stderr = module.exports(process.stderr);