From e4e2b0ce134ce781847272ae0b4bb889e75f223f Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 19 Mar 2019 14:19:38 +0100 Subject: [PATCH] readline: replace quadratic regex with linear one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify regular expression in _wordLeft and _deleteWordLeft readline methods. PR-URL: https://github.com/nodejs/node/pull/26778 Reviewed-By: Ruben Bridgewater Reviewed-By: Michaƫl Zasso --- lib/readline.js | 10 ++++++++-- test/parallel/test-readline-interface.js | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/readline.js b/lib/readline.js index ccacacfb87988c..4f1e2930b611bc 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -577,8 +577,11 @@ function commonPrefix(strings) { Interface.prototype._wordLeft = function() { if (this.cursor > 0) { + // Reverse the string and match a word near beginning + // to avoid quadratic time complexity var leading = this.line.slice(0, this.cursor); - var match = leading.match(/(?:[^\w\s]+|\w+|)\s*$/); + var reversed = leading.split('').reverse().join(''); + var match = reversed.match(/^\s*(?:[^\w\s]+|\w+)?/); this._moveCursor(-match[0].length); } }; @@ -634,8 +637,11 @@ Interface.prototype._deleteRight = function() { Interface.prototype._deleteWordLeft = function() { if (this.cursor > 0) { + // Reverse the string and match a word near beginning + // to avoid quadratic time complexity var leading = this.line.slice(0, this.cursor); - var match = leading.match(/(?:[^\w\s]+|\w+|)\s*$/); + var reversed = leading.split('').reverse().join(''); + var match = reversed.match(/^\s*(?:[^\w\s]+|\w+)?/); leading = leading.slice(0, leading.length - match[0].length); this.line = leading + this.line.slice(this.cursor, this.line.length); this.cursor = leading.length; diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index 5096198a71d9eb..2dff11f2a27e72 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -1272,3 +1272,26 @@ const crlfDelay = Infinity; }), delay); } }); + +// Ensure that the _wordLeft method works even for large input +{ + const input = new Readable({ + read() { + this.push('\x1B[1;5D'); // CTRL + Left + this.push(null); + }, + }); + const output = new Writable({ + write: common.mustCall((data, encoding, cb) => { + assert.strictEqual(rl.cursor, rl.line.length - 1); + cb(); + }), + }); + const rl = new readline.createInterface({ + input: input, + output: output, + terminal: true, + }); + rl.line = `a${' '.repeat(1e6)}a`; + rl.cursor = rl.line.length; +}