From 795c7482f24c0c2f1b2db8d004b03ea373b6381b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 13 Jul 2019 19:22:46 -0400 Subject: [PATCH] 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 Reviewed-By: Rich Trott Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/readline.md | 10 +++++++++- lib/readline.js | 24 +++++++++++++++++------- test/parallel/test-readline-csi.js | 20 +++++++++++++++++++- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/doc/api/readline.md b/doc/api/readline.md index 936ffb5d842788..43314e136fcab3 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -525,14 +525,22 @@ if (process.stdin.isTTY) process.stdin.setRawMode(true); ``` -## readline.moveCursor(stream, dx, dy) +## readline.moveCursor(stream, dx, dy[, callback]) * `stream` {stream.Writable} * `dx` {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 position in a given [TTY][] `stream`. diff --git a/lib/readline.js b/lib/readline.js index 6a60df82c79776..cccae73eec5ffb 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -1210,21 +1210,31 @@ function cursorTo(stream, x, y) { * moves the cursor relative to its current location */ -function moveCursor(stream, dx, dy) { - if (stream === null || stream === undefined) - return; +function moveCursor(stream, dx, dy, callback) { + if (callback !== undefined && typeof callback !== 'function') + 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) { - stream.write(CSI`${-dx}D`); + data += CSI`${-dx}D`; } else if (dx > 0) { - stream.write(CSI`${dx}C`); + data += CSI`${dx}C`; } if (dy < 0) { - stream.write(CSI`${-dy}A`); + data += CSI`${-dy}A`; } else if (dy > 0) { - stream.write(CSI`${dy}B`); + data += CSI`${dy}B`; } + + return stream.write(data, callback); } /** diff --git a/test/parallel/test-readline-csi.js b/test/parallel/test-readline-csi.js index becd4cd8d4dc05..b89990d594dc80 100644 --- a/test/parallel/test-readline-csi.js +++ b/test/parallel/test-readline-csi.js @@ -83,10 +83,28 @@ assert.strictEqual(readline.clearLine(undefined, 0, common.mustCall()), true); [1, -1, '\x1b[1C\x1b[1A'], ].forEach((set) => { 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]); }); +// 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. readline.cursorTo(null); readline.cursorTo();