Skip to content
Permalink
Browse files

readline: expose stream API in cursorTo()

This commit adds an optional callback to cursorTo(), which is
passed to the stream's write() method. It also exposes the
return value of write().

PR-URL: #28674
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
  • Loading branch information...
cjihrig authored and targos committed Jul 14, 2019
1 parent 4a7e20f commit caee9106acd54832b529ac7f8ce7d9a8da170a4e
Showing with 36 additions and 17 deletions.
  1. +9 −1 doc/api/readline.md
  2. +10 −10 lib/readline.js
  3. +17 −6 test/parallel/test-readline-csi.js
@@ -487,14 +487,22 @@ function completer(linePartial, callback) {
}
```

## readline.cursorTo(stream, x, y)
## readline.cursorTo(stream, x, y[, callback])
<!-- YAML
added: v0.7.7
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/28674
description: The stream's write() callback and return value are exposed.
-->

* `stream` {stream.Writable}
* `x` {number}
* `y` {number}
* `callback` {Function} Invoked once the operation completes.
* Returns: {boolean} `false` if `stream` wishes for the calling code to wait for
the `'drain'` event to be emitted before continuing to write additional data;
otherwise `true`.

The `readline.cursorTo()` method moves cursor to the specified position in a
given [TTY][] `stream`.
@@ -1189,21 +1189,21 @@ function emitKeypressEvents(stream, iface) {
* moves the cursor to the x and y coordinate on the given stream
*/

function cursorTo(stream, x, y) {
if (stream === null || stream === undefined)
return;
function cursorTo(stream, x, y, callback) {
if (callback !== undefined && typeof callback !== 'function')
throw new ERR_INVALID_CALLBACK(callback);

if (typeof x !== 'number' && typeof y !== 'number')
return;
if (stream == null || (typeof x !== 'number' && typeof y !== 'number')) {
if (typeof callback === 'function')
process.nextTick(callback);
return true;
}

if (typeof x !== 'number')
throw new ERR_INVALID_CURSOR_POS();

if (typeof y !== 'number') {
stream.write(CSI`${x + 1}G`);
} else {
stream.write(CSI`${y + 1};${x + 1}H`);
}
const data = typeof y !== 'number' ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`;
return stream.write(data, callback);
}

/**
@@ -106,15 +106,17 @@ assert.strictEqual(readline.moveCursor(undefined, 1, 1, common.mustCall()),
true);

// Undefined or null as stream should not throw.
readline.cursorTo(null);
readline.cursorTo();
assert.strictEqual(readline.cursorTo(null), true);
assert.strictEqual(readline.cursorTo(), true);
assert.strictEqual(readline.cursorTo(null, 1, 1, common.mustCall()), true);
assert.strictEqual(readline.cursorTo(undefined, 1, 1, common.mustCall()), true);

writable.data = '';
readline.cursorTo(writable, 'a');
assert.strictEqual(readline.cursorTo(writable, 'a'), true);
assert.strictEqual(writable.data, '');

writable.data = '';
readline.cursorTo(writable, 'a', 'b');
assert.strictEqual(readline.cursorTo(writable, 'a', 'b'), true);
assert.strictEqual(writable.data, '');

writable.data = '';
@@ -128,9 +130,18 @@ common.expectsError(
assert.strictEqual(writable.data, '');

writable.data = '';
readline.cursorTo(writable, 1, 'a');
assert.strictEqual(readline.cursorTo(writable, 1, 'a'), true);
assert.strictEqual(writable.data, '\x1b[2G');

writable.data = '';
readline.cursorTo(writable, 1, 2);
assert.strictEqual(readline.cursorTo(writable, 1, 2), true);
assert.strictEqual(writable.data, '\x1b[3;2H');

writable.data = '';
assert.strictEqual(readline.cursorTo(writable, 1, 2, common.mustCall()), true);
assert.strictEqual(writable.data, '\x1b[3;2H');

// Verify that cursorTo() throws on invalid callback.
assert.throws(() => {
readline.cursorTo(writable, 1, 1, null);
}, /ERR_INVALID_CALLBACK/);

0 comments on commit caee910

Please sign in to comment.
You can’t perform that action at this time.