| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -429,7 +429,10 @@ const consoleMethods = { | |||
| 429 | 429 | if (this._stdout.isTTY && process.env.TERM !== 'dumb') { | |
| 430 | 430 | // The require is here intentionally to avoid readline being | |
| 431 | 431 | // required too early when console is first loaded. | |
| 432 | - const { cursorTo, clearScreenDown } = require('readline'); | ||
| 432 | + const { | ||
| 433 | + cursorTo, | ||
| 434 | + clearScreenDown, | ||
| 435 | + } = require('internal/readline/callbacks'); | ||
| 433 | 436 | cursorTo(this._stdout, 0, 0); | |
| 434 | 437 | clearScreenDown(this._stdout); | |
| 435 | 438 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,132 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const { | ||
| 4 | + NumberIsNaN, | ||
| 5 | + } = primordials; | ||
| 6 | + | ||
| 7 | + const { | ||
| 8 | + codes: { | ||
| 9 | + ERR_INVALID_ARG_VALUE, | ||
| 10 | + ERR_INVALID_CURSOR_POS, | ||
| 11 | + }, | ||
| 12 | + } = require('internal/errors'); | ||
| 13 | + | ||
| 14 | + const { | ||
| 15 | + validateCallback, | ||
| 16 | + } = require('internal/validators'); | ||
| 17 | + const { | ||
| 18 | + CSI, | ||
| 19 | + } = require('internal/readline/utils'); | ||
| 20 | + | ||
| 21 | + const { | ||
| 22 | + kClearLine, | ||
| 23 | + kClearScreenDown, | ||
| 24 | + kClearToLineBeginning, | ||
| 25 | + kClearToLineEnd, | ||
| 26 | + } = CSI; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * moves the cursor to the x and y coordinate on the given stream | ||
| 31 | + */ | ||
| 32 | + | ||
| 33 | + function cursorTo(stream, x, y, callback) { | ||
| 34 | + if (callback !== undefined) { | ||
| 35 | + validateCallback(callback); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + if (typeof y === 'function') { | ||
| 39 | + callback = y; | ||
| 40 | + y = undefined; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + if (NumberIsNaN(x)) throw new ERR_INVALID_ARG_VALUE('x', x); | ||
| 44 | + if (NumberIsNaN(y)) throw new ERR_INVALID_ARG_VALUE('y', y); | ||
| 45 | + | ||
| 46 | + if (stream == null || (typeof x !== 'number' && typeof y !== 'number')) { | ||
| 47 | + if (typeof callback === 'function') process.nextTick(callback, null); | ||
| 48 | + return true; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + if (typeof x !== 'number') throw new ERR_INVALID_CURSOR_POS(); | ||
| 52 | + | ||
| 53 | + const data = typeof y !== 'number' ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`; | ||
| 54 | + return stream.write(data, callback); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * moves the cursor relative to its current location | ||
| 59 | + */ | ||
| 60 | + | ||
| 61 | + function moveCursor(stream, dx, dy, callback) { | ||
| 62 | + if (callback !== undefined) { | ||
| 63 | + validateCallback(callback); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + if (stream == null || !(dx || dy)) { | ||
| 67 | + if (typeof callback === 'function') process.nextTick(callback, null); | ||
| 68 | + return true; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + let data = ''; | ||
| 72 | + | ||
| 73 | + if (dx < 0) { | ||
| 74 | + data += CSI`${-dx}D`; | ||
| 75 | + } else if (dx > 0) { | ||
| 76 | + data += CSI`${dx}C`; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + if (dy < 0) { | ||
| 80 | + data += CSI`${-dy}A`; | ||
| 81 | + } else if (dy > 0) { | ||
| 82 | + data += CSI`${dy}B`; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + return stream.write(data, callback); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * clears the current line the cursor is on: | ||
| 90 | + * -1 for left of the cursor | ||
| 91 | + * +1 for right of the cursor | ||
| 92 | + * 0 for the entire line | ||
| 93 | + */ | ||
| 94 | + | ||
| 95 | + function clearLine(stream, dir, callback) { | ||
| 96 | + if (callback !== undefined) { | ||
| 97 | + validateCallback(callback); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + if (stream === null || stream === undefined) { | ||
| 101 | + if (typeof callback === 'function') process.nextTick(callback, null); | ||
| 102 | + return true; | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + const type = | ||
| 106 | + dir < 0 ? kClearToLineBeginning : dir > 0 ? kClearToLineEnd : kClearLine; | ||
| 107 | + return stream.write(type, callback); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * clears the screen from the current position of the cursor down | ||
| 112 | + */ | ||
| 113 | + | ||
| 114 | + function clearScreenDown(stream, callback) { | ||
| 115 | + if (callback !== undefined) { | ||
| 116 | + validateCallback(callback); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + if (stream === null || stream === undefined) { | ||
| 120 | + if (typeof callback === 'function') process.nextTick(callback, null); | ||
| 121 | + return true; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + return stream.write(kClearScreenDown, callback); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + module.exports = { | ||
| 128 | + clearLine, | ||
| 129 | + clearScreenDown, | ||
| 130 | + cursorTo, | ||
| 131 | + moveCursor, | ||
| 132 | + }; | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,96 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const { | ||
| 4 | + SafeStringIterator, | ||
| 5 | + Symbol, | ||
| 6 | + } = primordials; | ||
| 7 | + | ||
| 8 | + const { | ||
| 9 | + charLengthAt, | ||
| 10 | + CSI, | ||
| 11 | + emitKeys, | ||
| 12 | + } = require('internal/readline/utils'); | ||
| 13 | + | ||
| 14 | + const { clearTimeout, setTimeout } = require('timers'); | ||
| 15 | + const { | ||
| 16 | + kEscape, | ||
| 17 | + } = CSI; | ||
| 18 | + | ||
| 19 | + const { StringDecoder } = require('string_decoder'); | ||
| 20 | + | ||
| 21 | + const KEYPRESS_DECODER = Symbol('keypress-decoder'); | ||
| 22 | + const ESCAPE_DECODER = Symbol('escape-decoder'); | ||
| 23 | + | ||
| 24 | + // GNU readline library - keyseq-timeout is 500ms (default) | ||
| 25 | + const ESCAPE_CODE_TIMEOUT = 500; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * accepts a readable Stream instance and makes it emit "keypress" events | ||
| 29 | + */ | ||
| 30 | + | ||
| 31 | + function emitKeypressEvents(stream, iface = {}) { | ||
| 32 | + if (stream[KEYPRESS_DECODER]) return; | ||
| 33 | + | ||
| 34 | + stream[KEYPRESS_DECODER] = new StringDecoder('utf8'); | ||
| 35 | + | ||
| 36 | + stream[ESCAPE_DECODER] = emitKeys(stream); | ||
| 37 | + stream[ESCAPE_DECODER].next(); | ||
| 38 | + | ||
| 39 | + const triggerEscape = () => stream[ESCAPE_DECODER].next(''); | ||
| 40 | + const { escapeCodeTimeout = ESCAPE_CODE_TIMEOUT } = iface; | ||
| 41 | + let timeoutId; | ||
| 42 | + | ||
| 43 | + function onData(input) { | ||
| 44 | + if (stream.listenerCount('keypress') > 0) { | ||
| 45 | + const string = stream[KEYPRESS_DECODER].write(input); | ||
| 46 | + if (string) { | ||
| 47 | + clearTimeout(timeoutId); | ||
| 48 | + | ||
| 49 | + // This supports characters of length 2. | ||
| 50 | + iface._sawKeyPress = charLengthAt(string, 0) === string.length; | ||
| 51 | + iface.isCompletionEnabled = false; | ||
| 52 | + | ||
| 53 | + let length = 0; | ||
| 54 | + for (const character of new SafeStringIterator(string)) { | ||
| 55 | + length += character.length; | ||
| 56 | + if (length === string.length) { | ||
| 57 | + iface.isCompletionEnabled = true; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + try { | ||
| 61 | + stream[ESCAPE_DECODER].next(character); | ||
| 62 | + // Escape letter at the tail position | ||
| 63 | + if (length === string.length && character === kEscape) { | ||
| 64 | + timeoutId = setTimeout(triggerEscape, escapeCodeTimeout); | ||
| 65 | + } | ||
| 66 | + } catch (err) { | ||
| 67 | + // If the generator throws (it could happen in the `keypress` | ||
| 68 | + // event), we need to restart it. | ||
| 69 | + stream[ESCAPE_DECODER] = emitKeys(stream); | ||
| 70 | + stream[ESCAPE_DECODER].next(); | ||
| 71 | + throw err; | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + } else { | ||
| 76 | + // Nobody's watching anyway | ||
| 77 | + stream.removeListener('data', onData); | ||
| 78 | + stream.on('newListener', onNewListener); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + function onNewListener(event) { | ||
| 83 | + if (event === 'keypress') { | ||
| 84 | + stream.on('data', onData); | ||
| 85 | + stream.removeListener('newListener', onNewListener); | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + if (stream.listenerCount('keypress') > 0) { | ||
| 90 | + stream.on('data', onData); | ||
| 91 | + } else { | ||
| 92 | + stream.on('newListener', onNewListener); | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + module.exports = emitKeypressEvents; | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,7 +41,7 @@ const { | |||
| 41 | 41 | clearScreenDown, | |
| 42 | 42 | cursorTo, | |
| 43 | 43 | moveCursor, | |
| 44 | - } = require('readline'); | ||
| 44 | + } = require('internal/readline/callbacks'); | ||
| 45 | 45 | ||
| 46 | 46 | const { | |
| 47 | 47 | commonPrefix, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments