From 64e483701191c5920c48dd9fbcacb76a55ca3968 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 28 Jun 2021 15:02:07 +0200 Subject: [PATCH] readline: allow completer to rewrite existing input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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: https://github.com/nodejs/node/pull/39178 Reviewed-By: Antoine du Hamel Reviewed-By: Gus Caplan Reviewed-By: Rich Trott Reviewed-By: Colin Ihrig Reviewed-By: Tobias Nießen --- lib/readline.js | 14 +++++++- test/parallel/test-readline-tab-complete.js | 36 +++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/readline.js b/lib/readline.js index b40c8019746120..1b8b276a6d6db0 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -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) { diff --git a/test/parallel/test-readline-tab-complete.js b/test/parallel/test-readline-tab-complete.js index c283d446f9af28..be993911c6fe16 100644 --- a/test/parallel/test-readline-tab-complete.js +++ b/test/parallel/test-readline-tab-complete.js @@ -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(); + }); + }); +}