readline: show completions only after 2nd TAB
Show `TAB` completion suggestions only after the user has pressed `TAB` twice in a row, so that the full list of suggestions doesn’t present a distraction. The first time a `TAB` key is pressed, only partial longest-common-prefix completion is performed. This moves the `readline` autocompletion a lot closer to what e.g. `bash` does. Fixes: https://github.com/nodejs/node/issues/7665 PR-URL: https://github.com/nodejs/node/pull/7754 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
c809b88345
commit
1a9e247c79
@ -41,6 +41,7 @@ function Interface(input, output, completer, terminal) {
|
|||||||
|
|
||||||
this._sawReturn = false;
|
this._sawReturn = false;
|
||||||
this.isCompletionEnabled = true;
|
this.isCompletionEnabled = true;
|
||||||
|
this._previousKey = null;
|
||||||
|
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
var historySize;
|
var historySize;
|
||||||
@ -391,7 +392,7 @@ Interface.prototype._insertString = function(c) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Interface.prototype._tabComplete = function() {
|
Interface.prototype._tabComplete = function(lastKeypressWasTab) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.pause();
|
self.pause();
|
||||||
@ -407,9 +408,7 @@ Interface.prototype._tabComplete = function() {
|
|||||||
const completeOn = rv[1]; // the text that was completed
|
const completeOn = rv[1]; // the text that was completed
|
||||||
if (completions && completions.length) {
|
if (completions && completions.length) {
|
||||||
// Apply/show completions.
|
// Apply/show completions.
|
||||||
if (completions.length === 1) {
|
if (lastKeypressWasTab) {
|
||||||
self._insertString(completions[0].slice(completeOn.length));
|
|
||||||
} else {
|
|
||||||
self._writeToOutput('\r\n');
|
self._writeToOutput('\r\n');
|
||||||
var width = completions.reduce(function(a, b) {
|
var width = completions.reduce(function(a, b) {
|
||||||
return a.length > b.length ? a : b;
|
return a.length > b.length ? a : b;
|
||||||
@ -429,16 +428,15 @@ Interface.prototype._tabComplete = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleGroup(self, group, width, maxColumns);
|
handleGroup(self, group, width, maxColumns);
|
||||||
|
}
|
||||||
|
|
||||||
// If there is a common prefix to all matches, then apply that
|
// If there is a common prefix to all matches, then apply that portion.
|
||||||
// portion.
|
const f = completions.filter(function(e) { if (e) return e; });
|
||||||
var f = completions.filter(function(e) { if (e) return e; });
|
const prefix = commonPrefix(f);
|
||||||
var prefix = commonPrefix(f);
|
|
||||||
if (prefix.length > completeOn.length) {
|
if (prefix.length > completeOn.length) {
|
||||||
self._insertString(prefix.slice(completeOn.length));
|
self._insertString(prefix.slice(completeOn.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
self._refreshLine();
|
self._refreshLine();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -474,6 +472,7 @@ function commonPrefix(strings) {
|
|||||||
if (!strings || strings.length == 0) {
|
if (!strings || strings.length == 0) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
if (strings.length === 1) return strings[0];
|
||||||
var sorted = strings.slice().sort();
|
var sorted = strings.slice().sort();
|
||||||
var min = sorted[0];
|
var min = sorted[0];
|
||||||
var max = sorted[sorted.length - 1];
|
var max = sorted[sorted.length - 1];
|
||||||
@ -688,7 +687,9 @@ Interface.prototype._moveCursor = function(dx) {
|
|||||||
|
|
||||||
// handle a write from the tty
|
// handle a write from the tty
|
||||||
Interface.prototype._ttyWrite = function(s, key) {
|
Interface.prototype._ttyWrite = function(s, key) {
|
||||||
|
const previousKey = this._previousKey;
|
||||||
key = key || {};
|
key = key || {};
|
||||||
|
this._previousKey = key;
|
||||||
|
|
||||||
// Ignore escape key - Fixes #2876
|
// Ignore escape key - Fixes #2876
|
||||||
if (key.name == 'escape') return;
|
if (key.name == 'escape') return;
|
||||||
@ -892,7 +893,8 @@ 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' && this.isCompletionEnabled) {
|
if (typeof this.completer === 'function' && this.isCompletionEnabled) {
|
||||||
this._tabComplete();
|
const lastKeypressWasTab = previousKey && previousKey.name === 'tab';
|
||||||
|
this._tabComplete(lastKeypressWasTab);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// falls through
|
// falls through
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const PassThrough = require('stream').PassThrough;
|
const PassThrough = require('stream').PassThrough;
|
||||||
const readline = require('readline');
|
const readline = require('readline');
|
||||||
@ -26,12 +26,17 @@ oStream.on('data', function(data) {
|
|||||||
output += data;
|
output += data;
|
||||||
});
|
});
|
||||||
|
|
||||||
oStream.on('end', function() {
|
oStream.on('end', common.mustCall(() => {
|
||||||
const expect = 'process.stdout\r\n' +
|
const expect = 'process.stdout\r\n' +
|
||||||
'process.stdin\r\n' +
|
'process.stdin\r\n' +
|
||||||
'process.stderr';
|
'process.stderr';
|
||||||
assert(new RegExp(expect).test(output));
|
assert(new RegExp(expect).test(output));
|
||||||
});
|
}));
|
||||||
|
|
||||||
iStream.write('process.std\t');
|
iStream.write('process.s\t');
|
||||||
|
|
||||||
|
assert(/process.std\b/.test(output)); // Completion works.
|
||||||
|
assert(!/stdout/.test(output)); // Completion doesn’t show all results yet.
|
||||||
|
|
||||||
|
iStream.write('\t');
|
||||||
oStream.end();
|
oStream.end();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user