Skip to content

Commit 20cc8ec

Browse files
addaleaxtargos
authored andcommitted
readline: allow completer to rewrite existing input
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: #39178 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent 63f8702 commit 20cc8ec

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

Diff for: lib/readline.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -705,9 +705,21 @@ Interface.prototype._tabComplete = function(lastKeypressWasTab) {
705705
// If there is a common prefix to all matches, then apply that portion.
706706
const prefix = commonPrefix(ArrayPrototypeFilter(completions,
707707
(e) => e !== ''));
708-
if (prefix.length > completeOn.length) {
708+
if (StringPrototypeStartsWith(prefix, completeOn) &&
709+
prefix.length > completeOn.length) {
709710
this._insertString(StringPrototypeSlice(prefix, completeOn.length));
710711
return;
712+
} else if (!StringPrototypeStartsWith(completeOn, prefix)) {
713+
this.line = StringPrototypeSlice(this.line,
714+
0,
715+
this.cursor - completeOn.length) +
716+
prefix +
717+
StringPrototypeSlice(this.line,
718+
this.cursor,
719+
this.line.length);
720+
this.cursor = this.cursor - completeOn.length + prefix.length;
721+
this._refreshLine();
722+
return;
711723
}
712724

713725
if (!lastKeypressWasTab) {

Diff for: test/parallel/test-readline-tab-complete.js

+36
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,39 @@ common.skipIfDumbTerminal();
100100
});
101101
rli.close();
102102
}
103+
104+
{
105+
let output = '';
106+
class FakeInput extends EventEmitter {
107+
columns = 80
108+
109+
write = common.mustCall((data) => {
110+
output += data;
111+
}, 9)
112+
113+
resume() {}
114+
pause() {}
115+
end() {}
116+
}
117+
118+
const fi = new FakeInput();
119+
const rli = new readline.Interface({
120+
input: fi,
121+
output: fi,
122+
terminal: true,
123+
completer: common.mustCall((input, cb) => {
124+
cb(null, [[input[0].toUpperCase() + input.slice(1)], input]);
125+
}),
126+
});
127+
128+
rli.on('line', common.mustNotCall());
129+
fi.emit('data', 'input');
130+
queueMicrotask(() => {
131+
fi.emit('data', '\t');
132+
queueMicrotask(() => {
133+
assert.match(output, /> Input/);
134+
output = '';
135+
rli.close();
136+
});
137+
});
138+
}

0 commit comments

Comments
 (0)