From e6e98afbf272d2480d6bf4aa6dfa2d8e2fdd42ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Zugmeyer?= Date: Tue, 18 Jun 2019 00:34:27 +0200 Subject: [PATCH] readline: fix position computation The implementation of _getDisplayPos, used to compute the cursor position and to find out how many lines to clear up when re-rendering the readline output, was counting each line (except the last one) from the input as one row, even if they were wraping. This caused some rendering issues when the 'prompt' have at least one wide line ending with a newline char, duplicating the lines at the top of the prompt when calling _refreshLine (ex: when the user hits backspace). This patch fixes the issue by computing the real rows count for each new line in the input string. PR-URL: https://github.com/nodejs/node/pull/28272 Reviewed-By: Rich Trott Reviewed-By: Anna Henningsen --- lib/readline.js | 3 ++- test/parallel/test-readline-interface.js | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/readline.js b/lib/readline.js index c8d0a8040ad971..2c29eafc945461 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -732,8 +732,9 @@ Interface.prototype._getDisplayPos = function(str) { i++; } if (code === 0x0a) { // new line \n + // row must be incremented by 1 even if offset = 0 or col = +Infinity + row += Math.ceil(offset / col) || 1; offset = 0; - row += 1; continue; } const width = getStringWidth(code); diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index 2dff11f2a27e72..3f80fd44428549 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -1042,7 +1042,7 @@ function isWarned(emitter) { rli.close(); } - // multi-line cursor position + // Multi-line input cursor position { const fi = new FakeInput(); const rli = new readline.Interface({ @@ -1059,6 +1059,23 @@ function isWarned(emitter) { rli.close(); } + // Multi-line prompt cursor position + { + const fi = new FakeInput(); + const rli = new readline.Interface({ + input: fi, + output: fi, + prompt: '\nfilledline\nwraping text\n> ', + terminal: terminal + }); + fi.columns = 10; + fi.emit('data', 't'); + const cursorPos = rli._getCursorPos(); + assert.strictEqual(cursorPos.rows, 4); + assert.strictEqual(cursorPos.cols, 3); + rli.close(); + } + // Clear the whole screen { const fi = new FakeInput();