diff --git a/lib/readline.js b/lib/readline.js index 7348201fa9..d9a6fcdb4a 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -86,12 +86,28 @@ function Interface(input, output, completer, terminal) { this.terminal = !!terminal; + function ondata(data) { + self._normalWrite(data); + } + + function onend() { + self.close(); + } + + function onkeypress(s, key) { + self._ttyWrite(s, key); + } + + function onresize() { + self._refreshLine(); + } + if (!this.terminal) { - input.on('data', function(data) { - self._normalWrite(data); - }); - input.on('end', function() { - self.close(); + input.on('data', ondata); + input.on('end', onend); + self.once('close', function() { + input.removeListener('data', ondata); + input.removeListener('end', onend); }); var StringDecoder = require('string_decoder').StringDecoder; // lazy load this._decoder = new StringDecoder('utf8'); @@ -101,9 +117,7 @@ function Interface(input, output, completer, terminal) { exports.emitKeypressEvents(input); // input usually refers to stdin - input.on('keypress', function(s, key) { - self._ttyWrite(s, key); - }); + input.on('keypress', onkeypress); // Current line this.line = ''; @@ -117,8 +131,10 @@ function Interface(input, output, completer, terminal) { this.history = []; this.historyIndex = -1; - output.on('resize', function() { - self._refreshLine(); + output.on('resize', onresize); + self.once('close', function() { + input.removeListener('keypress', onkeypress); + output.removeListener('resize', onresize); }); } } diff --git a/test/simple/test-readline-interface.js b/test/simple/test-readline-interface.js index 986fa1f478..568b73a29b 100644 --- a/test/simple/test-readline-interface.js +++ b/test/simple/test-readline-interface.js @@ -31,6 +31,7 @@ function FakeInput() { } inherits(FakeInput, EventEmitter); FakeInput.prototype.resume = function() {}; +FakeInput.prototype.pause = function() {}; var fi; var rli; @@ -67,6 +68,7 @@ rli.on('line', function(line) { }); fi.emit('data', 'a'); assert.ok(!called); +rli.close(); // sending a single character with no newline and then a newline fi = new FakeInput(); @@ -80,6 +82,7 @@ fi.emit('data', 'a'); assert.ok(!called); fi.emit('data', '\n'); assert.ok(called); +rli.close(); // sending multiple newlines at once fi = new FakeInput(); @@ -92,6 +95,7 @@ rli.on('line', function(line) { }); fi.emit('data', expectedLines.join('')); assert.equal(callCount, expectedLines.length); +rli.close(); // sending multiple newlines at once that does not end with a new line fi = new FakeInput(); @@ -104,6 +108,7 @@ rli.on('line', function(line) { }); fi.emit('data', expectedLines.join('')); assert.equal(callCount, expectedLines.length - 1); +rli.close(); // sending a multi-byte utf8 char over multiple writes var buf = Buffer('☮', 'utf8'); @@ -120,3 +125,7 @@ rli.on('line', function(line) { assert.equal(callCount, 0); fi.emit('data', '\n'); assert.equal(callCount, 1); +rli.close(); + +assert.deepEqual(fi.listeners('end'), []); +assert.deepEqual(fi.listeners('data'), []); diff --git a/test/simple/test-readline-set-raw-mode.js b/test/simple/test-readline-set-raw-mode.js index a300f7a268..5bca5272cc 100644 --- a/test/simple/test-readline-set-raw-mode.js +++ b/test/simple/test-readline-set-raw-mode.js @@ -85,3 +85,7 @@ assert(rawModeCalled); assert(!resumeCalled); assert(pauseCalled); +assert.deepEqual(stream.listeners('end'), []); +assert.deepEqual(stream.listeners('keypress'), []); +// one data listener for the keypress events. +assert.equal(stream.listeners('data').length, 1);