Skip to content

Commit

Permalink
Discard stdin by default (#112)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <[email protected]>
  • Loading branch information
Yanis Benson and sindresorhus committed Sep 22, 2019
1 parent 8bcde17 commit b1f140b
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 6 deletions.
21 changes: 16 additions & 5 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 7 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
58 changes: 57 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const isInteractive = require('is-interactive');
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') {
Expand All @@ -21,7 +25,8 @@ class Ora {
this.options = Object.assign({
text: '',
color: 'cyan',
stream: process.stderr
stream: process.stderr,
discardStdin: true
}, options);

this.spinner = this.options.spinner;
Expand All @@ -38,6 +43,7 @@ class Ora {
this.prefixText = this.options.prefixText;
this.linesToClear = 0;
this.indent = this.options.indent;
this.discardStdin = this.options.discardStdin;
}

get indent() {
Expand Down Expand Up @@ -171,6 +177,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);

Expand All @@ -190,9 +200,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});
}
Expand Down
1 change: 1 addition & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
7 changes: 7 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,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`<br>
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 <kbd>Enter</kbd> key presses, and prevents buffering of input while the spinner is running.

### Instance

#### .start(text?)
Expand Down

0 comments on commit b1f140b

Please sign in to comment.