diff --git a/example.js b/example.js
index 2e6d824..1a6585d 100644
--- a/example.js
+++ b/example.js
@@ -3,31 +3,42 @@ const chalk = require('chalk');
const Ora = require('.');
const spinner = new Ora({
+ discardStdin: false,
+ text: 'Loading unicorns, not discarding stdin',
+ spinner: process.argv[2]
+});
+
+const spinnerDiscardingStdin = new Ora({
text: 'Loading unicorns',
spinner: process.argv[2]
});
-spinner.start();
+spinnerDiscardingStdin.start();
+
+setTimeout(() => {
+ spinnerDiscardingStdin.succeed();
+ spinner.start();
+}, 3000);
setTimeout(() => {
spinner.color = 'yellow';
spinner.text = `Loading ${chalk.red('rainbows')}`;
-}, 1000);
+}, 4000);
setTimeout(() => {
spinner.color = 'green';
spinner.indent = 2;
spinner.text = 'Loading with indent';
-}, 2000);
+}, 5000);
setTimeout(() => {
spinner.indent = 0;
spinner.spinner = 'moon';
spinner.text = 'Loading with different spinners';
-}, 3000);
+}, 6000);
setTimeout(() => {
spinner.succeed();
-}, 4000);
+}, 7000);
// $ node example.js nameOfSpinner
diff --git a/index.d.ts b/index.d.ts
index e1d4f18..29abbc4 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -89,6 +89,13 @@ declare namespace ora {
Note that `{isEnabled: false}` doesn't mean it won't output anything. It just means it won't output the spinner, colors, and other ansi escape codes. It will still log text.
*/
readonly isEnabled?: boolean;
+
+ /**
+ Discard stdin input (except Ctrl+C) while running if it's TTY. This prevents the spinner from twitching on input, outputting broken lines on `Enter` key presses, and prevents buffering of input while the spinner is running.
+
+ @default true
+ */
+ readonly discardStdin?: boolean;
}
interface PersistOptions {
diff --git a/index.js b/index.js
index 028db28..617b808 100644
--- a/index.js
+++ b/index.js
@@ -9,6 +9,10 @@ const wcwidth = require('wcwidth');
const TEXT = Symbol('text');
const PREFIX_TEXT = Symbol('prefixText');
+const noop = () => {};
+
+const ASCII_ETX_CODE = 0x03; // Ctrl+C emits this code
+
class Ora {
constructor(options) {
if (typeof options === 'string') {
@@ -20,7 +24,8 @@ class Ora {
this.options = Object.assign({
text: '',
color: 'cyan',
- stream: process.stderr
+ stream: process.stderr,
+ discardStdin: true
}, options);
this.spinner = this.options.spinner;
@@ -37,6 +42,7 @@ class Ora {
this.prefixText = this.options.prefixText;
this.linesToClear = 0;
this.indent = this.options.indent;
+ this.discardStdin = this.options.discardStdin;
}
get indent() {
@@ -166,6 +172,10 @@ class Ora {
cliCursor.hide(this.stream);
}
+ if (this.discardStdin && process.stdin.isTTY) {
+ this.startDiscardingStdin();
+ }
+
this.render();
this.id = setInterval(this.render.bind(this), this.interval);
@@ -185,9 +195,55 @@ class Ora {
cliCursor.show(this.stream);
}
+ if (this.discardStdin && process.stdin.isTTY) {
+ this.stopDiscardingStdin();
+ }
+
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);
+
+ const self = this;
+ stdin.emit = function (event, data, ...args) {
+ 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});
}
diff --git a/index.test-d.ts b/index.test-d.ts
index b2caf9d..3ff2f99 100644
--- a/index.test-d.ts
+++ b/index.test-d.ts
@@ -15,6 +15,7 @@ ora({indent: 1});
ora({interval: 80});
ora({stream: new PassThroughStream()});
ora({isEnabled: true});
+ora({discardStdin: true});
spinner.color = 'yellow';
spinner.text = 'Loading rainbows';
diff --git a/readme.md b/readme.md
index 114ffee..9219ec2 100644
--- a/readme.md
+++ b/readme.md
@@ -116,6 +116,13 @@ Force enable/disable the spinner. If not specified, the spinner will be enabled
Note that `{isEnabled: false}` doesn't mean it won't output anything. It just means it won't output the spinner, colors, and other ansi escape codes. It will still log text.
+##### discardStdin
+
+Type: `boolean`
+Default: `true`
+
+Discard stdin input (except Ctrl+C) while running if it's TTY. This prevents the spinner from twitching on input, outputting broken lines on Enter key presses, and prevents buffering of input while the spinner is running.
+
### Instance
#### .start([text])