From d7f3462929f827705699ef5cc7c16fba43414fcc Mon Sep 17 00:00:00 2001 From: Tarun Batra Date: Sat, 11 Oct 2025 20:32:07 -0700 Subject: [PATCH] repl: handle screen refresh for multiline input Fixes an issue where when navigating a multiline input which exceeds terminal height, pressing UP arrow would not update the visible data when the cursor reaches the top. Fixes: https://github.com/nodejs/node/issues/59938 --- lib/internal/readline/interface.js | 35 ++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/internal/readline/interface.js b/lib/internal/readline/interface.js index 46674883381392..bf32d6cdb80f72 100644 --- a/lib/internal/readline/interface.js +++ b/lib/internal/readline/interface.js @@ -364,6 +364,11 @@ class Interface extends InterfaceConstructor { return Infinity; } + get rows() { + if (this.output?.rows) return this.output.rows; + return Infinity; + } + /** * Sets the prompt written to the output. * @param {string} prompt @@ -496,6 +501,7 @@ class Interface extends InterfaceConstructor { const dispPos = this[kGetDisplayPos](line); const lineCols = dispPos.cols; const lineRows = dispPos.rows; + const terminalRows = this.rows; // cursor position const cursorPos = this.getCursorPos(); @@ -513,11 +519,32 @@ class Interface extends InterfaceConstructor { if (this[kIsMultiline]) { const lines = StringPrototypeSplit(this.line, '\n'); - // Write first line with normal prompt - this[kWriteToOutput](this[kPrompt] + lines[0]); - + // Normal case - display line from the first row to the last + let startLine = 0; + let endLine = lineRows; + + const exceedsTerminal = lineRows >= terminalRows && terminalRows !== Infinity; + if (exceedsTerminal) { + const topOfVisibleData = lineRows - terminalRows; + // The cursor starts from the last row. If it is within the + // visible data segment, show the last part of the multiline data + if (cursorPos.rows > topOfVisibleData) { + startLine = topOfVisibleData; + } else { + // Cursor has traveled through the visible rows + // Start displaying the data that the cursor is on + // up until the terminal size allows + startLine = cursorPos.rows; + endLine = cursorPos.rows + terminalRows - 1; + } + } + // If the first row is visible, show the normal prompt + if (startLine === 0) { + this[kWriteToOutput](this[kPrompt] + lines[0]); + startLine++; + } // For continuation lines, add the "|" prefix - for (let i = 1; i < lines.length; i++) { + for (let i = startLine; i <= endLine; i++) { this[kWriteToOutput](`\n${kMultilinePrompt.description}` + lines[i]); } } else {