From ae178838ebde5093f316a827e74ba91b67df252d Mon Sep 17 00:00:00 2001 From: Eugene Obrezkov Date: Fri, 13 May 2016 10:54:31 +0300 Subject: [PATCH] repl: copying tabs shouldn't trigger completion PR-URL: https://github.com/nodejs/node/pull/5958 Fixes: https://github.com/nodejs/node/issues/5954 Reviewed-By: Anna Henningsen Reviewed-By: Jeremiah Senkpiel --- doc/api/readline.md | 4 +++- lib/readline.js | 15 ++++++++++++--- test/parallel/test-readline-interface.js | 4 +++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/doc/api/readline.md b/doc/api/readline.md index c75054dd2ee..a9478ac0b84 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -357,10 +357,12 @@ a `'resize'` event on the `output` if/when the columns ever change Move cursor to the specified position in a given TTY stream. -## readline.emitKeypressEvents(stream) +## readline.emitKeypressEvents(stream[, interface]) Causes `stream` to begin emitting `'keypress'` events corresponding to its input. +Optionally, `interface` specifies a `readline.Interface` instance for which +autocompletion is disabled when copy-pasted input is detected. ## readline.moveCursor(stream, dx, dy) diff --git a/lib/readline.js b/lib/readline.js index 57a27a97705..096929f8858 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -40,6 +40,7 @@ function Interface(input, output, completer, terminal) { } this._sawReturn = false; + this.isCompletionEnabled = true; EventEmitter.call(this); var historySize; @@ -129,7 +130,7 @@ function Interface(input, output, completer, terminal) { } else { - emitKeypressEvents(input); + emitKeypressEvents(input, this); // input usually refers to stdin input.on('keypress', onkeypress); @@ -878,7 +879,7 @@ Interface.prototype._ttyWrite = function(s, key) { case 'tab': // If tab completion enabled, do that... - if (typeof this.completer === 'function') { + if (typeof this.completer === 'function' && this.isCompletionEnabled) { this._tabComplete(); break; } @@ -912,7 +913,7 @@ exports.Interface = Interface; const KEYPRESS_DECODER = Symbol('keypress-decoder'); const ESCAPE_DECODER = Symbol('escape-decoder'); -function emitKeypressEvents(stream) { +function emitKeypressEvents(stream, iface) { if (stream[KEYPRESS_DECODER]) return; var StringDecoder = require('string_decoder').StringDecoder; // lazy load stream[KEYPRESS_DECODER] = new StringDecoder('utf8'); @@ -925,6 +926,10 @@ function emitKeypressEvents(stream) { var r = stream[KEYPRESS_DECODER].write(b); if (r) { for (var i = 0; i < r.length; i++) { + if (r[i] === '\t' && typeof r[i + 1] === 'string' && iface) { + iface.isCompletionEnabled = false; + } + try { stream[ESCAPE_DECODER].next(r[i]); } catch (err) { @@ -933,6 +938,10 @@ function emitKeypressEvents(stream) { stream[ESCAPE_DECODER] = emitKeys(stream); stream[ESCAPE_DECODER].next(); throw err; + } finally { + if (iface) { + iface.isCompletionEnabled = true; + } } } } diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index 9a3b7f5ef3e..57e8152d141 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -229,7 +229,9 @@ function isWarned(emitter) { assert.strictEqual(called, false); called = true; }); - fi.emit('data', '\tfo\to\t'); + for (var character of '\tfo\to\t') { + fi.emit('data', character); + } fi.emit('data', '\n'); assert.ok(called); rli.close();