Skip to content

Commit

Permalink
readline: allow completer to rewrite existing input
Browse files Browse the repository at this point in the history
Sometimes, it makes sense for a completer to change the existing
input, e.g. by adjusting the casing (imagine a completer that
corrects `Number.isNan` to `Number.IsNaN`, for example).

This commit allows that in the readline implemention.

PR-URL: nodejs#39178
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
  • Loading branch information
addaleax authored and ejose19 committed Jul 5, 2021
1 parent 6fccab7 commit c5db850
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
14 changes: 13 additions & 1 deletion lib/readline.js
Original file line number Diff line number Diff line change
Expand Up @@ -705,9 +705,21 @@ Interface.prototype._tabComplete = function(lastKeypressWasTab) {
// If there is a common prefix to all matches, then apply that portion.
const prefix = commonPrefix(ArrayPrototypeFilter(completions,
(e) => e !== ''));
if (prefix.length > completeOn.length) {
if (StringPrototypeStartsWith(prefix, completeOn) &&
prefix.length > completeOn.length) {
this._insertString(StringPrototypeSlice(prefix, completeOn.length));
return;
} else if (!StringPrototypeStartsWith(completeOn, prefix)) {
this.line = StringPrototypeSlice(this.line,
0,
this.cursor - completeOn.length) +
prefix +
StringPrototypeSlice(this.line,
this.cursor,
this.line.length);
this.cursor = this.cursor - completeOn.length + prefix.length;
this._refreshLine();
return;
}

if (!lastKeypressWasTab) {
Expand Down
36 changes: 36 additions & 0 deletions test/parallel/test-readline-tab-complete.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,39 @@ common.skipIfDumbTerminal();
});
rli.close();
}

{
let output = '';
class FakeInput extends EventEmitter {
columns = 80

write = common.mustCall((data) => {
output += data;
}, 9)

resume() {}
pause() {}
end() {}
}

const fi = new FakeInput();
const rli = new readline.Interface({
input: fi,
output: fi,
terminal: true,
completer: common.mustCall((input, cb) => {
cb(null, [[input[0].toUpperCase() + input.slice(1)], input]);
}),
});

rli.on('line', common.mustNotCall());
fi.emit('data', 'input');
queueMicrotask(() => {
fi.emit('data', '\t');
queueMicrotask(() => {
assert.match(output, /> Input/);
output = '';
rli.close();
});
});
}

0 comments on commit c5db850

Please sign in to comment.