diff options
author | Julien Gilli <julien.gilli@joyent.com> | 2014-09-22 13:21:11 -0700 |
---|---|---|
committer | Trevor Norris <trev.norris@gmail.com> | 2014-10-01 15:00:02 -0700 |
commit | 862cc28183b03f0e1a67b052b5c8250a3e2e8995 (patch) | |
tree | 5514582ca85ba2729988daddb9e5ea840f8e0d45 | |
parent | 8dc6be1747d3a48af56f89e973ecb5665f89a2e1 (diff) | |
download | node-862cc28183b03f0e1a67b052b5c8250a3e2e8995.tar.gz |
readline: should not require an output stream.
Passing null as the output stream to readline.Interface()'s constructor
is now supported. Any output written by readline is just discarded. It
makes it easier to use readline just as a line parser.
Fixes: https://github.com/joyent/node/issues/4408
Reviewed-by: Trevor Norris <trev.norris@gmail.com>
-rw-r--r-- | doc/api/readline.markdown | 13 | ||||
-rw-r--r-- | lib/readline.js | 54 | ||||
-rw-r--r-- | test/simple/test-readline-interface.js | 31 |
3 files changed, 81 insertions, 17 deletions
diff --git a/doc/api/readline.markdown b/doc/api/readline.markdown index 16bbd3c0c..6aab28679 100644 --- a/doc/api/readline.markdown +++ b/doc/api/readline.markdown @@ -30,7 +30,7 @@ the following values: - `input` - the readable stream to listen to (Required). - - `output` - the writable stream to write readline data to (Required). + - `output` - the writable stream to write readline data to (Optional). - `completer` - an optional function that is used for Tab autocompletion. See below for an example of using this. @@ -100,6 +100,9 @@ to `true` to prevent the cursor placement being reset to `0`. This will also resume the `input` stream used with `createInterface` if it has been paused. +If `output` is set to `null` or `undefined` when calling `createInterface`, the +prompt is not written. + ### rl.question(query, callback) Prepends the prompt with `query` and invokes `callback` with the user's @@ -109,6 +112,9 @@ with the user's response after it has been typed. This will also resume the `input` stream used with `createInterface` if it has been paused. +If `output` is set to `null` or `undefined` when calling `createInterface`, +nothing is displayed. + Example usage: interface.question('What is your favorite food?', function(answer) { @@ -130,8 +136,9 @@ Closes the `Interface` instance, relinquishing control on the `input` and ### rl.write(data[, key]) -Writes `data` to `output` stream. `key` is an object literal to represent a key -sequence; available if the terminal is a TTY. +Writes `data` to `output` stream, unless `output` is set to `null` or +`undefined` when calling `createInterface`. `key` is an object literal to +represent a key sequence; available if the terminal is a TTY. This will also resume the `input` stream if it has been paused. diff --git a/lib/readline.js b/lib/readline.js index a3f1b9d58..bafef00e0 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -68,7 +68,7 @@ function Interface(input, output, completer, terminal) { // backwards compat; check the isTTY prop of the output stream // when `terminal` was not specified - if (util.isUndefined(terminal)) { + if (util.isUndefined(terminal) && !util.isNullOrUndefined(output)) { terminal = !!output.isTTY; } @@ -142,11 +142,15 @@ function Interface(input, output, completer, terminal) { this.history = []; this.historyIndex = -1; - output.on('resize', onresize); + if (!util.isNullOrUndefined(output)) + output.on('resize', onresize); + self.once('close', function() { input.removeListener('keypress', onkeypress); input.removeListener('end', ontermend); - output.removeListener('resize', onresize); + if (!util.isNullOrUndefined(output)) { + output.removeListener('resize', onresize); + } }); } @@ -156,7 +160,10 @@ function Interface(input, output, completer, terminal) { inherits(Interface, EventEmitter); Interface.prototype.__defineGetter__('columns', function() { - return this.output.columns || Infinity; + var columns = Infinity; + if (this.output && this.output.columns) + columns = this.output.columns; + return columns; }); Interface.prototype.setPrompt = function(prompt) { @@ -177,7 +184,7 @@ Interface.prototype.prompt = function(preserveCursor) { if (!preserveCursor) this.cursor = 0; this._refreshLine(); } else { - this.output.write(this._prompt); + this._writeToOutput(this._prompt); } }; @@ -207,6 +214,13 @@ Interface.prototype._onLine = function(line) { } }; +Interface.prototype._writeToOutput = function _writeToOutput(stringToWrite) { + if (!util.isString(stringToWrite)) + throw new TypeError('stringToWrite must be a string'); + + if (!util.isNullOrUndefined(this.output)) + this.output.write(stringToWrite); +}; Interface.prototype._addHistory = function() { if (this.line.length === 0) return ''; @@ -245,11 +259,11 @@ Interface.prototype._refreshLine = function() { exports.clearScreenDown(this.output); // Write the prompt and the current buffer content. - this.output.write(line); + this._writeToOutput(line); // Force terminal to allocate a new line if (lineCols === 0) { - this.output.write(' '); + this._writeToOutput(' '); } // Move cursor to original position. @@ -351,7 +365,7 @@ Interface.prototype._insertString = function(c) { if (this._getCursorPos().cols === 0) { this._refreshLine(); } else { - this.output.write(c); + this._writeToOutput(c); } // a hack to get the line refreshed if it's needed @@ -378,7 +392,7 @@ Interface.prototype._tabComplete = function() { if (completions.length === 1) { self._insertString(completions[0].slice(completeOn.length)); } else { - self.output.write('\r\n'); + self._writeToOutput('\r\n'); var width = completions.reduce(function(a, b) { return a.length > b.length ? a : b; }).length + 2; // 2 space padding @@ -422,17 +436,17 @@ function handleGroup(self, group, width, maxColumns) { break; } var item = group[idx]; - self.output.write(item); + self._writeToOutput(item); if (col < maxColumns - 1) { for (var s = 0, itemLen = item.length; s < width - itemLen; s++) { - self.output.write(' '); + self._writeToOutput(' '); } } } - self.output.write('\r\n'); + self._writeToOutput('\r\n'); } - self.output.write('\r\n'); + self._writeToOutput('\r\n'); } function commonPrefix(strings) { @@ -525,7 +539,7 @@ Interface.prototype._deleteLineRight = function() { Interface.prototype.clearLine = function() { this._moveCursor(+Infinity); - this.output.write('\r\n'); + this._writeToOutput('\r\n'); this.line = ''; this.cursor = 0; this.prevRows = 0; @@ -1168,6 +1182,9 @@ function emitKeys(stream, s) { */ function cursorTo(stream, x, y) { + if (util.isNullOrUndefined(stream)) + return; + if (!util.isNumber(x) && !util.isNumber(y)) return; @@ -1188,6 +1205,9 @@ exports.cursorTo = cursorTo; */ function moveCursor(stream, dx, dy) { + if (util.isNullOrUndefined(stream)) + return; + if (dx < 0) { stream.write('\x1b[' + (-dx) + 'D'); } else if (dx > 0) { @@ -1211,6 +1231,9 @@ exports.moveCursor = moveCursor; */ function clearLine(stream, dir) { + if (util.isNullOrUndefined(stream)) + return; + if (dir < 0) { // to the beginning stream.write('\x1b[1K'); @@ -1230,6 +1253,9 @@ exports.clearLine = clearLine; */ function clearScreenDown(stream) { + if (util.isNullOrUndefined(stream)) + return; + stream.write('\x1b[0J'); } exports.clearScreenDown = clearScreenDown; diff --git a/test/simple/test-readline-interface.js b/test/simple/test-readline-interface.js index f91c10821..b86dd5a8a 100644 --- a/test/simple/test-readline-interface.js +++ b/test/simple/test-readline-interface.js @@ -307,5 +307,36 @@ function isWarned(emitter) { assert.equal(isWarned(process.stdout._events), false); } + //can create a new readline Interface with a null output arugument + fi = new FakeInput(); + rli = new readline.Interface({input: fi, output: null, terminal: terminal }); + + called = false; + rli.on('line', function(line) { + called = true; + assert.equal(line, 'asdf'); + }); + fi.emit('data', 'asdf\n'); + assert.ok(called); + + assert.doesNotThrow(function() { + rli.setPrompt("ddd> "); + }); + + assert.doesNotThrow(function() { + rli.prompt(); + }); + + assert.doesNotThrow(function() { + rli.write('really shouldnt be seeing this'); + }); + + assert.doesNotThrow(function() { + rli.question("What do you think of node.js? ", function(answer) { + console.log("Thank you for your valuable feedback:", answer); + rli.close(); + }) + }); + }); |