Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readline: promote _getCursorPos to public api #30687

Closed
Closed
Show file tree
Hide file tree
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
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 @@ -365,7 +365,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 @@ -481,7 +481,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 @@ -760,7 +760,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 @@ -777,20 +777,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);
}
}