reslop 0.1.1 → 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 +13 -6
- package/README.md +11 -9
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +0 -1
- package/lib/cli.js +44 -43
- package/lib/clipboard.js +1 -1
- package/lib/deps.js +1440 -0
- package/lib/detect.js +4 -4
- package/lib/diff.js +31 -55
- package/lib/editor.js +1 -1
- package/lib/files.js +22 -3
- package/lib/git.js +360 -36
- package/lib/github.js +28 -34
- package/lib/highlight.js +126 -140
- package/lib/keys.js +29 -39
- package/lib/render.js +172 -129
- package/lib/review.js +22 -42
- package/lib/select.js +16 -18
- package/lib/session.js +97 -208
- package/lib/source.js +7 -3
- package/package.json +1 -1
package/lib/highlight.js
CHANGED
|
@@ -294,7 +294,7 @@ 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
|
};
|
|
@@ -424,8 +424,6 @@ const styleProperty = ({ out }) => {
|
|
|
424
424
|
return /\.$/.test(prev) ? 'property' : null;
|
|
425
425
|
};
|
|
426
426
|
|
|
427
|
-
const styleVariable = () => 'variable';
|
|
428
|
-
|
|
429
427
|
const IDENT_RULES = [
|
|
430
428
|
styleExpected,
|
|
431
429
|
styleKeyword,
|
|
@@ -434,7 +432,6 @@ const IDENT_RULES = [
|
|
|
434
432
|
styleCall,
|
|
435
433
|
styleAssign,
|
|
436
434
|
styleProperty,
|
|
437
|
-
styleVariable,
|
|
438
435
|
];
|
|
439
436
|
|
|
440
437
|
const identStyle = (ctx) => {
|
|
@@ -442,7 +439,7 @@ const identStyle = (ctx) => {
|
|
|
442
439
|
const style = rule(ctx);
|
|
443
440
|
if (style) return style;
|
|
444
441
|
}
|
|
445
|
-
return '
|
|
442
|
+
return 'variable';
|
|
446
443
|
};
|
|
447
444
|
|
|
448
445
|
const readString = (source, i) => {
|
|
@@ -519,150 +516,143 @@ const isRegexContext = (out) => {
|
|
|
519
516
|
return afterOperator || afterKeyword;
|
|
520
517
|
};
|
|
521
518
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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;
|
|
538
555
|
}
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
buf += source[j];
|
|
559
|
+
j += 1;
|
|
560
|
+
}
|
|
561
|
+
flush();
|
|
562
|
+
return { tokens: parts, end: j };
|
|
563
|
+
};
|
|
539
564
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
565
|
+
const highlightJsFamily = (source, ts = false) => {
|
|
566
|
+
const out = [];
|
|
567
|
+
let i = 0;
|
|
568
|
+
const n = source.length;
|
|
569
|
+
let expectName = null;
|
|
546
570
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
i = r.end;
|
|
551
|
-
continue;
|
|
552
|
-
}
|
|
571
|
+
while (i < n) {
|
|
572
|
+
const ch = source[i];
|
|
573
|
+
const next = source[i + 1];
|
|
553
574
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
575
|
+
if (ch === '/' && next === '/') {
|
|
576
|
+
const { text, end } = readUntilNl(source, i);
|
|
577
|
+
emit(out, 'comment', text);
|
|
578
|
+
i = end;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
560
581
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
582
|
+
if (ch === '/' && next === '*') {
|
|
583
|
+
const { text, end } = readBlockComment(source, i);
|
|
584
|
+
emit(out, 'comment', text);
|
|
585
|
+
i = end;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
567
588
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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
|
+
}
|
|
574
595
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
596
|
+
if (QUOTES.includes(ch)) {
|
|
597
|
+
const { text, end } = readString(source, i);
|
|
598
|
+
emit(out, 'string', text);
|
|
599
|
+
i = end;
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
583
602
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
emit(out, identStyle(ctx), word);
|
|
591
|
-
if (EXPECT_STYLE[expectName]) expectName = null;
|
|
592
|
-
else expectName = NEXT_EXPECT[word] ?? null;
|
|
593
|
-
i = end;
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
603
|
+
if (ch === '/' && isRegexContext(out)) {
|
|
604
|
+
const { text, end } = readRegex(source, i);
|
|
605
|
+
emit(out, 'regex', text);
|
|
606
|
+
i = end;
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
596
609
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
continue;
|
|
603
|
-
}
|
|
604
|
-
if (/[{}()[\];,.]/.test(ch)) {
|
|
605
|
-
emit(out, 'punct', ch);
|
|
606
|
-
i += 1;
|
|
607
|
-
continue;
|
|
608
|
-
}
|
|
609
|
-
emit(out, 'plain', ch);
|
|
610
|
-
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;
|
|
611
615
|
}
|
|
612
|
-
return out;
|
|
613
|
-
}
|
|
614
616
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
if (buf) {
|
|
623
|
-
emit(parts, 'template', buf);
|
|
624
|
-
buf = '';
|
|
625
|
-
}
|
|
626
|
-
};
|
|
627
|
-
while (j < n) {
|
|
628
|
-
if (source[j] === '\\') {
|
|
629
|
-
flush();
|
|
630
|
-
emit(parts, 'escape', source.slice(j, j + 2));
|
|
631
|
-
j += 2;
|
|
632
|
-
continue;
|
|
633
|
-
}
|
|
634
|
-
if (source[j] === '`') {
|
|
635
|
-
flush();
|
|
636
|
-
emit(parts, 'template', '`');
|
|
637
|
-
j += 1;
|
|
638
|
-
break;
|
|
639
|
-
}
|
|
640
|
-
if (source[j] === '$' && source[j + 1] === '{') {
|
|
641
|
-
flush();
|
|
642
|
-
emit(parts, 'interpolation', '${');
|
|
643
|
-
j += 2;
|
|
644
|
-
const interp = readTemplateInterp(source, j);
|
|
645
|
-
const inner = this.highlightJsFamily(interp.expr, false);
|
|
646
|
-
for (const t of inner) parts.push(t);
|
|
647
|
-
j = interp.end;
|
|
648
|
-
if (source[j] === '}') {
|
|
649
|
-
emit(parts, 'interpolation', '}');
|
|
650
|
-
j += 1;
|
|
651
|
-
}
|
|
652
|
-
continue;
|
|
653
|
-
}
|
|
654
|
-
buf += source[j];
|
|
655
|
-
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;
|
|
656
624
|
}
|
|
657
|
-
flush();
|
|
658
|
-
return { tokens: parts, end: j };
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
625
|
|
|
662
|
-
|
|
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
|
+
}
|
|
663
638
|
|
|
664
|
-
|
|
665
|
-
|
|
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
|
+
};
|
|
666
656
|
|
|
667
657
|
const highlightJson = (source) => {
|
|
668
658
|
const out = [];
|
|
@@ -1158,9 +1148,6 @@ const HIGHLIGHTERS = {
|
|
|
1158
1148
|
html: highlightHtml,
|
|
1159
1149
|
csv: highlightCsv,
|
|
1160
1150
|
bash: highlightBash,
|
|
1161
|
-
sh: highlightBash,
|
|
1162
|
-
shell: highlightBash,
|
|
1163
|
-
zsh: highlightBash,
|
|
1164
1151
|
log: highlightLog,
|
|
1165
1152
|
dot: highlightDot,
|
|
1166
1153
|
txt: highlightTxt,
|
|
@@ -1224,8 +1211,7 @@ const overlayTokens = (tokens, spans) => {
|
|
|
1224
1211
|
};
|
|
1225
1212
|
|
|
1226
1213
|
module.exports = {
|
|
1214
|
+
tokensText,
|
|
1227
1215
|
tokenize,
|
|
1228
1216
|
overlayTokens,
|
|
1229
|
-
tokensText,
|
|
1230
|
-
HIGHLIGHTERS,
|
|
1231
1217
|
};
|
package/lib/keys.js
CHANGED
|
@@ -1,40 +1,36 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const ACTIONS =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const FILES_DISABLED = ['
|
|
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'];
|
|
18
18
|
|
|
19
19
|
const SCROLL = {
|
|
20
20
|
up: 'scrollUp',
|
|
21
|
-
k: 'scrollUp',
|
|
22
21
|
down: 'scrollDown',
|
|
23
|
-
j: 'scrollDown',
|
|
24
|
-
h: 'help',
|
|
25
|
-
'?': 'help',
|
|
26
22
|
enter: 'open',
|
|
27
23
|
backspace: 'removeTodo',
|
|
28
24
|
delete: 'removeTodo',
|
|
29
25
|
};
|
|
30
26
|
|
|
31
|
-
const KEY_TO_ACTION =
|
|
27
|
+
const KEY_TO_ACTION = {};
|
|
32
28
|
|
|
33
|
-
for (const
|
|
34
|
-
for (const key of
|
|
29
|
+
for (const id of ACTION_IDS) {
|
|
30
|
+
for (const key of ACTIONS[id].keys) KEY_TO_ACTION[key] = id;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
|
-
for (const
|
|
33
|
+
for (const key of Object.keys(SCROLL)) KEY_TO_ACTION[key] = SCROLL[key];
|
|
38
34
|
|
|
39
35
|
const CSI_KEYS = {
|
|
40
36
|
A: 'up',
|
|
@@ -51,6 +47,15 @@ const CSI_TILDE = {
|
|
|
51
47
|
4: 'end',
|
|
52
48
|
};
|
|
53
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
|
+
};
|
|
58
|
+
|
|
54
59
|
const MOUSE_WHEEL = {
|
|
55
60
|
64: 'wheelUp',
|
|
56
61
|
65: 'wheelDown',
|
|
@@ -64,11 +69,6 @@ const mouseKindFromButton = (button, press) => {
|
|
|
64
69
|
return 'press';
|
|
65
70
|
};
|
|
66
71
|
|
|
67
|
-
const mouseKind = (event) => {
|
|
68
|
-
if (event.kind) return event.kind;
|
|
69
|
-
return mouseKindFromButton(event.button, event.press);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
72
|
const parseMouse = (body, flag) => {
|
|
73
73
|
const parts = body.split(';');
|
|
74
74
|
if (parts.length < 3) return null;
|
|
@@ -123,15 +123,6 @@ const parseEsc = (text, start) => {
|
|
|
123
123
|
return { event: { type: 'key', key: 'escape' }, end: start + 1 };
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
-
const LITERAL_KEY = {
|
|
127
|
-
'\x7f': 'backspace',
|
|
128
|
-
'\x08': 'backspace',
|
|
129
|
-
'\t': 'tab',
|
|
130
|
-
'\x03': 'ctrl-c',
|
|
131
|
-
'\r': 'enter',
|
|
132
|
-
'\n': 'enter',
|
|
133
|
-
};
|
|
134
|
-
|
|
135
126
|
const decodeChunk = (text, carry = '') => {
|
|
136
127
|
const source = carry + text;
|
|
137
128
|
const events = [];
|
|
@@ -199,13 +190,12 @@ const hitAction = (hits, x) => {
|
|
|
199
190
|
|
|
200
191
|
module.exports = {
|
|
201
192
|
ACTIONS,
|
|
193
|
+
ACTION_IDS,
|
|
202
194
|
FILES_DISABLED,
|
|
203
|
-
KEY_TO_ACTION,
|
|
204
195
|
decodeChunk,
|
|
205
196
|
actionFromKey,
|
|
206
197
|
actionHot,
|
|
207
198
|
actionLetter,
|
|
208
199
|
buttonWord,
|
|
209
200
|
hitAction,
|
|
210
|
-
mouseKind,
|
|
211
201
|
};
|