readline: expose stream API in moveCursor()

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

PR-URL: https://github.com/nodejs/node/pull/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>
This commit is contained in:
cjihrig 2019-07-13 19:22:46 -04:00
parent 79cc8bb241
commit 795c7482f2
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
3 changed files with 45 additions and 9 deletions

View File

@ -525,14 +525,22 @@ if (process.stdin.isTTY)
process.stdin.setRawMode(true); process.stdin.setRawMode(true);
``` ```
## readline.moveCursor(stream, dx, dy) ## readline.moveCursor(stream, dx, dy[, callback])
<!-- YAML <!-- YAML
added: v0.7.7 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} * `stream` {stream.Writable}
* `dx` {number} * `dx` {number}
* `dy` {number} * `dy` {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.moveCursor()` method moves the cursor *relative* to its current The `readline.moveCursor()` method moves the cursor *relative* to its current
position in a given [TTY][] `stream`. position in a given [TTY][] `stream`.

View File

@ -1210,21 +1210,31 @@ function cursorTo(stream, x, y) {
* moves the cursor relative to its current location * moves the cursor relative to its current location
*/ */
function moveCursor(stream, dx, dy) { function moveCursor(stream, dx, dy, callback) {
if (stream === null || stream === undefined) if (callback !== undefined && typeof callback !== 'function')
return; throw new ERR_INVALID_CALLBACK(callback);
if (stream == null || !(dx || dy)) {
if (typeof callback === 'function')
process.nextTick(callback);
return true;
}
let data = '';
if (dx < 0) { if (dx < 0) {
stream.write(CSI`${-dx}D`); data += CSI`${-dx}D`;
} else if (dx > 0) { } else if (dx > 0) {
stream.write(CSI`${dx}C`); data += CSI`${dx}C`;
} }
if (dy < 0) { if (dy < 0) {
stream.write(CSI`${-dy}A`); data += CSI`${-dy}A`;
} else if (dy > 0) { } else if (dy > 0) {
stream.write(CSI`${dy}B`); data += CSI`${dy}B`;
} }
return stream.write(data, callback);
} }
/** /**

View File

@ -83,10 +83,28 @@ assert.strictEqual(readline.clearLine(undefined, 0, common.mustCall()), true);
[1, -1, '\x1b[1C\x1b[1A'], [1, -1, '\x1b[1C\x1b[1A'],
].forEach((set) => { ].forEach((set) => {
writable.data = ''; writable.data = '';
readline.moveCursor(writable, set[0], set[1]); assert.strictEqual(readline.moveCursor(writable, set[0], set[1]), true);
assert.deepStrictEqual(writable.data, set[2]);
writable.data = '';
assert.strictEqual(
readline.moveCursor(writable, set[0], set[1], common.mustCall()),
true
);
assert.deepStrictEqual(writable.data, set[2]); assert.deepStrictEqual(writable.data, set[2]);
}); });
// Verify that moveCursor() throws on invalid callback.
assert.throws(() => {
readline.moveCursor(writable, 1, 1, null);
}, /ERR_INVALID_CALLBACK/);
// Verify that moveCursor() does not throw on null or undefined stream.
assert.strictEqual(readline.moveCursor(null, 1, 1), true);
assert.strictEqual(readline.moveCursor(undefined, 1, 1), true);
assert.strictEqual(readline.moveCursor(null, 1, 1, common.mustCall()), true);
assert.strictEqual(readline.moveCursor(undefined, 1, 1, common.mustCall()),
true);
// Undefined or null as stream should not throw. // Undefined or null as stream should not throw.
readline.cursorTo(null); readline.cursorTo(null);
readline.cursorTo(); readline.cursorTo();