Browse Source

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 <anna@addaleax.net>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
v4.x
Eugene Obrezkov 9 years ago
committed by Myles Borins
parent
commit
a3fa5db5ca
  1. 7
      doc/api/readline.md
  2. 15
      lib/readline.js
  3. 4
      test/parallel/test-readline-interface.js

7
doc/api/readline.md

@ -354,6 +354,13 @@ a `'resize'` event on the `output` if/when the columns ever change
Move cursor to the specified position in a given TTY stream. Move cursor to the specified position in a given TTY 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) ## readline.moveCursor(stream, dx, dy)
Move cursor relative to it's current position in a given TTY stream. Move cursor relative to it's current position in a given TTY stream.

15
lib/readline.js

@ -36,6 +36,7 @@ function Interface(input, output, completer, terminal) {
} }
this._sawReturn = false; this._sawReturn = false;
this.isCompletionEnabled = true;
EventEmitter.call(this); EventEmitter.call(this);
var historySize; var historySize;
@ -122,7 +123,7 @@ function Interface(input, output, completer, terminal) {
} else { } else {
exports.emitKeypressEvents(input); exports.emitKeypressEvents(input, this);
// input usually refers to stdin // input usually refers to stdin
input.on('keypress', onkeypress); input.on('keypress', onkeypress);
@ -868,7 +869,7 @@ Interface.prototype._ttyWrite = function(s, key) {
case 'tab': case 'tab':
// If tab completion enabled, do that... // If tab completion enabled, do that...
if (typeof this.completer === 'function') { if (typeof this.completer === 'function' && this.isCompletionEnabled) {
this._tabComplete(); this._tabComplete();
break; break;
} }
@ -902,7 +903,7 @@ exports.Interface = Interface;
const KEYPRESS_DECODER = Symbol('keypress-decoder'); const KEYPRESS_DECODER = Symbol('keypress-decoder');
const ESCAPE_DECODER = Symbol('escape-decoder'); const ESCAPE_DECODER = Symbol('escape-decoder');
function emitKeypressEvents(stream) { function emitKeypressEvents(stream, iface) {
if (stream[KEYPRESS_DECODER]) return; if (stream[KEYPRESS_DECODER]) return;
var StringDecoder = require('string_decoder').StringDecoder; // lazy load var StringDecoder = require('string_decoder').StringDecoder; // lazy load
stream[KEYPRESS_DECODER] = new StringDecoder('utf8'); stream[KEYPRESS_DECODER] = new StringDecoder('utf8');
@ -915,6 +916,10 @@ function emitKeypressEvents(stream) {
var r = stream[KEYPRESS_DECODER].write(b); var r = stream[KEYPRESS_DECODER].write(b);
if (r) { if (r) {
for (var i = 0; i < r.length; i++) { for (var i = 0; i < r.length; i++) {
if (r[i] === '\t' && typeof r[i + 1] === 'string' && iface) {
iface.isCompletionEnabled = false;
}
try { try {
stream[ESCAPE_DECODER].next(r[i]); stream[ESCAPE_DECODER].next(r[i]);
} catch (err) { } catch (err) {
@ -923,6 +928,10 @@ function emitKeypressEvents(stream) {
stream[ESCAPE_DECODER] = emitKeys(stream); stream[ESCAPE_DECODER] = emitKeys(stream);
stream[ESCAPE_DECODER].next(); stream[ESCAPE_DECODER].next();
throw err; throw err;
} finally {
if (iface) {
iface.isCompletionEnabled = true;
}
} }
} }
} }

4
test/parallel/test-readline-interface.js

@ -208,7 +208,9 @@ function isWarned(emitter) {
assert.strictEqual(called, false); assert.strictEqual(called, false);
called = true; called = true;
}); });
fi.emit('data', '\tfo\to\t'); for (var character of '\tfo\to\t') {
fi.emit('data', character);
}
fi.emit('data', '\n'); fi.emit('data', '\n');
assert.ok(called); assert.ok(called);
rli.close(); rli.close();

Loading…
Cancel
Save