* accepts a readable Stream instance and makes it emit "keypress" events
(stream, iface = { __proto__: null })
| 32 | */ |
| 33 | |
| 34 | function emitKeypressEvents(stream, iface = { __proto__: null }) { |
| 35 | if (stream[KEYPRESS_DECODER]) return; |
| 36 | |
| 37 | stream[KEYPRESS_DECODER] = new StringDecoder('utf8'); |
| 38 | |
| 39 | stream[ESCAPE_DECODER] = emitKeys(stream); |
| 40 | stream[ESCAPE_DECODER].next(); |
| 41 | |
| 42 | const triggerEscape = () => stream[ESCAPE_DECODER].next(''); |
| 43 | const { escapeCodeTimeout = ESCAPE_CODE_TIMEOUT } = iface; |
| 44 | let timeoutId; |
| 45 | |
| 46 | function onData(input) { |
| 47 | if (stream.listenerCount('keypress') > 0) { |
| 48 | const string = stream[KEYPRESS_DECODER].write(input); |
| 49 | if (string) { |
| 50 | clearTimeout(timeoutId); |
| 51 | |
| 52 | // This supports characters of length 2. |
| 53 | iface[kSawKeyPress] = charLengthAt(string, 0) === string.length; |
| 54 | iface.isCompletionEnabled = false; |
| 55 | |
| 56 | let length = 0; |
| 57 | for (const character of new SafeStringIterator(string)) { |
| 58 | length += character.length; |
| 59 | if (length === string.length) { |
| 60 | iface.isCompletionEnabled = true; |
| 61 | } |
| 62 | |
| 63 | try { |
| 64 | stream[ESCAPE_DECODER].next(character); |
| 65 | // Escape letter at the tail position |
| 66 | if (length === string.length && character === kEscape) { |
| 67 | timeoutId = setTimeout(triggerEscape, escapeCodeTimeout); |
| 68 | } |
| 69 | } catch (err) { |
| 70 | // If the generator throws (it could happen in the `keypress` |
| 71 | // event), we need to restart it. |
| 72 | stream[ESCAPE_DECODER] = emitKeys(stream); |
| 73 | stream[ESCAPE_DECODER].next(); |
| 74 | throw err; |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | } else { |
| 79 | // Nobody's watching anyway |
| 80 | stream.removeListener('data', onData); |
| 81 | stream.on('newListener', onNewListener); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | function onNewListener(event) { |
| 86 | if (event === 'keypress') { |
| 87 | stream.on('data', onData); |
| 88 | stream.removeListener('newListener', onNewListener); |
| 89 | } |
| 90 | } |
| 91 |
no test coverage detected
searching dependent graphs…