From 686a3bcf92d1f530fcebb5dca5a0719a11917a36 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 31 Dec 2019 15:16:09 +0100 Subject: [PATCH] readline,repl: support tabs properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/31112 Fixes: https://github.com/nodejs/node/issues/25272 Reviewed-By: Michaƫl Zasso Reviewed-By: James M Snell --- lib/readline.js | 39 ++++++++++++++---------------- test/parallel/test-repl-preview.js | 6 ++--- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/lib/readline.js b/lib/readline.js index 4f4d118c9f68fa..9cbb3c55c8d951 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -490,9 +490,6 @@ Interface.prototype._insertString = function(c) { } else { this._writeToOutput(c); } - - // A hack to get the line refreshed if it's needed - this._moveCursor(0); } }; @@ -731,6 +728,12 @@ Interface.prototype._getDisplayPos = function(str) { offset = 0; continue; } + // Tabs must be aligned by an offset of 8. + // TODO(BridgeAR): Make the tab size configurable. + if (char === '\t') { + offset += 8 - (offset % 8); + continue; + } const width = getStringWidth(char); if (width === 0 || width === 1) { offset += width; @@ -768,33 +771,27 @@ Interface.prototype._getCursorPos = Interface.prototype.getCursorPos; // This function moves cursor dx places to the right -// (-dx for left) and refreshes the line if it is needed +// (-dx for left) and refreshes the line if it is needed. Interface.prototype._moveCursor = function(dx) { - const oldcursor = this.cursor; + if (dx === 0) { + return; + } const oldPos = this.getCursorPos(); this.cursor += dx; - // bounds check - if (this.cursor < 0) this.cursor = 0; - else if (this.cursor > this.line.length) this.cursor = this.line.length; + // Bounds check + if (this.cursor < 0) { + this.cursor = 0; + } else if (this.cursor > this.line.length) { + this.cursor = this.line.length; + } const newPos = this.getCursorPos(); - // Check if cursors are in the same line + // Check if cursor stayed on the line. if (oldPos.rows === newPos.rows) { - const diffCursor = this.cursor - oldcursor; - let diffWidth; - if (diffCursor < 0) { - diffWidth = -getStringWidth( - this.line.substring(this.cursor, oldcursor) - ); - } else if (diffCursor > 0) { - diffWidth = getStringWidth( - this.line.substring(this.cursor, oldcursor) - ); - } + const diffWidth = newPos.cols - oldPos.cols; moveCursor(this.output, diffWidth, 0); - this.prevRows = newPos.rows; } else { this._refreshLine(); } diff --git a/test/parallel/test-repl-preview.js b/test/parallel/test-repl-preview.js index 4846248bdba294..1c6dfd76b89bc1 100644 --- a/test/parallel/test-repl-preview.js +++ b/test/parallel/test-repl-preview.js @@ -93,9 +93,9 @@ async function tests(options) { '\x1B[33mtrue\x1B[39m', '\x1B[1G\x1B[0Jrepl > \x1B[8G'], [' \t { a: true};', [2, 5], '\x1B[33mtrue\x1B[39m', - ' \t { a: tru\x1B[90me\x1B[39m\x1B[19G\x1B[0Ke}', - '\x1B[90m{ a: true }\x1B[39m\x1B[8C\x1B[1A\x1B[1B\x1B[2K\x1B[1A;', - '\x1B[90mtrue\x1B[39m\x1B[16C\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', + ' \t { a: tru\x1B[90me\x1B[39m\x1B[26G\x1B[0Ke}', + '\x1B[90m{ a: true }\x1B[39m\x1B[16C\x1B[1A\x1B[1B\x1B[2K\x1B[1A;', + '\x1B[90mtrue\x1B[39m\x1B[24C\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33mtrue\x1B[39m', '\x1B[1G\x1B[0Jrepl > \x1B[8G'] ];