Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 251x 251x 250x 250x 250x 250x 250x 250x 250x 250x 250x 250x 250x 828x 827x 827x 821x 821x 821x 821x 821x 821x 821x 821x 11198x 11198x 821x 821x 11198x 11198x 11198x 11198x 11198x 10x 10x 11198x 2x 2x 2x 2x 2x 2x 11198x 819x 828x 1x 1x 1x 1x 828x 250x 250x 498x 249x 249x 249x 498x 250x 251x 2x 251x 248x 248x 251x 2x 2x | 'use strict'; const { SafeStringIterator, Symbol, } = primordials; const { charLengthAt, CSI, emitKeys, } = require('internal/readline/utils'); const { kSawKeyPress, } = require('internal/readline/interface'); const { clearTimeout, setTimeout } = require('timers'); const { kEscape, } = CSI; const { StringDecoder } = require('string_decoder'); const KEYPRESS_DECODER = Symbol('keypress-decoder'); const ESCAPE_DECODER = Symbol('escape-decoder'); // GNU readline library - keyseq-timeout is 500ms (default) const ESCAPE_CODE_TIMEOUT = 500; /** * accepts a readable Stream instance and makes it emit "keypress" events */ function emitKeypressEvents(stream, iface = {}) { if (stream[KEYPRESS_DECODER]) return; stream[KEYPRESS_DECODER] = new StringDecoder('utf8'); stream[ESCAPE_DECODER] = emitKeys(stream); stream[ESCAPE_DECODER].next(); const triggerEscape = () => stream[ESCAPE_DECODER].next(''); const { escapeCodeTimeout = ESCAPE_CODE_TIMEOUT } = iface; let timeoutId; function onData(input) { if (stream.listenerCount('keypress') > 0) { const string = stream[KEYPRESS_DECODER].write(input); if (string) { clearTimeout(timeoutId); // This supports characters of length 2. iface[kSawKeyPress] = charLengthAt(string, 0) === string.length; iface.isCompletionEnabled = false; let length = 0; for (const character of new SafeStringIterator(string)) { length += character.length; if (length === string.length) { iface.isCompletionEnabled = true; } try { stream[ESCAPE_DECODER].next(character); // Escape letter at the tail position if (length === string.length && character === kEscape) { timeoutId = setTimeout(triggerEscape, escapeCodeTimeout); } } catch (err) { // If the generator throws (it could happen in the `keypress` // event), we need to restart it. stream[ESCAPE_DECODER] = emitKeys(stream); stream[ESCAPE_DECODER].next(); throw err; } } } } else { // Nobody's watching anyway stream.removeListener('data', onData); stream.on('newListener', onNewListener); } } function onNewListener(event) { if (event === 'keypress') { stream.on('data', onData); stream.removeListener('newListener', onNewListener); } } if (stream.listenerCount('keypress') > 0) { stream.on('data', onData); } else { stream.on('newListener', onNewListener); } } module.exports = emitKeypressEvents; |