diff options
-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(); + }) + }); + }); |