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/detect.js
CHANGED
|
@@ -46,9 +46,9 @@ const PROSE_BASENAMES = [
|
|
|
46
46
|
|
|
47
47
|
const fileExt = (filePath) => {
|
|
48
48
|
const base = path.basename(filePath || '');
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
return base.slice(
|
|
49
|
+
const dot = base.lastIndexOf('.');
|
|
50
|
+
if (dot <= 0) return '';
|
|
51
|
+
return base.slice(dot + 1).toLowerCase();
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
const mapLang = (name) => {
|
|
@@ -81,4 +81,4 @@ const detectLang = (filePath) => {
|
|
|
81
81
|
return 'dot';
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
module.exports = {
|
|
84
|
+
module.exports = { mapLang, detectLang };
|
package/lib/diff.js
CHANGED
|
@@ -15,12 +15,18 @@ const LINE_MARK = {
|
|
|
15
15
|
add: '+',
|
|
16
16
|
del: '-',
|
|
17
17
|
ctx: ' ',
|
|
18
|
+
warn: ' ',
|
|
19
|
+
note: ' ',
|
|
20
|
+
noteSep: ' ',
|
|
18
21
|
};
|
|
22
|
+
const CTX_TYPES = ['ctx', 'warn', 'note', 'noteSep'];
|
|
19
23
|
const LINE_TYPE = {
|
|
20
24
|
'+': 'add',
|
|
21
25
|
'-': 'del',
|
|
22
26
|
' ': 'ctx',
|
|
23
27
|
};
|
|
28
|
+
|
|
29
|
+
const isCtxType = (type) => CTX_TYPES.includes(type);
|
|
24
30
|
const INDEX_SIDE = {
|
|
25
31
|
staged: 'new',
|
|
26
32
|
unstaged: 'old',
|
|
@@ -236,27 +242,23 @@ const diffTokenMiddle = (midA, midB) => {
|
|
|
236
242
|
return lcsSpans(midA, midB);
|
|
237
243
|
};
|
|
238
244
|
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
const newParts = [];
|
|
245
|
+
const joinAffix = (prefix, mid, suffix) => {
|
|
246
|
+
const parts = [];
|
|
242
247
|
if (prefix.length) {
|
|
243
|
-
|
|
244
|
-
oldParts.push({ text, changed: false });
|
|
245
|
-
newParts.push({ text, changed: false });
|
|
248
|
+
parts.push({ text: prefix.join(''), changed: false });
|
|
246
249
|
}
|
|
247
|
-
for (const span of mid
|
|
248
|
-
for (const span of mid.newSpans) newParts.push(span);
|
|
250
|
+
for (const span of mid) parts.push(span);
|
|
249
251
|
if (suffix.length) {
|
|
250
|
-
|
|
251
|
-
oldParts.push({ text, changed: false });
|
|
252
|
-
newParts.push({ text, changed: false });
|
|
252
|
+
parts.push({ text: suffix.join(''), changed: false });
|
|
253
253
|
}
|
|
254
|
-
return
|
|
255
|
-
oldSpans: collapseSpans(oldParts),
|
|
256
|
-
newSpans: collapseSpans(newParts),
|
|
257
|
-
};
|
|
254
|
+
return collapseSpans(parts);
|
|
258
255
|
};
|
|
259
256
|
|
|
257
|
+
const joinTrimmedSpans = (prefix, mid, suffix) => ({
|
|
258
|
+
oldSpans: joinAffix(prefix, mid.oldSpans, suffix),
|
|
259
|
+
newSpans: joinAffix(prefix, mid.newSpans, suffix),
|
|
260
|
+
});
|
|
261
|
+
|
|
260
262
|
const diffTokens = (a, b) => {
|
|
261
263
|
if (a.length === 0 && b.length === 0) {
|
|
262
264
|
return { oldSpans: [], newSpans: [] };
|
|
@@ -331,18 +333,6 @@ const spansFromWordOps = (ops) => {
|
|
|
331
333
|
};
|
|
332
334
|
};
|
|
333
335
|
|
|
334
|
-
const joinAffix = (prefix, mid, suffix) => {
|
|
335
|
-
const parts = [];
|
|
336
|
-
if (prefix.length) {
|
|
337
|
-
parts.push({ text: prefix.join(''), changed: false });
|
|
338
|
-
}
|
|
339
|
-
for (const span of mid) parts.push(span);
|
|
340
|
-
if (suffix.length) {
|
|
341
|
-
parts.push({ text: suffix.join(''), changed: false });
|
|
342
|
-
}
|
|
343
|
-
return collapseSpans(parts);
|
|
344
|
-
};
|
|
345
|
-
|
|
346
336
|
const diffChars = (oldText, newText) => {
|
|
347
337
|
const a = splitPieces(oldText);
|
|
348
338
|
const b = splitPieces(newText);
|
|
@@ -350,18 +340,7 @@ const diffChars = (oldText, newText) => {
|
|
|
350
340
|
return { oldSpans: [], newSpans: [] };
|
|
351
341
|
}
|
|
352
342
|
if (a.length === 0 || b.length === 0) return wholeChanged(a, b);
|
|
353
|
-
|
|
354
|
-
while (lo < a.length && lo < b.length && a[lo] === b[lo]) lo += 1;
|
|
355
|
-
let hiA = a.length;
|
|
356
|
-
let hiB = b.length;
|
|
357
|
-
while (hiA > lo && hiB > lo && a[hiA - 1] === b[hiB - 1]) {
|
|
358
|
-
hiA -= 1;
|
|
359
|
-
hiB -= 1;
|
|
360
|
-
}
|
|
361
|
-
const prefix = a.slice(0, lo);
|
|
362
|
-
const suffix = a.slice(hiA);
|
|
363
|
-
const midA = a.slice(lo, hiA);
|
|
364
|
-
const midB = b.slice(lo, hiB);
|
|
343
|
+
const { prefix, suffix, midA, midB } = trimSharedEnds(a, b);
|
|
365
344
|
let mid;
|
|
366
345
|
if (midA.length === 0 && midB.length === 0) {
|
|
367
346
|
mid = { oldSpans: [], newSpans: [] };
|
|
@@ -433,7 +412,7 @@ const attachInline = (lines) => {
|
|
|
433
412
|
);
|
|
434
413
|
applyInlineSpans(dels, adds, delToAdd);
|
|
435
414
|
for (const line of lines) {
|
|
436
|
-
if (line.type
|
|
415
|
+
if (isCtxType(line.type)) {
|
|
437
416
|
line.spans = [{ text: line.text, changed: false }];
|
|
438
417
|
}
|
|
439
418
|
}
|
|
@@ -501,13 +480,13 @@ const mapHunkBlocks = (lines, onCtx, onChange) => {
|
|
|
501
480
|
const out = [];
|
|
502
481
|
let i = 0;
|
|
503
482
|
while (i < lines.length) {
|
|
504
|
-
if (lines[i].type
|
|
483
|
+
if (isCtxType(lines[i].type)) {
|
|
505
484
|
out.push(onCtx(lines[i]));
|
|
506
485
|
i += 1;
|
|
507
486
|
continue;
|
|
508
487
|
}
|
|
509
488
|
const start = i;
|
|
510
|
-
while (i < lines.length && lines[i].type
|
|
489
|
+
while (i < lines.length && !isCtxType(lines[i].type)) i += 1;
|
|
511
490
|
const block = lines.slice(start, i);
|
|
512
491
|
const { dels, adds } = changeSides(block);
|
|
513
492
|
const delToAdd = pairIndices(
|
|
@@ -698,7 +677,7 @@ const splitHunk = (hunk) => {
|
|
|
698
677
|
let current = null;
|
|
699
678
|
let blockId = -1;
|
|
700
679
|
const lines = hunk.lines.map((line) => {
|
|
701
|
-
if (line.type
|
|
680
|
+
if (isCtxType(line.type)) {
|
|
702
681
|
current = null;
|
|
703
682
|
return { ...line, blockId: null };
|
|
704
683
|
}
|
|
@@ -722,7 +701,7 @@ const otherContext = (contextSide, blockId) => {
|
|
|
722
701
|
const flattenBlock = (hunk, blockId, contextSide) => {
|
|
723
702
|
const out = [];
|
|
724
703
|
for (const line of hunk.lines) {
|
|
725
|
-
if (line.blockId === blockId || line.type
|
|
704
|
+
if (line.blockId === blockId || isCtxType(line.type)) {
|
|
726
705
|
out.push(line);
|
|
727
706
|
continue;
|
|
728
707
|
}
|
|
@@ -742,8 +721,8 @@ const countSides = (lines) => {
|
|
|
742
721
|
let oldCount = 0;
|
|
743
722
|
let newCount = 0;
|
|
744
723
|
for (const line of lines) {
|
|
745
|
-
if (line.type
|
|
746
|
-
if (line.type
|
|
724
|
+
if (isCtxType(line.type) || line.type === 'del') oldCount += 1;
|
|
725
|
+
if (isCtxType(line.type) || line.type === 'add') newCount += 1;
|
|
747
726
|
}
|
|
748
727
|
return { oldCount, newCount };
|
|
749
728
|
};
|
|
@@ -794,9 +773,10 @@ const windowAroundBlock = (lines, blockId, radius) => {
|
|
|
794
773
|
return lines.slice(from, to);
|
|
795
774
|
};
|
|
796
775
|
|
|
797
|
-
const displayLines = (hunk, blockId, layout = 'unified') => {
|
|
776
|
+
const displayLines = (hunk, blockId, layout = 'unified', radius) => {
|
|
798
777
|
const flat = flattenBlock(hunk, blockId, 'new');
|
|
799
|
-
const
|
|
778
|
+
const around = radius ?? DISPLAY_CONTEXT;
|
|
779
|
+
const windowed = windowAroundBlock(flat, blockId, around);
|
|
800
780
|
const lines = windowed.map((line) => ({ ...line }));
|
|
801
781
|
const painted = attachInline(lines);
|
|
802
782
|
const align = LAYOUT_ALIGN[layout];
|
|
@@ -876,7 +856,7 @@ const refreshIndexPatches = (items, item) => {
|
|
|
876
856
|
siblings.push(other);
|
|
877
857
|
}
|
|
878
858
|
}
|
|
879
|
-
const sides =
|
|
859
|
+
const sides = {};
|
|
880
860
|
for (const other of siblings) {
|
|
881
861
|
sides[other.blockId] = INDEX_SIDE[other.origin] ?? 'old';
|
|
882
862
|
}
|
|
@@ -886,22 +866,18 @@ const refreshIndexPatches = (items, item) => {
|
|
|
886
866
|
};
|
|
887
867
|
|
|
888
868
|
module.exports = {
|
|
889
|
-
LCS_CELL_LIMIT,
|
|
890
869
|
DISPLAY_CONTEXT,
|
|
891
|
-
|
|
870
|
+
isCtxType,
|
|
892
871
|
diffChars,
|
|
893
|
-
similarity,
|
|
894
|
-
pairScore,
|
|
895
872
|
pairIndices,
|
|
896
873
|
attachInline,
|
|
897
874
|
parseDiff,
|
|
898
875
|
splitHunk,
|
|
899
876
|
flattenBlock,
|
|
877
|
+
countSides,
|
|
900
878
|
formatPatch,
|
|
901
879
|
displayLines,
|
|
902
|
-
alignSplit,
|
|
903
880
|
synthesizeNewFile,
|
|
904
881
|
itemsFromFiles,
|
|
905
882
|
refreshIndexPatches,
|
|
906
|
-
countSides,
|
|
907
883
|
};
|
package/lib/editor.js
CHANGED
package/lib/files.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const REVIEW_DIR = '.review';
|
|
3
4
|
const ORIGIN_ORDER = ['staged', 'unstaged', 'untracked', 'commit', 'pr'];
|
|
4
5
|
|
|
6
|
+
const normalizePathSpec = (spec) =>
|
|
7
|
+
`${spec ?? ''}`.replaceAll('\\', '/').replace(/\/+$/, '');
|
|
8
|
+
|
|
9
|
+
const isPathInScope = (rel, paths) => {
|
|
10
|
+
if (!paths.length) return true;
|
|
11
|
+
for (const spec of paths) {
|
|
12
|
+
const norm = normalizePathSpec(spec);
|
|
13
|
+
if (!norm || norm === '.') return true;
|
|
14
|
+
if (rel === norm || rel.startsWith(`${norm}/`)) return true;
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
|
|
5
19
|
const itemPath = (item) => {
|
|
6
20
|
if (!item || !item.file) return '';
|
|
7
21
|
return item.file.newPath || item.file.oldPath || '';
|
|
@@ -19,10 +33,9 @@ const fileStatus = (origins) => {
|
|
|
19
33
|
return key;
|
|
20
34
|
};
|
|
21
35
|
|
|
22
|
-
const fileEntries = (items
|
|
36
|
+
const fileEntries = (items) => {
|
|
23
37
|
const groups = new Map();
|
|
24
38
|
for (let i = 0; i < items.length; i++) {
|
|
25
|
-
if (!kept.has(i)) continue;
|
|
26
39
|
const item = items[i];
|
|
27
40
|
const rel = itemPath(item);
|
|
28
41
|
let group = groups.get(rel);
|
|
@@ -44,4 +57,10 @@ const fileEntries = (items, kept) => {
|
|
|
44
57
|
return entries;
|
|
45
58
|
};
|
|
46
59
|
|
|
47
|
-
module.exports = {
|
|
60
|
+
module.exports = {
|
|
61
|
+
REVIEW_DIR,
|
|
62
|
+
isPathInScope,
|
|
63
|
+
itemPath,
|
|
64
|
+
fileStatus,
|
|
65
|
+
fileEntries,
|
|
66
|
+
};
|