Skip to content

Commit

Permalink
readline: promote _getCursorPos to public api
Browse files Browse the repository at this point in the history
Alias _getCursorPos() = getCursorPos() for backwards
compatibility.

Refs: #30347

PR-URL: #30687
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
  • Loading branch information
Js-Brecht authored and MylesBorins committed Dec 17, 2019
1 parent 13b5ace commit 5b49ded
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 40 deletions.
13 changes: 13 additions & 0 deletions doc/api/readline.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,19 @@ reading input from a TTY stream. The position of cursor determines the
portion of the input string that will be modified as input is processed,
as well as the column where the terminal caret will be rendered.

### rl.getCursorPos()
<!-- YAML
added: REPLACEME
-->

* Returns: {Object}
* `rows` {number} the row of the prompt the cursor currently lands on
* `cols` {number} the screen column the cursor currently lands on

Returns the real position of the cursor in relation to the input
prompt + string. Long input (wrapping) strings, as well as multiple
line prompts are included in the calculations.

## readline.clearLine(stream, dir\[, callback\])
<!-- YAML
added: v0.7.7
Expand Down
11 changes: 6 additions & 5 deletions lib/readline.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ Interface.prototype._refreshLine = function() {
const lineRows = dispPos.rows;

// cursor position
const cursorPos = this._getCursorPos();
const cursorPos = this.getCursorPos();

// First move to the bottom of the current line, based on cursor pos
const prevRows = this.prevRows || 0;
Expand Down Expand Up @@ -483,7 +483,7 @@ Interface.prototype._insertString = function(c) {
this.line += c;
this.cursor += c.length;

if (this._getCursorPos().cols === 0) {
if (this.getCursorPos().cols === 0) {
this._refreshLine();
} else {
this._writeToOutput(c);
Expand Down Expand Up @@ -750,7 +750,7 @@ Interface.prototype._getDisplayPos = function(str) {


// Returns current cursor's position and line
Interface.prototype._getCursorPos = function() {
Interface.prototype.getCursorPos = function() {
const columns = this.columns;
const strBeforeCursor = this._prompt + this.line.substring(0, this.cursor);
const dispPos = this._getDisplayPos(
Expand All @@ -767,20 +767,21 @@ Interface.prototype._getCursorPos = function() {
}
return { cols: cols, rows: rows };
};
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
Interface.prototype._moveCursor = function(dx) {
const oldcursor = this.cursor;
const oldPos = this._getCursorPos();
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;

const newPos = this._getCursorPos();
const newPos = this.getCursorPos();

// Check if cursors are in the same line
if (oldPos.rows === newPos.rows) {
Expand Down
68 changes: 34 additions & 34 deletions test/parallel/test-readline-interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ function isWarned(emitter) {
rli.question(expectedLines[0], function() {
rli.close();
});
const cursorPos = rli._getCursorPos();
const cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, expectedLines[0].length);
rli.close();
Expand All @@ -606,7 +606,7 @@ function isWarned(emitter) {
rli.question(expectedLines.join('\n'), function() {
rli.close();
});
const cursorPos = rli._getCursorPos();
const cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, expectedLines.length - 1);
assert.strictEqual(cursorPos.cols, expectedLines.slice(-1)[0].length);
rli.close();
Expand All @@ -623,11 +623,11 @@ function isWarned(emitter) {
});
fi.emit('data', 'the quick brown fox');
fi.emit('keypress', '.', { ctrl: true, name: 'a' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);
fi.emit('keypress', '.', { ctrl: true, name: 'e' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 19);
rli.close();
Expand All @@ -643,28 +643,28 @@ function isWarned(emitter) {
terminal: terminal
});
fi.emit('data', 'the quick brown fox');
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 19);

// Back one character
fi.emit('keypress', '.', { ctrl: true, name: 'b' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 18);
// Back one character
fi.emit('keypress', '.', { ctrl: true, name: 'b' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 17);
// Forward one character
fi.emit('keypress', '.', { ctrl: true, name: 'f' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 18);
// Forward one character
fi.emit('keypress', '.', { ctrl: true, name: 'f' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 19);
rli.close();
Expand All @@ -683,13 +683,13 @@ function isWarned(emitter) {

// Move left one character/code point
fi.emit('keypress', '.', { name: 'left' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);

// Move right one character/code point
fi.emit('keypress', '.', { name: 'right' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
if (common.hasIntl) {
assert.strictEqual(cursorPos.cols, 2);
Expand Down Expand Up @@ -717,12 +717,12 @@ function isWarned(emitter) {

// Move left one character/code point
fi.emit('keypress', '.', { name: 'left' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);

fi.emit('data', '🐕');
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);

if (common.hasIntl) {
Expand Down Expand Up @@ -753,7 +753,7 @@ function isWarned(emitter) {

// Move left one character/code point
fi.emit('keypress', '.', { name: 'right' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
if (common.hasIntl) {
assert.strictEqual(cursorPos.cols, 2);
Expand All @@ -764,7 +764,7 @@ function isWarned(emitter) {
}

fi.emit('data', '🐕');
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
if (common.hasIntl) {
assert.strictEqual(cursorPos.cols, 4);
Expand All @@ -790,19 +790,19 @@ function isWarned(emitter) {
});
fi.emit('data', 'the quick brown fox');
fi.emit('keypress', '.', { ctrl: true, name: 'left' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 16);
fi.emit('keypress', '.', { meta: true, name: 'b' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 10);
fi.emit('keypress', '.', { ctrl: true, name: 'right' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 16);
fi.emit('keypress', '.', { meta: true, name: 'f' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 19);
rli.close();
Expand Down Expand Up @@ -904,13 +904,13 @@ function isWarned(emitter) {
terminal: terminal
});
fi.emit('data', 'the quick brown fox');
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 19);

// Delete left character
fi.emit('keypress', '.', { ctrl: true, name: 'h' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 18);
rli.on('line', common.mustCall((line) => {
Expand All @@ -930,7 +930,7 @@ function isWarned(emitter) {
terminal: terminal
});
fi.emit('data', '💻');
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
if (common.hasIntl) {
assert.strictEqual(cursorPos.cols, 2);
Expand All @@ -939,7 +939,7 @@ function isWarned(emitter) {
}
// Delete left character
fi.emit('keypress', '.', { ctrl: true, name: 'h' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);
rli.on('line', common.mustCall((line) => {
Expand All @@ -962,13 +962,13 @@ function isWarned(emitter) {

// Go to the start of the line
fi.emit('keypress', '.', { ctrl: true, name: 'a' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);

// Delete right character
fi.emit('keypress', '.', { ctrl: true, name: 'd' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);
rli.on('line', common.mustCall((line) => {
Expand All @@ -991,13 +991,13 @@ function isWarned(emitter) {

// Go to the start of the line
fi.emit('keypress', '.', { ctrl: true, name: 'a' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);

// Delete right character
fi.emit('keypress', '.', { ctrl: true, name: 'd' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);
rli.on('line', common.mustCall((line) => {
Expand All @@ -1017,13 +1017,13 @@ function isWarned(emitter) {
terminal: terminal
});
fi.emit('data', 'the quick brown fox');
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 19);

// Delete from current to start of line
fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'backspace' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);
rli.on('line', common.mustCall((line) => {
Expand All @@ -1046,13 +1046,13 @@ function isWarned(emitter) {

// Go to the start of the line
fi.emit('keypress', '.', { ctrl: true, name: 'a' });
let cursorPos = rli._getCursorPos();
let cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);

// Delete from current to end of line
fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' });
cursorPos = rli._getCursorPos();
cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 0);
rli.on('line', common.mustCall((line) => {
Expand All @@ -1073,7 +1073,7 @@ function isWarned(emitter) {
});
fi.columns = 10;
fi.emit('data', 'multi-line text');
const cursorPos = rli._getCursorPos();
const cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 1);
assert.strictEqual(cursorPos.cols, 5);
rli.close();
Expand All @@ -1090,7 +1090,7 @@ function isWarned(emitter) {
});
fi.columns = 10;
fi.emit('data', 't');
const cursorPos = rli._getCursorPos();
const cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 4);
assert.strictEqual(cursorPos.cols, 3);
rli.close();
Expand All @@ -1108,7 +1108,7 @@ function isWarned(emitter) {
const lines = ['line 1', 'line 2', 'line 3'];
fi.emit('data', lines.join('\n'));
fi.emit('keypress', '.', { ctrl: true, name: 'l' });
const cursorPos = rli._getCursorPos();
const cursorPos = rli.getCursorPos();
assert.strictEqual(cursorPos.rows, 0);
assert.strictEqual(cursorPos.cols, 6);
rli.on('line', common.mustCall((line) => {
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-readline-position.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const ctrlU = { ctrl: true, name: 'u' };

for (const [cursor, string] of tests) {
rl.write(string);
assert.strictEqual(rl._getCursorPos().cols, cursor);
assert.strictEqual(rl.getCursorPos().cols, cursor);
rl.write(null, ctrlU);
}
}

0 comments on commit 5b49ded

Please sign in to comment.