Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions lib/internal/readline/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const {
StringPrototypeCodePointAt,
StringPrototypeEndsWith,
StringPrototypeIncludes,
StringPrototypeLastIndexOf,
StringPrototypeRepeat,
StringPrototypeReplaceAll,
StringPrototypeSlice,
Expand Down Expand Up @@ -1091,21 +1092,20 @@ class Interface extends InterfaceConstructor {
this[kRefreshLine]();
}

[kMultilineMove](direction, splitLines, { rows, cols }) {
const curr = splitLines[rows];
[kMultilineMove](direction, splitLines, { logicalRows, logicalCols }) {
const curr = splitLines[logicalRows];
const down = direction === 1;
const adj = splitLines[rows + direction];
const promptLen = kMultilinePrompt.description.length;
const adj = splitLines[logicalRows + direction];
let amountToMove;
// Clamp distance to end of current + prompt + next/prev line + newline
// Clamp distance to end of current + next/prev line + newline
const clamp = down ?
curr.length - cols + promptLen + adj.length + 1 :
-cols + 1;
const shouldClamp = cols > adj.length + 1;
curr.length - logicalCols + adj.length + 1 :
-logicalCols - 1;
const shouldClamp = logicalCols > adj.length;

if (shouldClamp) {
if (this[kPreviousCursorCols] === -1) {
this[kPreviousCursorCols] = cols;
this[kPreviousCursorCols] = logicalCols;
}
amountToMove = clamp;
} else {
Expand All @@ -1116,7 +1116,7 @@ class Interface extends InterfaceConstructor {
}
if (this[kPreviousCursorCols] !== -1) {
if (this[kPreviousCursorCols] <= adj.length) {
amountToMove += this[kPreviousCursorCols] - cols;
amountToMove += this[kPreviousCursorCols] - logicalCols;
this[kPreviousCursorCols] = -1;
} else {
amountToMove = clamp;
Expand All @@ -1128,10 +1128,10 @@ class Interface extends InterfaceConstructor {
}

[kMoveDownOrHistoryNext]() {
const cursorPos = this.getCursorPos();
const logicalCursorPos = this.getLogicalCursorPos();
const splitLines = StringPrototypeSplit(this.line, '\n');
if (this[kIsMultiline] && cursorPos.rows < splitLines.length - 1) {
this[kMultilineMove](1, splitLines, cursorPos);
if (this[kIsMultiline] && logicalCursorPos.logicalRows < splitLines.length - 1) {
this[kMultilineMove](1, splitLines, logicalCursorPos);
return;
}
this[kPreviousCursorCols] = -1;
Expand All @@ -1155,10 +1155,10 @@ class Interface extends InterfaceConstructor {
}

[kMoveUpOrHistoryPrev]() {
const cursorPos = this.getCursorPos();
if (this[kIsMultiline] && cursorPos.rows > 0) {
const logicalCursorPos = this.getLogicalCursorPos();
if (this[kIsMultiline] && logicalCursorPos.logicalRows > 0) {
const splitLines = StringPrototypeSplit(this.line, '\n');
this[kMultilineMove](-1, splitLines, cursorPos);
this[kMultilineMove](-1, splitLines, logicalCursorPos);
return;
}
this[kPreviousCursorCols] = -1;
Expand Down Expand Up @@ -1226,6 +1226,22 @@ class Interface extends InterfaceConstructor {
return this[kGetDisplayPos](strBeforeCursor);
}

/**
* Returns the logical position of the cursor within the input string
* excluding prompt and terminal formatting.
* @returns {{
* logicalCols: number;
* logicalRows: number;
* }}
*/
getLogicalCursorPos() {
const logicalCols = this.cursor - (StringPrototypeLastIndexOf(this.line, '\n', this.cursor - 1) + 1);
const strlineBeforeCursor = StringPrototypeSlice(this.line, 0, this.cursor);
const logicalRows = StringPrototypeSplit(strlineBeforeCursor, '\n').length - 1

return { logicalCols, logicalRows };
}

// This function moves cursor dx places to the right
// (-dx for left) and refreshes the line if it is needed.
[kMoveCursor](dx) {
Expand Down