From de85060f56fda11c0705c69f4f0430532f85aaca Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Wed, 2 Oct 2019 18:27:25 +0300 Subject: [PATCH] made stdin discarder singleton --- index.js | 137 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 51 deletions(-) diff --git a/index.js b/index.js index ba61ae2..24995a0 100644 --- a/index.js +++ b/index.js @@ -11,9 +11,88 @@ const TEXT = Symbol('text'); const PREFIX_TEXT = Symbol('prefixText'); const noop = () => {}; - const ASCII_ETX_CODE = 0x03; // Ctrl+C emits this code +class StdinDiscarder { + constructor() { + this.requests = 0; + + const self = this; + this.ourEmit = function (event, data, ...args) { + const {stdin} = process; + if (self.requests > 0 || stdin.emit === self.ourEmit) { + if (event === 'keypress') { // Fixes readline behavior + return; + } + + if (event === 'data' && data.includes(ASCII_ETX_CODE)) { + process.emit('SIGINT'); + } + + self.oldEmit.apply(this, [event, data, ...args]); + } else { + process.stdin.emit.apply(this, [event, data, ...args]); + } + }; + } + + start() { + this.requests++; + + if (this.requests === 1) { + this.realStart(); + } + } + + stop() { + if (this.requests <= 0) { + throw new Error('`stop` called more times than `start`'); + } + + this.requests--; + + if (this.requests === 0) { + this.realStop(); + } + } + + realStart() { + const {stdin} = process; + + this.oldRawMode = stdin.isRaw; + this.oldEmit = stdin.emit; + this.oldEmitOwnProperty = Object.prototype.hasOwnProperty.call(stdin, 'emit'); + + stdin.setRawMode(true); + stdin.on('data', noop); + stdin.resume(); + + stdin.emit = this.ourEmit; + } + + realStop() { + const {stdin} = process; + + if (this.oldEmitOwnProperty) { + stdin.emit = this.oldEmit; + } else { + delete stdin.emit; + } + + this.oldRawMode = undefined; + this.oldEmit = undefined; + this.oldEmitOwnProperty = undefined; + + stdin.setRawMode(this.oldRawMode); + stdin.removeListener('data', noop); + if (stdin.listenerCount('data') === 0) { + stdin.pause(); + } + } +} + +const stdinDiscarder = new StdinDiscarder(); + class Ora { constructor(options) { if (typeof options === 'string') { @@ -45,6 +124,7 @@ class Ora { this.linesToClear = 0; this.indent = this.options.indent; this.discardStdin = this.options.discardStdin; + this.isDiscardingStdin = false; } get indent() { @@ -183,7 +263,8 @@ class Ora { } if (this.discardStdin && process.stdin.isTTY) { - this.startDiscardingStdin(); + this.isDiscardingStdin = true; + stdinDiscarder.start(); } this.render(); @@ -205,60 +286,14 @@ class Ora { cliCursor.show(this.stream); } - if (this.discardStdin && process.stdin.isTTY) { - this.stopDiscardingStdin(); + if (this.discardStdin && process.stdin.isTTY && this.isDiscardingStdin) { + stdinDiscarder.stop(); + this.isDiscardingStdin = false; } return this; } - startDiscardingStdin() { - const {stdin} = process; - - this._stdinOldRawMode = stdin.isRaw; - this._stdinOldEmit = stdin.emit; - this._stdinOldEmitOwnProperty = Object.prototype.hasOwnProperty.call(stdin, 'emit'); - - stdin.setRawMode(true); - stdin.on('data', noop); - stdin.resume(); - - const self = this; - stdin.emit = function (event, data, ...args) { - if (event === 'keypress') { // Fixes readline behavior - return; - } - - if (event === 'data' && data.includes(ASCII_ETX_CODE)) { - process.emit('SIGINT'); - } - - self._stdinOldEmit.apply(this, [event, data, ...args]); - }; - } - - stopDiscardingStdin() { - if (this._stdinOldEmit !== undefined) { - const {stdin} = process; - stdin.setRawMode(this._stdinOldRawMode); - stdin.removeListener('data', noop); - - if (stdin.listenerCount('data') === 0) { - stdin.pause(); - } - - if (this._stdinOldEmitOwnProperty) { - stdin.emit = this._stdinOldEmit; - } else { - delete stdin.emit; - } - - this._stdinOldRawMode = undefined; - this._stdinOldEmit = undefined; - this._stdinOldEmitOwnProperty = undefined; - } - } - succeed(text) { return this.stopAndPersist({symbol: logSymbols.success, text}); }