reslop 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -9
- package/README.md +25 -40
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +0 -1
- package/lib/api.js +5 -0
- package/lib/cli.js +84 -79
- package/lib/clipboard.js +1 -1
- package/lib/deps.js +1440 -0
- package/lib/detect.js +4 -4
- package/lib/diff.js +40 -63
- package/lib/editor.js +1 -1
- package/lib/files.js +23 -4
- package/lib/git.js +367 -18
- package/lib/github.js +625 -0
- package/lib/highlight.js +149 -166
- package/lib/keys.js +34 -41
- package/lib/render.js +218 -143
- package/lib/review.js +52 -45
- package/lib/select.js +21 -31
- package/lib/session.js +298 -235
- package/lib/source.js +30 -0
- package/package.json +37 -18
package/lib/highlight.js
CHANGED
|
@@ -258,7 +258,7 @@ const LOG_DATETIME_RE = new RegExp(
|
|
|
258
258
|
'(?:\\.\\d+)?(?:Z|[+-]\\d{2}:?\\d{2})?)',
|
|
259
259
|
);
|
|
260
260
|
|
|
261
|
-
const LOG_TAG_STYLE =
|
|
261
|
+
const LOG_TAG_STYLE = {
|
|
262
262
|
error: 'logError',
|
|
263
263
|
err: 'logError',
|
|
264
264
|
warn: 'logWarn',
|
|
@@ -266,24 +266,24 @@ const LOG_TAG_STYLE = Object.assign(Object.create(null), {
|
|
|
266
266
|
info: 'logInfo',
|
|
267
267
|
debug: 'logDebug',
|
|
268
268
|
log: 'plain',
|
|
269
|
-
}
|
|
269
|
+
};
|
|
270
270
|
|
|
271
|
-
const JSON_LITERAL =
|
|
271
|
+
const JSON_LITERAL = {
|
|
272
272
|
true: 'literal',
|
|
273
273
|
false: 'literal',
|
|
274
274
|
null: 'literal',
|
|
275
|
-
}
|
|
275
|
+
};
|
|
276
276
|
|
|
277
|
-
const CSS_NEXT_STYLE =
|
|
277
|
+
const CSS_NEXT_STYLE = {
|
|
278
278
|
':': 'property',
|
|
279
279
|
'{': 'tag',
|
|
280
|
-
}
|
|
280
|
+
};
|
|
281
281
|
|
|
282
|
-
const EXPECT_STYLE =
|
|
282
|
+
const EXPECT_STYLE = {
|
|
283
283
|
function: 'function',
|
|
284
284
|
class: 'className',
|
|
285
285
|
type: 'className',
|
|
286
|
-
}
|
|
286
|
+
};
|
|
287
287
|
|
|
288
288
|
const NEXT_EXPECT = {
|
|
289
289
|
function: 'function',
|
|
@@ -294,33 +294,30 @@ const NEXT_EXPECT = {
|
|
|
294
294
|
};
|
|
295
295
|
|
|
296
296
|
const wordStyle = (words, style) => {
|
|
297
|
-
const table =
|
|
297
|
+
const table = {};
|
|
298
298
|
for (const word of words) table[word] = style;
|
|
299
299
|
return table;
|
|
300
300
|
};
|
|
301
301
|
|
|
302
|
-
const BASH_WORD_STYLE =
|
|
303
|
-
|
|
304
|
-
wordStyle(
|
|
305
|
-
|
|
306
|
-
);
|
|
302
|
+
const BASH_WORD_STYLE = {
|
|
303
|
+
...wordStyle(BASH_KEYWORDS, 'control'),
|
|
304
|
+
...wordStyle(BASH_BUILTINS, 'function'),
|
|
305
|
+
};
|
|
307
306
|
|
|
308
307
|
const typeOverlay = TYPES.filter((word) => STORAGE.includes(word));
|
|
309
308
|
|
|
310
|
-
const WORD_STYLE =
|
|
311
|
-
|
|
312
|
-
wordStyle(
|
|
313
|
-
wordStyle(
|
|
314
|
-
wordStyle(
|
|
315
|
-
wordStyle(
|
|
316
|
-
|
|
317
|
-
);
|
|
309
|
+
const WORD_STYLE = {
|
|
310
|
+
...wordStyle(CONTROL, 'control'),
|
|
311
|
+
...wordStyle(LITERALS, 'literal'),
|
|
312
|
+
...wordStyle(BUILTINS, 'className'),
|
|
313
|
+
...wordStyle(STORAGE, 'storage'),
|
|
314
|
+
...wordStyle(typeOverlay, 'type'),
|
|
315
|
+
};
|
|
318
316
|
|
|
319
|
-
const TS_WORD_STYLE =
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
);
|
|
317
|
+
const TS_WORD_STYLE = {
|
|
318
|
+
...WORD_STYLE,
|
|
319
|
+
...wordStyle(TYPES, 'type'),
|
|
320
|
+
};
|
|
324
321
|
|
|
325
322
|
const peekIdent = (source, i) => {
|
|
326
323
|
if (!/[A-Za-z_$]/.test(source[i] || '')) return null;
|
|
@@ -427,8 +424,6 @@ const styleProperty = ({ out }) => {
|
|
|
427
424
|
return /\.$/.test(prev) ? 'property' : null;
|
|
428
425
|
};
|
|
429
426
|
|
|
430
|
-
const styleVariable = () => 'variable';
|
|
431
|
-
|
|
432
427
|
const IDENT_RULES = [
|
|
433
428
|
styleExpected,
|
|
434
429
|
styleKeyword,
|
|
@@ -437,7 +432,6 @@ const IDENT_RULES = [
|
|
|
437
432
|
styleCall,
|
|
438
433
|
styleAssign,
|
|
439
434
|
styleProperty,
|
|
440
|
-
styleVariable,
|
|
441
435
|
];
|
|
442
436
|
|
|
443
437
|
const identStyle = (ctx) => {
|
|
@@ -445,7 +439,7 @@ const identStyle = (ctx) => {
|
|
|
445
439
|
const style = rule(ctx);
|
|
446
440
|
if (style) return style;
|
|
447
441
|
}
|
|
448
|
-
return '
|
|
442
|
+
return 'variable';
|
|
449
443
|
};
|
|
450
444
|
|
|
451
445
|
const readString = (source, i) => {
|
|
@@ -522,150 +516,143 @@ const isRegexContext = (out) => {
|
|
|
522
516
|
return afterOperator || afterKeyword;
|
|
523
517
|
};
|
|
524
518
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
519
|
+
const highlightTemplate = (source, i, highlightExpr) => {
|
|
520
|
+
const n = source.length;
|
|
521
|
+
let j = i + 1;
|
|
522
|
+
const parts = [];
|
|
523
|
+
emit(parts, 'template', '`');
|
|
524
|
+
let buf = '';
|
|
525
|
+
const flush = () => {
|
|
526
|
+
if (buf) {
|
|
527
|
+
emit(parts, 'template', buf);
|
|
528
|
+
buf = '';
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
while (j < n) {
|
|
532
|
+
if (source[j] === '\\') {
|
|
533
|
+
flush();
|
|
534
|
+
emit(parts, 'escape', source.slice(j, j + 2));
|
|
535
|
+
j += 2;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (source[j] === '`') {
|
|
539
|
+
flush();
|
|
540
|
+
emit(parts, 'template', '`');
|
|
541
|
+
j += 1;
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
if (source[j] === '$' && source[j + 1] === '{') {
|
|
545
|
+
flush();
|
|
546
|
+
emit(parts, 'interpolation', '${');
|
|
547
|
+
j += 2;
|
|
548
|
+
const interp = readTemplateInterp(source, j);
|
|
549
|
+
const inner = highlightExpr(interp.expr, false);
|
|
550
|
+
for (const t of inner) parts.push(t);
|
|
551
|
+
j = interp.end;
|
|
552
|
+
if (source[j] === '}') {
|
|
553
|
+
emit(parts, 'interpolation', '}');
|
|
554
|
+
j += 1;
|
|
541
555
|
}
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
buf += source[j];
|
|
559
|
+
j += 1;
|
|
560
|
+
}
|
|
561
|
+
flush();
|
|
562
|
+
return { tokens: parts, end: j };
|
|
563
|
+
};
|
|
542
564
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
565
|
+
const highlightJsFamily = (source, ts = false) => {
|
|
566
|
+
const out = [];
|
|
567
|
+
let i = 0;
|
|
568
|
+
const n = source.length;
|
|
569
|
+
let expectName = null;
|
|
549
570
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
i = r.end;
|
|
554
|
-
continue;
|
|
555
|
-
}
|
|
571
|
+
while (i < n) {
|
|
572
|
+
const ch = source[i];
|
|
573
|
+
const next = source[i + 1];
|
|
556
574
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
575
|
+
if (ch === '/' && next === '/') {
|
|
576
|
+
const { text, end } = readUntilNl(source, i);
|
|
577
|
+
emit(out, 'comment', text);
|
|
578
|
+
i = end;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
563
581
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
582
|
+
if (ch === '/' && next === '*') {
|
|
583
|
+
const { text, end } = readBlockComment(source, i);
|
|
584
|
+
emit(out, 'comment', text);
|
|
585
|
+
i = end;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
570
588
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
589
|
+
if (ch === '`') {
|
|
590
|
+
const r = highlightTemplate(source, i, highlightJsFamily);
|
|
591
|
+
for (const t of r.tokens) out.push(t);
|
|
592
|
+
i = r.end;
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
577
595
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
continue;
|
|
585
|
-
}
|
|
596
|
+
if (QUOTES.includes(ch)) {
|
|
597
|
+
const { text, end } = readString(source, i);
|
|
598
|
+
emit(out, 'string', text);
|
|
599
|
+
i = end;
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
586
602
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
emit(out, identStyle(ctx), word);
|
|
594
|
-
if (EXPECT_STYLE[expectName]) expectName = null;
|
|
595
|
-
else expectName = NEXT_EXPECT[word] ?? null;
|
|
596
|
-
i = end;
|
|
597
|
-
continue;
|
|
598
|
-
}
|
|
603
|
+
if (ch === '/' && isRegexContext(out)) {
|
|
604
|
+
const { text, end } = readRegex(source, i);
|
|
605
|
+
emit(out, 'regex', text);
|
|
606
|
+
i = end;
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
599
609
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
continue;
|
|
606
|
-
}
|
|
607
|
-
if (/[{}()[\];,.]/.test(ch)) {
|
|
608
|
-
emit(out, 'punct', ch);
|
|
609
|
-
i += 1;
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
|
-
emit(out, 'plain', ch);
|
|
613
|
-
i += 1;
|
|
610
|
+
if (/[0-9]/.test(ch) || (ch === '.' && /[0-9]/.test(next || ''))) {
|
|
611
|
+
const { text, end } = readJsNumber(source, i);
|
|
612
|
+
emit(out, 'number', text);
|
|
613
|
+
i = end;
|
|
614
|
+
continue;
|
|
614
615
|
}
|
|
615
|
-
return out;
|
|
616
|
-
}
|
|
617
616
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
if (buf) {
|
|
626
|
-
emit(parts, 'template', buf);
|
|
627
|
-
buf = '';
|
|
628
|
-
}
|
|
629
|
-
};
|
|
630
|
-
while (j < n) {
|
|
631
|
-
if (source[j] === '\\') {
|
|
632
|
-
flush();
|
|
633
|
-
emit(parts, 'escape', source.slice(j, j + 2));
|
|
634
|
-
j += 2;
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
if (source[j] === '`') {
|
|
638
|
-
flush();
|
|
639
|
-
emit(parts, 'template', '`');
|
|
640
|
-
j += 1;
|
|
641
|
-
break;
|
|
642
|
-
}
|
|
643
|
-
if (source[j] === '$' && source[j + 1] === '{') {
|
|
644
|
-
flush();
|
|
645
|
-
emit(parts, 'interpolation', '${');
|
|
646
|
-
j += 2;
|
|
647
|
-
const interp = readTemplateInterp(source, j);
|
|
648
|
-
const inner = this.highlightJsFamily(interp.expr, false);
|
|
649
|
-
for (const t of inner) parts.push(t);
|
|
650
|
-
j = interp.end;
|
|
651
|
-
if (source[j] === '}') {
|
|
652
|
-
emit(parts, 'interpolation', '}');
|
|
653
|
-
j += 1;
|
|
654
|
-
}
|
|
655
|
-
continue;
|
|
656
|
-
}
|
|
657
|
-
buf += source[j];
|
|
658
|
-
j += 1;
|
|
617
|
+
if (ch === '@') {
|
|
618
|
+
let j = i + 1;
|
|
619
|
+
while (j < n && /[A-Za-z0-9_$]/.test(source[j])) j += 1;
|
|
620
|
+
emit(out, 'decorator', source.slice(i, j));
|
|
621
|
+
i = j;
|
|
622
|
+
expectName = null;
|
|
623
|
+
continue;
|
|
659
624
|
}
|
|
660
|
-
flush();
|
|
661
|
-
return { tokens: parts, end: j };
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
625
|
|
|
665
|
-
|
|
626
|
+
if (/[A-Za-z_$]/.test(ch)) {
|
|
627
|
+
const word = peekIdent(source, i);
|
|
628
|
+
const end = i + word.length;
|
|
629
|
+
const k = skipWs(source, end);
|
|
630
|
+
const after = source[k];
|
|
631
|
+
const ctx = { word, ts, after, source, k, out, expectName };
|
|
632
|
+
emit(out, identStyle(ctx), word);
|
|
633
|
+
if (EXPECT_STYLE[expectName]) expectName = null;
|
|
634
|
+
else expectName = NEXT_EXPECT[word] ?? null;
|
|
635
|
+
i = end;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
666
638
|
|
|
667
|
-
|
|
668
|
-
|
|
639
|
+
if (/[=<>!+\-*/%&|^~?:]/.test(ch)) {
|
|
640
|
+
const { text, end } = readJsOperator(source, i);
|
|
641
|
+
emit(out, 'operator', text);
|
|
642
|
+
i = end;
|
|
643
|
+
expectName = null;
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
if (/[{}()[\];,.]/.test(ch)) {
|
|
647
|
+
emit(out, 'punct', ch);
|
|
648
|
+
i += 1;
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
emit(out, 'plain', ch);
|
|
652
|
+
i += 1;
|
|
653
|
+
}
|
|
654
|
+
return out;
|
|
655
|
+
};
|
|
669
656
|
|
|
670
657
|
const highlightJson = (source) => {
|
|
671
658
|
const out = [];
|
|
@@ -1161,9 +1148,6 @@ const HIGHLIGHTERS = {
|
|
|
1161
1148
|
html: highlightHtml,
|
|
1162
1149
|
csv: highlightCsv,
|
|
1163
1150
|
bash: highlightBash,
|
|
1164
|
-
sh: highlightBash,
|
|
1165
|
-
shell: highlightBash,
|
|
1166
|
-
zsh: highlightBash,
|
|
1167
1151
|
log: highlightLog,
|
|
1168
1152
|
dot: highlightDot,
|
|
1169
1153
|
txt: highlightTxt,
|
|
@@ -1227,8 +1211,7 @@ const overlayTokens = (tokens, spans) => {
|
|
|
1227
1211
|
};
|
|
1228
1212
|
|
|
1229
1213
|
module.exports = {
|
|
1214
|
+
tokensText,
|
|
1230
1215
|
tokenize,
|
|
1231
1216
|
overlayTokens,
|
|
1232
|
-
tokensText,
|
|
1233
|
-
HIGHLIGHTERS,
|
|
1234
1217
|
};
|
package/lib/keys.js
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const ACTIONS =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
const ACTIONS = {
|
|
4
|
+
add: { keys: ['a'], label: 'Add' },
|
|
5
|
+
unstage: { keys: ['u'], label: 'Unstage' },
|
|
6
|
+
revert: { keys: ['r'], label: 'Revert' },
|
|
7
|
+
prev: { keys: ['left', 'p'], hot: '←', label: 'Prev' },
|
|
8
|
+
next: { keys: ['right', 'n'], hot: '→', label: 'Next' },
|
|
9
|
+
layout: { keys: ['m'], label: 'Mode' },
|
|
10
|
+
files: { keys: ['l'], label: 'Files' },
|
|
11
|
+
feedback: { keys: ['f'], label: 'Feedback' },
|
|
12
|
+
todo: { keys: ['t'], label: 'Todo' },
|
|
13
|
+
quit: { keys: ['q', 'ctrl-c'], label: 'Quit' },
|
|
14
|
+
};
|
|
15
|
+
const ACTION_IDS = Object.keys(ACTIONS);
|
|
16
|
+
|
|
17
|
+
const FILES_DISABLED = ['layout', 'feedback'];
|
|
16
18
|
|
|
17
19
|
const SCROLL = {
|
|
18
20
|
up: 'scrollUp',
|
|
19
|
-
k: 'scrollUp',
|
|
20
21
|
down: 'scrollDown',
|
|
21
|
-
j: 'scrollDown',
|
|
22
|
-
h: 'help',
|
|
23
|
-
'?': 'help',
|
|
24
22
|
enter: 'open',
|
|
25
23
|
backspace: 'removeTodo',
|
|
26
24
|
delete: 'removeTodo',
|
|
27
25
|
};
|
|
28
26
|
|
|
29
|
-
const KEY_TO_ACTION =
|
|
27
|
+
const KEY_TO_ACTION = {};
|
|
30
28
|
|
|
31
|
-
for (const
|
|
32
|
-
for (const key of
|
|
29
|
+
for (const id of ACTION_IDS) {
|
|
30
|
+
for (const key of ACTIONS[id].keys) KEY_TO_ACTION[key] = id;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
for (const
|
|
33
|
+
for (const key of Object.keys(SCROLL)) KEY_TO_ACTION[key] = SCROLL[key];
|
|
36
34
|
|
|
37
35
|
const CSI_KEYS = {
|
|
38
36
|
A: 'up',
|
|
@@ -43,16 +41,25 @@ const CSI_KEYS = {
|
|
|
43
41
|
F: 'end',
|
|
44
42
|
};
|
|
45
43
|
|
|
46
|
-
const CSI_TILDE =
|
|
44
|
+
const CSI_TILDE = {
|
|
47
45
|
1: 'home',
|
|
48
46
|
3: 'delete',
|
|
49
47
|
4: 'end',
|
|
50
|
-
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const LITERAL_KEY = {
|
|
51
|
+
'\x7f': 'backspace',
|
|
52
|
+
'\x08': 'backspace',
|
|
53
|
+
'\t': 'tab',
|
|
54
|
+
'\x03': 'ctrl-c',
|
|
55
|
+
'\r': 'enter',
|
|
56
|
+
'\n': 'enter',
|
|
57
|
+
};
|
|
51
58
|
|
|
52
|
-
const MOUSE_WHEEL =
|
|
59
|
+
const MOUSE_WHEEL = {
|
|
53
60
|
64: 'wheelUp',
|
|
54
61
|
65: 'wheelDown',
|
|
55
|
-
}
|
|
62
|
+
};
|
|
56
63
|
|
|
57
64
|
const mouseKindFromButton = (button, press) => {
|
|
58
65
|
const wheel = MOUSE_WHEEL[button];
|
|
@@ -62,11 +69,6 @@ const mouseKindFromButton = (button, press) => {
|
|
|
62
69
|
return 'press';
|
|
63
70
|
};
|
|
64
71
|
|
|
65
|
-
const mouseKind = (event) => {
|
|
66
|
-
if (event.kind) return event.kind;
|
|
67
|
-
return mouseKindFromButton(event.button, event.press);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
72
|
const parseMouse = (body, flag) => {
|
|
71
73
|
const parts = body.split(';');
|
|
72
74
|
if (parts.length < 3) return null;
|
|
@@ -121,15 +123,6 @@ const parseEsc = (text, start) => {
|
|
|
121
123
|
return { event: { type: 'key', key: 'escape' }, end: start + 1 };
|
|
122
124
|
};
|
|
123
125
|
|
|
124
|
-
const LITERAL_KEY = Object.assign(Object.create(null), {
|
|
125
|
-
'\x7f': 'backspace',
|
|
126
|
-
'\x08': 'backspace',
|
|
127
|
-
'\t': 'tab',
|
|
128
|
-
'\x03': 'ctrl-c',
|
|
129
|
-
'\r': 'enter',
|
|
130
|
-
'\n': 'enter',
|
|
131
|
-
});
|
|
132
|
-
|
|
133
126
|
const decodeChunk = (text, carry = '') => {
|
|
134
127
|
const source = carry + text;
|
|
135
128
|
const events = [];
|
|
@@ -197,12 +190,12 @@ const hitAction = (hits, x) => {
|
|
|
197
190
|
|
|
198
191
|
module.exports = {
|
|
199
192
|
ACTIONS,
|
|
200
|
-
|
|
193
|
+
ACTION_IDS,
|
|
194
|
+
FILES_DISABLED,
|
|
201
195
|
decodeChunk,
|
|
202
196
|
actionFromKey,
|
|
203
197
|
actionHot,
|
|
204
198
|
actionLetter,
|
|
205
199
|
buttonWord,
|
|
206
200
|
hitAction,
|
|
207
|
-
mouseKind,
|
|
208
201
|
};
|