repl: make ^D emit an 'end' event on the readline instance

Also emit 'exit' on the repl when 'end' is emitted on the readline.

Fixes `node debug test/fixtures/breakpoints.js` when ^D is pressed.
This commit is contained in:
Nathan Rajlich 2012-03-27 12:41:42 -07:00
parent 00224771e3
commit f41901cdf6
5 changed files with 96 additions and 1 deletions

View File

@ -160,6 +160,14 @@ Example of listening for `resume`:
console.log('Readline resumed.');
});
### Event: 'end'
`function () {}`
Emitted when the `input` stream receives its "end" event, or when `^D` is
pressed by the user. It's generally a good idea to consider this `Interface`
instance as completed after this is emitted.
### Event: 'SIGINT'
`function () {}`

View File

@ -116,7 +116,8 @@ see: https://gist.github.com/2053342
`function () {}`
Emitted when the user exits the REPL in any of the defined ways. Namely, typing
`.exit` at the repl, or pressing Ctrl+C twice to signal SIGINT.
`.exit` at the repl, pressing Ctrl+C twice to signal SIGINT, or pressing Ctrl+D
to signal "end" on the `input` stream.
Example of listening for `exit`:

View File

@ -90,6 +90,9 @@ function Interface(input, output, completer, terminal) {
input.on('data', function(data) {
self._normalWrite(data);
});
input.on('end', function() {
self.emit('end');
});
} else {
@ -575,6 +578,7 @@ Interface.prototype._ttyWrite = function(s, key) {
case 'd': // delete right or EOF
if (this.cursor === 0 && this.line.length === 0) {
this.pause();
this.emit('end');
} else if (this.cursor < this.line.length) {
this._deleteRight();
}

View File

@ -168,6 +168,11 @@ function REPLServer(prompt, stream, eval, useGlobal, ignoreUndefined) {
rli.setPrompt(self.prompt);
rli.on('end', function() {
self.rli.output.write('\n');
self.emit('exit');
});
var sawSIGINT = false;
rli.on('SIGINT', function() {
var empty = rli.line.length === 0;

View File

@ -0,0 +1,77 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common'),
assert = require('assert'),
Stream = require('stream'),
repl = require('repl'),
gotTerminalExit = false,
gotRegularExit = false;
// create a dummy stream that does nothing
var stream = new Stream();
stream.write = stream.pause = stream.resume = function(){};
stream.readable = stream.writable = true;
function testTerminalMode() {
var r1 = repl.start({
input: stream,
output: stream,
terminal: true
});
process.nextTick(function() {
// manually fire a ^D keypress
stream.emit('data', '\u0004');
});
r1.on('exit', function() {
// should be fired from the simulated ^D keypress
gotTerminalExit = true;
testRegularMode();
});
}
function testRegularMode() {
var r2 = repl.start({
input: stream,
output: stream,
terminal: false
});
process.nextTick(function() {
stream.emit('end');
});
r2.on('exit', function() {
// should be fired from the simulated 'end' event
gotRegularExit = true;
});
}
process.on('exit', function() {
assert(gotTerminalExit);
assert(gotRegularExit);
});
// start
testTerminalMode();