summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/readline.markdown13
-rw-r--r--lib/readline.js54
-rw-r--r--test/simple/test-readline-interface.js31
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();
+ })
+ });
+
});