.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / enquirer / lib / keypress.js
1 'use strict';
2
3 const readline = require('readline');
4 const combos = require('./combos');
5
6 /* eslint-disable no-control-regex */
7 const metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
8 const fnKeyRe = /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
9 const keyName = {
10     /* xterm/gnome ESC O letter */
11     'OP': 'f1',
12     'OQ': 'f2',
13     'OR': 'f3',
14     'OS': 'f4',
15     /* xterm/rxvt ESC [ number ~ */
16     '[11~': 'f1',
17     '[12~': 'f2',
18     '[13~': 'f3',
19     '[14~': 'f4',
20     /* from Cygwin and used in libuv */
21     '[[A': 'f1',
22     '[[B': 'f2',
23     '[[C': 'f3',
24     '[[D': 'f4',
25     '[[E': 'f5',
26     /* common */
27     '[15~': 'f5',
28     '[17~': 'f6',
29     '[18~': 'f7',
30     '[19~': 'f8',
31     '[20~': 'f9',
32     '[21~': 'f10',
33     '[23~': 'f11',
34     '[24~': 'f12',
35     /* xterm ESC [ letter */
36     '[A': 'up',
37     '[B': 'down',
38     '[C': 'right',
39     '[D': 'left',
40     '[E': 'clear',
41     '[F': 'end',
42     '[H': 'home',
43     /* xterm/gnome ESC O letter */
44     'OA': 'up',
45     'OB': 'down',
46     'OC': 'right',
47     'OD': 'left',
48     'OE': 'clear',
49     'OF': 'end',
50     'OH': 'home',
51     /* xterm/rxvt ESC [ number ~ */
52     '[1~': 'home',
53     '[2~': 'insert',
54     '[3~': 'delete',
55     '[4~': 'end',
56     '[5~': 'pageup',
57     '[6~': 'pagedown',
58     /* putty */
59     '[[5~': 'pageup',
60     '[[6~': 'pagedown',
61     /* rxvt */
62     '[7~': 'home',
63     '[8~': 'end',
64     /* rxvt keys with modifiers */
65     '[a': 'up',
66     '[b': 'down',
67     '[c': 'right',
68     '[d': 'left',
69     '[e': 'clear',
70
71     '[2$': 'insert',
72     '[3$': 'delete',
73     '[5$': 'pageup',
74     '[6$': 'pagedown',
75     '[7$': 'home',
76     '[8$': 'end',
77
78     'Oa': 'up',
79     'Ob': 'down',
80     'Oc': 'right',
81     'Od': 'left',
82     'Oe': 'clear',
83
84     '[2^': 'insert',
85     '[3^': 'delete',
86     '[5^': 'pageup',
87     '[6^': 'pagedown',
88     '[7^': 'home',
89     '[8^': 'end',
90     /* misc. */
91     '[Z': 'tab',
92 }
93
94 function isShiftKey(code) {
95     return ['[a', '[b', '[c', '[d', '[e', '[2$', '[3$', '[5$', '[6$', '[7$', '[8$', '[Z'].includes(code)
96 }
97
98 function isCtrlKey(code) {
99     return [ 'Oa', 'Ob', 'Oc', 'Od', 'Oe', '[2^', '[3^', '[5^', '[6^', '[7^', '[8^'].includes(code)
100 }
101
102 const keypress = (s = '', event = {}) => {
103   let parts;
104   let key = {
105     name: event.name,
106     ctrl: false,
107     meta: false,
108     shift: false,
109     option: false,
110     sequence: s,
111     raw: s,
112     ...event
113   };
114
115   if (Buffer.isBuffer(s)) {
116     if (s[0] > 127 && s[1] === void 0) {
117       s[0] -= 128;
118       s = '\x1b' + String(s);
119     } else {
120       s = String(s);
121     }
122   } else if (s !== void 0 && typeof s !== 'string') {
123     s = String(s);
124   } else if (!s) {
125     s = key.sequence || '';
126   }
127
128   key.sequence = key.sequence || s || key.name;
129
130   if (s === '\r') {
131     // carriage return
132     key.raw = void 0;
133     key.name = 'return';
134   } else if (s === '\n') {
135     // enter, should have been called linefeed
136     key.name = 'enter';
137   } else if (s === '\t') {
138     // tab
139     key.name = 'tab';
140   } else if (s === '\b' || s === '\x7f' || s === '\x1b\x7f' || s === '\x1b\b') {
141     // backspace or ctrl+h
142     key.name = 'backspace';
143     key.meta = s.charAt(0) === '\x1b';
144   } else if (s === '\x1b' || s === '\x1b\x1b') {
145     // escape key
146     key.name = 'escape';
147     key.meta = s.length === 2;
148   } else if (s === ' ' || s === '\x1b ') {
149     key.name = 'space';
150     key.meta = s.length === 2;
151   } else if (s <= '\x1a') {
152     // ctrl+letter
153     key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
154     key.ctrl = true;
155   } else if (s.length === 1 && s >= '0' && s <= '9') {
156     // number
157     key.name = 'number';
158   } else if (s.length === 1 && s >= 'a' && s <= 'z') {
159     // lowercase letter
160     key.name = s;
161   } else if (s.length === 1 && s >= 'A' && s <= 'Z') {
162     // shift+letter
163     key.name = s.toLowerCase();
164     key.shift = true;
165   } else if ((parts = metaKeyCodeRe.exec(s))) {
166     // meta+character key
167     key.meta = true;
168     key.shift = /^[A-Z]$/.test(parts[1]);
169   } else if ((parts = fnKeyRe.exec(s))) {
170     let segs = [...s];
171
172     if (segs[0] === '\u001b' && segs[1] === '\u001b') {
173       key.option = true;
174     }
175
176     // ansi escape sequence
177     // reassemble the key code leaving out leading \x1b's,
178     // the modifier key bitflag and any meaningless "1;" sequence
179     let code = [parts[1], parts[2], parts[4], parts[6]].filter(Boolean).join('');
180     let modifier = (parts[3] || parts[5] || 1) - 1;
181
182     // Parse the key modifier
183     key.ctrl = !!(modifier & 4);
184     key.meta = !!(modifier & 10);
185     key.shift = !!(modifier & 1);
186     key.code = code;
187
188     key.name = keyName[code];
189     key.shift = isShiftKey(code) || key.shift;
190     key.ctrl = isCtrlKey(code) || key.ctrl;
191   }
192   return key;
193 };
194
195 keypress.listen = (options = {}, onKeypress) => {
196   let { stdin } = options;
197
198   if (!stdin || (stdin !== process.stdin && !stdin.isTTY)) {
199     throw new Error('Invalid stream passed');
200   }
201
202   let rl = readline.createInterface({ terminal: true, input: stdin });
203   readline.emitKeypressEvents(stdin, rl);
204
205   let on = (buf, key) => onKeypress(buf, keypress(buf, key), rl);
206   let isRaw = stdin.isRaw;
207
208   if (stdin.isTTY) stdin.setRawMode(true);
209   stdin.on('keypress', on);
210   rl.resume();
211
212   let off = () => {
213     if (stdin.isTTY) stdin.setRawMode(isRaw);
214     stdin.removeListener('keypress', on);
215     rl.pause();
216     rl.close();
217   };
218
219   return off;
220 };
221
222 keypress.action = (buf, key, customActions) => {
223   let obj = { ...combos, ...customActions };
224   if (key.ctrl) {
225     key.action = obj.ctrl[key.name];
226     return key;
227   }
228
229   if (key.option && obj.option) {
230     key.action = obj.option[key.name];
231     return key;
232   }
233
234   if (key.shift) {
235     key.action = obj.shift[key.name];
236     return key;
237   }
238
239   key.action = obj.keys[key.name];
240   return key;
241 };
242
243 module.exports = keypress;