reslop 0.2.4 → 0.2.6
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 -1
- package/LICENSE +1 -1
- package/README.md +12 -13
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -12
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +48 -18
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +332 -0
- package/lib/dashboard/npm.js +193 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +196 -404
- package/lib/deps.js +240 -399
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +138 -141
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +90 -206
- package/lib/editor.js +98 -55
- package/lib/files.js +86 -103
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +182 -344
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +141 -212
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +157 -132
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +16 -26
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +22 -35
- package/lib/highlight/txt.js +9 -22
- package/lib/highlight.js +17 -46
- package/lib/keys.js +62 -85
- package/lib/manifest.js +67 -130
- package/lib/npm-commands.js +119 -189
- package/lib/remote.js +141 -197
- package/lib/render/branches.js +66 -73
- package/lib/render/chrome.js +264 -323
- package/lib/render/commits.js +187 -500
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +245 -0
- package/lib/render/dash-table.js +290 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -228
- package/lib/render/files.js +45 -99
- package/lib/render/frame.js +129 -183
- package/lib/render/notes.js +144 -160
- package/lib/render/npm.js +234 -112
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +131 -170
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/tiles.js +260 -0
- package/lib/render/unit.js +15 -28
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -38
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -78
- package/lib/report-test.js +256 -141
- package/lib/report-tools.js +96 -161
- package/lib/review-merge.js +114 -152
- package/lib/review.js +115 -189
- package/lib/runs.js +225 -0
- package/lib/select.js +89 -75
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +82 -63
- package/lib/session/branches.js +193 -247
- package/lib/session/change-actions.js +171 -214
- package/lib/session/commit.js +280 -342
- package/lib/session/compose.js +559 -674
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +164 -157
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +85 -53
- package/lib/session/items.js +73 -104
- package/lib/session/lifecycle.js +403 -541
- package/lib/session/load.js +48 -68
- package/lib/session/navigation.js +96 -87
- package/lib/session/npm.js +409 -345
- package/lib/session/ops.js +196 -63
- package/lib/session/pointer.js +23 -15
- package/lib/session/progress.js +33 -21
- package/lib/session/review.js +33 -54
- package/lib/session/tasks.js +333 -0
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -136
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +52 -83
- package/lib/session/watch.js +208 -204
- package/lib/session.js +112 -237
- package/lib/update.js +45 -116
- package/lib/utilities.js +67 -89
- package/lib/wrap.js +33 -44
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
package/lib/diff/patch.js
CHANGED
|
@@ -3,14 +3,7 @@
|
|
|
3
3
|
const align = require('./align.js');
|
|
4
4
|
const { isCtxType } = align;
|
|
5
5
|
|
|
6
|
-
const LINE_MARK = {
|
|
7
|
-
add: '+',
|
|
8
|
-
del: '-',
|
|
9
|
-
ctx: ' ',
|
|
10
|
-
warn: ' ',
|
|
11
|
-
note: ' ',
|
|
12
|
-
noteSep: ' ',
|
|
13
|
-
};
|
|
6
|
+
const LINE_MARK = { add: '+', del: '-' };
|
|
14
7
|
|
|
15
8
|
const splitHunk = (hunk) => {
|
|
16
9
|
const { oldStart, oldCount, newStart, newCount, header } = hunk;
|
|
@@ -33,9 +26,8 @@ const splitHunk = (hunk) => {
|
|
|
33
26
|
return { hunk: nextHunk, blocks };
|
|
34
27
|
};
|
|
35
28
|
|
|
36
|
-
const
|
|
37
|
-
if (contextSide === '
|
|
38
|
-
if (contextSide === 'old') return 'old';
|
|
29
|
+
const sideOf = (contextSide, blockId) => {
|
|
30
|
+
if (typeof contextSide === 'string') return contextSide;
|
|
39
31
|
return contextSide[blockId] ?? 'old';
|
|
40
32
|
};
|
|
41
33
|
|
|
@@ -46,12 +38,8 @@ const flattenBlock = (hunk, blockId, contextSide) => {
|
|
|
46
38
|
out.push(line);
|
|
47
39
|
continue;
|
|
48
40
|
}
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
out.push({ type: 'ctx', text: line.text, noNl: line.noNl });
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (side === 'new' && line.type === 'add') {
|
|
41
|
+
const kept = sideOf(contextSide, line.blockId) === 'old' ? 'del' : 'add';
|
|
42
|
+
if (line.type === kept) {
|
|
55
43
|
out.push({ type: 'ctx', text: line.text, noNl: line.noNl });
|
|
56
44
|
}
|
|
57
45
|
}
|
|
@@ -62,8 +50,8 @@ const countSides = (lines) => {
|
|
|
62
50
|
let oldCount = 0;
|
|
63
51
|
let newCount = 0;
|
|
64
52
|
for (const line of lines) {
|
|
65
|
-
if (
|
|
66
|
-
if (
|
|
53
|
+
if (line.type !== 'add') oldCount += 1;
|
|
54
|
+
if (line.type !== 'del') newCount += 1;
|
|
67
55
|
}
|
|
68
56
|
return { oldCount, newCount };
|
|
69
57
|
};
|
|
@@ -71,24 +59,15 @@ const countSides = (lines) => {
|
|
|
71
59
|
const formatHunkHeader = (oldStart, oldCount, newStart, newCount) =>
|
|
72
60
|
`@@ -${oldStart},${oldCount} +${newStart},${newCount} @@`;
|
|
73
61
|
|
|
74
|
-
const formatBodyLine = (line) => {
|
|
75
|
-
const rows = [`${LINE_MARK[line.type] ?? ' '}${line.text}`];
|
|
76
|
-
if (line.noNl) rows.push('\');
|
|
77
|
-
return rows;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
62
|
const formatPatch = (file, hunk, blockId, contextSide) => {
|
|
81
63
|
const lines = flattenBlock(hunk, blockId, contextSide);
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
counts.oldCount,
|
|
86
|
-
hunk.newStart,
|
|
87
|
-
counts.newCount,
|
|
88
|
-
);
|
|
64
|
+
const { oldCount, newCount } = countSides(lines);
|
|
65
|
+
const { oldStart, newStart } = hunk;
|
|
66
|
+
const header = formatHunkHeader(oldStart, oldCount, newStart, newCount);
|
|
89
67
|
const parts = [...file.preamble, header];
|
|
90
68
|
for (const line of lines) {
|
|
91
|
-
|
|
69
|
+
parts.push(`${LINE_MARK[line.type] ?? ' '}${line.text}`);
|
|
70
|
+
if (line.noNl) parts.push('\');
|
|
92
71
|
}
|
|
93
72
|
return `${parts.join('\n')}\n`;
|
|
94
73
|
};
|
package/lib/diff/unit.js
CHANGED
|
@@ -5,16 +5,14 @@ const { attachInline } = align;
|
|
|
5
5
|
const files = require('../files.js');
|
|
6
6
|
const { listPath } = files;
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return lines;
|
|
12
|
-
};
|
|
8
|
+
const LCS_CELLS = 4000000;
|
|
9
|
+
|
|
10
|
+
const splitEditor = (text) => text.split('\n');
|
|
13
11
|
|
|
14
12
|
const splitFile = (text) => {
|
|
15
13
|
if (!text) return [];
|
|
16
|
-
const lines =
|
|
17
|
-
if (lines
|
|
14
|
+
const lines = text.split('\n');
|
|
15
|
+
if (lines[lines.length - 1] === '') lines.pop();
|
|
18
16
|
return lines;
|
|
19
17
|
};
|
|
20
18
|
|
|
@@ -28,53 +26,13 @@ const hunkKey = (item) => {
|
|
|
28
26
|
|
|
29
27
|
const sameHunk = (left, right) => {
|
|
30
28
|
if (!left || !right) return false;
|
|
31
|
-
if (left.hunk &&
|
|
29
|
+
if (left.hunk && left.hunk === right.hunk) {
|
|
32
30
|
return listPath(left) === listPath(right);
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
if (!key) return false;
|
|
36
|
-
return key === hunkKey(right);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const emptyMarks = (last) => {
|
|
40
|
-
const size = last + 1;
|
|
41
|
-
const dels = new Array(size);
|
|
42
|
-
const adds = new Array(size);
|
|
43
|
-
for (let i = 0; i < size; i++) {
|
|
44
|
-
dels[i] = [];
|
|
45
|
-
adds[i] = null;
|
|
46
|
-
}
|
|
47
|
-
return { dels, adds };
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const clipAt = (n, last) => Math.min(Math.max(1, n), last);
|
|
51
|
-
|
|
52
|
-
const applyHunk = (marks, item) => {
|
|
53
|
-
const hunk = item.hunk;
|
|
54
|
-
if (!hunk || !hunk.lines) return;
|
|
55
|
-
const last = marks.dels.length - 1;
|
|
56
|
-
let newLine = hunk.newStart > 0 ? hunk.newStart : 1;
|
|
57
|
-
for (const line of hunk.lines) {
|
|
58
|
-
const extra = {
|
|
59
|
-
text: line.text ?? '',
|
|
60
|
-
item,
|
|
61
|
-
blockId: line.blockId,
|
|
62
|
-
origin: item.origin,
|
|
63
|
-
};
|
|
64
|
-
if (line.type === 'del') {
|
|
65
|
-
marks.dels[clipAt(newLine, last)].push(extra);
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (line.type === 'add') {
|
|
69
|
-
marks.adds[clipAt(newLine, last)] = extra;
|
|
70
|
-
newLine += 1;
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
newLine += 1;
|
|
74
|
-
}
|
|
32
|
+
return hunkKey(left) === hunkKey(right);
|
|
75
33
|
};
|
|
76
34
|
|
|
77
|
-
const tagged = (type, text, extra
|
|
35
|
+
const tagged = (type, text, extra) => ({
|
|
78
36
|
type,
|
|
79
37
|
text,
|
|
80
38
|
noNl: false,
|
|
@@ -83,20 +41,35 @@ const tagged = (type, text, extra = {}) => ({
|
|
|
83
41
|
item: extra.item ?? null,
|
|
84
42
|
});
|
|
85
43
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
44
|
+
const NO_EXTRA = {};
|
|
45
|
+
|
|
46
|
+
const clipAt = (n, last) => Math.min(Math.max(1, n), last);
|
|
47
|
+
|
|
48
|
+
const markHunk = (marks, item) => {
|
|
49
|
+
if (!item.hunk) return;
|
|
50
|
+
const last = marks.dels.length - 1;
|
|
51
|
+
let newLine = item.hunk.newStart > 0 ? item.hunk.newStart : 1;
|
|
52
|
+
for (const line of item.hunk.lines) {
|
|
53
|
+
const { type, text, blockId } = line;
|
|
54
|
+
const mark = { text, item, blockId, origin: item.origin };
|
|
55
|
+
if (type === 'del') {
|
|
56
|
+
marks.dels[clipAt(newLine, last)].push(mark);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (type === 'add') marks.adds[clipAt(newLine, last)] = mark;
|
|
60
|
+
newLine += 1;
|
|
90
61
|
}
|
|
91
|
-
return out;
|
|
92
62
|
};
|
|
93
63
|
|
|
64
|
+
const itemsForPath = (items, rel) =>
|
|
65
|
+
items.filter((item) => listPath(item) === rel);
|
|
66
|
+
|
|
94
67
|
const rowsFromAdds = (items) => {
|
|
95
68
|
const rows = [];
|
|
96
69
|
for (const item of items) {
|
|
97
|
-
|
|
98
|
-
for (const line of lines) {
|
|
99
|
-
if (line.type === 'add') rows.push(line.text
|
|
70
|
+
if (!item.hunk) continue;
|
|
71
|
+
for (const line of item.hunk.lines) {
|
|
72
|
+
if (line.type === 'add') rows.push(line.text);
|
|
100
73
|
}
|
|
101
74
|
}
|
|
102
75
|
return rows;
|
|
@@ -105,75 +78,57 @@ const rowsFromAdds = (items) => {
|
|
|
105
78
|
const unitLines = (text, items) => {
|
|
106
79
|
let rows = splitFile(text);
|
|
107
80
|
if (!rows.length) rows = rowsFromAdds(items);
|
|
108
|
-
const
|
|
109
|
-
|
|
81
|
+
const size = rows.length + 2;
|
|
82
|
+
const marks = {
|
|
83
|
+
dels: Array.from({ length: size }, () => []),
|
|
84
|
+
adds: new Array(size).fill(null),
|
|
85
|
+
};
|
|
86
|
+
for (const item of items) markHunk(marks, item);
|
|
110
87
|
const out = [];
|
|
111
88
|
for (let i = 0; i < rows.length; i++) {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
const add = marks.adds[n];
|
|
89
|
+
for (const del of marks.dels[i + 1]) out.push(tagged('del', del.text, del));
|
|
90
|
+
const add = marks.adds[i + 1];
|
|
115
91
|
if (add) out.push(tagged('add', rows[i], add));
|
|
116
|
-
else out.push(tagged('ctx', rows[i],
|
|
92
|
+
else out.push(tagged('ctx', rows[i], NO_EXTRA));
|
|
117
93
|
}
|
|
118
94
|
for (const del of marks.dels[rows.length + 1]) {
|
|
119
95
|
out.push(tagged('del', del.text, del));
|
|
120
96
|
}
|
|
121
|
-
if (!out.length) out.push(tagged('ctx', '',
|
|
97
|
+
if (!out.length) out.push(tagged('ctx', '', NO_EXTRA));
|
|
122
98
|
return attachInline(out);
|
|
123
99
|
};
|
|
124
100
|
|
|
125
|
-
const sameBlock = (line, item) =>
|
|
126
|
-
|
|
127
|
-
if (line.item !== item) return false;
|
|
128
|
-
return line.blockId === item.blockId;
|
|
129
|
-
};
|
|
101
|
+
const sameBlock = (line, item) =>
|
|
102
|
+
line.item === item && line.blockId === item.blockId;
|
|
130
103
|
|
|
131
|
-
const
|
|
132
|
-
let start =
|
|
104
|
+
const changedLineRange = (lines, item, belongs) => {
|
|
105
|
+
let start = -1;
|
|
133
106
|
let end = 0;
|
|
134
|
-
|
|
135
|
-
if (!item) return { start, end };
|
|
107
|
+
if (!item) return { start: 0, end };
|
|
136
108
|
for (let i = 0; i < lines.length; i++) {
|
|
137
109
|
const line = lines[i];
|
|
138
|
-
if (!
|
|
139
|
-
if (
|
|
140
|
-
if (!found) {
|
|
141
|
-
start = i;
|
|
142
|
-
found = true;
|
|
143
|
-
}
|
|
110
|
+
if (line.type === 'ctx' || !belongs(line, item)) continue;
|
|
111
|
+
if (start < 0) start = i;
|
|
144
112
|
end = i;
|
|
145
113
|
}
|
|
146
|
-
return { start, end };
|
|
114
|
+
return { start: Math.max(start, 0), end };
|
|
147
115
|
};
|
|
148
116
|
|
|
117
|
+
const blockLineRange = (lines, item) =>
|
|
118
|
+
changedLineRange(lines, item, sameBlock);
|
|
119
|
+
|
|
149
120
|
const blockLineIndex = (lines, item) => blockLineRange(lines, item).start;
|
|
150
121
|
|
|
151
|
-
const hunkLineRange = (lines, item) =>
|
|
152
|
-
|
|
153
|
-
let end = 0;
|
|
154
|
-
let found = false;
|
|
155
|
-
if (!item) return { start, end };
|
|
156
|
-
for (let i = 0; i < lines.length; i++) {
|
|
157
|
-
const line = lines[i];
|
|
158
|
-
if (!sameHunk(line.item, item)) continue;
|
|
159
|
-
if (line.type === 'ctx') continue;
|
|
160
|
-
if (!found) {
|
|
161
|
-
start = i;
|
|
162
|
-
found = true;
|
|
163
|
-
}
|
|
164
|
-
end = i;
|
|
165
|
-
}
|
|
166
|
-
return { start, end };
|
|
167
|
-
};
|
|
122
|
+
const hunkLineRange = (lines, item) =>
|
|
123
|
+
changedLineRange(lines, item, (line) => sameHunk(line.item, item));
|
|
168
124
|
|
|
169
125
|
const fileOffset = (lines, at) => {
|
|
170
126
|
let offset = 0;
|
|
171
|
-
const target = Math.max(0, at);
|
|
172
127
|
for (let i = 0; i < lines.length; i++) {
|
|
173
128
|
const line = lines[i];
|
|
174
129
|
if (line.type === 'del') continue;
|
|
175
|
-
if (i >=
|
|
176
|
-
offset +=
|
|
130
|
+
if (i >= at) return offset;
|
|
131
|
+
offset += line.text.length + 1;
|
|
177
132
|
}
|
|
178
133
|
return offset;
|
|
179
134
|
};
|
|
@@ -190,37 +145,27 @@ const fileLineIndex = (lines, fileLine) => {
|
|
|
190
145
|
return last;
|
|
191
146
|
};
|
|
192
147
|
|
|
193
|
-
const lastEditableIndex = (lines) => {
|
|
194
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
195
|
-
if (lines[i].type !== 'del') return i;
|
|
196
|
-
}
|
|
197
|
-
return -1;
|
|
198
|
-
};
|
|
199
|
-
|
|
200
148
|
const attachEditSpans = (lines) => {
|
|
149
|
+
let lastAt = lines.length - 1;
|
|
150
|
+
while (lastAt >= 0 && lines[lastAt].type === 'del') lastAt -= 1;
|
|
201
151
|
let offset = 0;
|
|
202
|
-
const lastAt = lastEditableIndex(lines);
|
|
203
152
|
for (let i = 0; i < lines.length; i++) {
|
|
204
153
|
const line = lines[i];
|
|
205
154
|
if (line.type === 'del') continue;
|
|
206
|
-
const text = line.text ?? '';
|
|
207
|
-
const last = i === lastAt;
|
|
208
155
|
line.wrap = true;
|
|
209
156
|
line.editStart = offset;
|
|
210
|
-
line.editEnd = offset + text.length;
|
|
211
|
-
line.editLast =
|
|
212
|
-
offset =
|
|
157
|
+
line.editEnd = offset + line.text.length;
|
|
158
|
+
line.editLast = i === lastAt;
|
|
159
|
+
offset = line.editEnd + 1;
|
|
213
160
|
}
|
|
214
161
|
return lines;
|
|
215
162
|
};
|
|
216
163
|
|
|
217
|
-
const LCS_CELLS = 4000000;
|
|
218
|
-
|
|
219
164
|
const lcsTable = (prev, next) => {
|
|
220
165
|
const n = prev.length;
|
|
221
166
|
const m = next.length;
|
|
222
167
|
const dp = new Array(n + 1);
|
|
223
|
-
for (let i = 0; i <= n; i++) dp[i] = new
|
|
168
|
+
for (let i = 0; i <= n; i++) dp[i] = new Uint32Array(m + 1);
|
|
224
169
|
for (let i = n - 1; i >= 0; i--) {
|
|
225
170
|
for (let j = m - 1; j >= 0; j--) {
|
|
226
171
|
if (prev[i] === next[j]) dp[i][j] = dp[i + 1][j + 1] + 1;
|
|
@@ -232,44 +177,35 @@ const lcsTable = (prev, next) => {
|
|
|
232
177
|
|
|
233
178
|
const zipOps = (prev, next) => {
|
|
234
179
|
const n = Math.min(prev.length, next.length);
|
|
235
|
-
const ops =
|
|
236
|
-
let
|
|
237
|
-
for (let i =
|
|
238
|
-
for (let i = n; i < prev.length; i++) ops[at++] = { kind: 'del' };
|
|
180
|
+
const ops = [];
|
|
181
|
+
for (let i = 0; i < n; i++) ops.push({ kind: 'rep', text: next[i] });
|
|
182
|
+
for (let i = n; i < prev.length; i++) ops.push({ kind: 'del' });
|
|
239
183
|
for (let i = n; i < next.length; i++) {
|
|
240
|
-
ops
|
|
184
|
+
ops.push({ kind: 'ins', text: next[i] });
|
|
241
185
|
}
|
|
242
186
|
return ops;
|
|
243
187
|
};
|
|
244
188
|
|
|
245
|
-
const
|
|
246
|
-
const
|
|
247
|
-
|
|
189
|
+
const lcsOps = (prev, next) => {
|
|
190
|
+
const dp = lcsTable(prev, next);
|
|
191
|
+
const ops = [];
|
|
248
192
|
let i = 0;
|
|
249
193
|
let j = 0;
|
|
250
194
|
while (i < prev.length && j < next.length) {
|
|
251
195
|
if (prev[i] === next[j]) {
|
|
252
|
-
ops
|
|
196
|
+
ops.push({ kind: 'eq', text: next[j] });
|
|
253
197
|
i += 1;
|
|
254
198
|
j += 1;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (dp[i + 1][j] >= dp[i][j + 1]) {
|
|
258
|
-
ops[n++] = { kind: 'del' };
|
|
199
|
+
} else if (dp[i + 1][j] >= dp[i][j + 1]) {
|
|
200
|
+
ops.push({ kind: 'del' });
|
|
259
201
|
i += 1;
|
|
260
|
-
|
|
202
|
+
} else {
|
|
203
|
+
ops.push({ kind: 'ins', text: next[j] });
|
|
204
|
+
j += 1;
|
|
261
205
|
}
|
|
262
|
-
ops[n++] = { kind: 'ins', text: next[j] };
|
|
263
|
-
j += 1;
|
|
264
|
-
}
|
|
265
|
-
while (i < prev.length) {
|
|
266
|
-
ops[n++] = { kind: 'del' };
|
|
267
|
-
i += 1;
|
|
268
|
-
}
|
|
269
|
-
while (j < next.length) {
|
|
270
|
-
ops[n++] = { kind: 'ins', text: next[j] };
|
|
271
|
-
j += 1;
|
|
272
206
|
}
|
|
207
|
+
for (; i < prev.length; i++) ops.push({ kind: 'del' });
|
|
208
|
+
for (; j < next.length; j++) ops.push({ kind: 'ins', text: next[j] });
|
|
273
209
|
return ops;
|
|
274
210
|
};
|
|
275
211
|
|
|
@@ -278,13 +214,10 @@ const collapseRep = (ops) => {
|
|
|
278
214
|
for (let i = 0; i < ops.length; i++) {
|
|
279
215
|
const op = ops[i];
|
|
280
216
|
const next = ops[i + 1];
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
if (op.kind === 'ins' && next && next.kind === 'del') {
|
|
287
|
-
out.push({ kind: 'rep', text: op.text });
|
|
217
|
+
const delIns = op.kind === 'del' && next?.kind === 'ins';
|
|
218
|
+
const insDel = op.kind === 'ins' && next?.kind === 'del';
|
|
219
|
+
if (delIns || insDel) {
|
|
220
|
+
out.push({ kind: 'rep', text: delIns ? next.text : op.text });
|
|
288
221
|
i += 1;
|
|
289
222
|
continue;
|
|
290
223
|
}
|
|
@@ -296,91 +229,44 @@ const collapseRep = (ops) => {
|
|
|
296
229
|
const lineOps = (prev, next) => {
|
|
297
230
|
if (prev.length === next.length) return zipOps(prev, next);
|
|
298
231
|
if (prev.length * next.length > LCS_CELLS) return zipOps(prev, next);
|
|
299
|
-
return collapseRep(
|
|
232
|
+
return collapseRep(lcsOps(prev, next));
|
|
300
233
|
};
|
|
301
234
|
|
|
302
|
-
const copyRow = (row, text) => ({
|
|
303
|
-
type: row.type,
|
|
304
|
-
text,
|
|
305
|
-
noNl: row.noNl === true,
|
|
306
|
-
blockId: row.blockId ?? null,
|
|
307
|
-
origin: row.origin ?? '',
|
|
308
|
-
item: row.item ?? null,
|
|
309
|
-
});
|
|
310
|
-
|
|
311
235
|
const pushDels = (out, base, at) => {
|
|
312
236
|
let i = at;
|
|
313
237
|
while (i < base.length && base[i].type === 'del') {
|
|
314
|
-
out.push(
|
|
238
|
+
out.push(tagged('del', base[i].text, base[i]));
|
|
315
239
|
i += 1;
|
|
316
240
|
}
|
|
317
241
|
return i;
|
|
318
242
|
};
|
|
319
243
|
|
|
320
|
-
const mergeEditRows = (
|
|
321
|
-
const
|
|
322
|
-
const texts = nextTexts && nextTexts.length ? nextTexts : [''];
|
|
244
|
+
const mergeEditRows = (base, nextTexts) => {
|
|
245
|
+
const texts = nextTexts.length ? nextTexts : [''];
|
|
323
246
|
const prev = [];
|
|
324
|
-
for (const row of base)
|
|
325
|
-
if (row.type === 'del') continue;
|
|
326
|
-
prev.push(row.text ?? '');
|
|
327
|
-
}
|
|
328
|
-
const ops = lineOps(prev, texts);
|
|
247
|
+
for (const row of base) if (row.type !== 'del') prev.push(row.text);
|
|
329
248
|
const out = [];
|
|
330
249
|
let at = 0;
|
|
331
|
-
for (const op of
|
|
250
|
+
for (const op of lineOps(prev, texts)) {
|
|
332
251
|
at = pushDels(out, base, at);
|
|
333
252
|
if (op.kind === 'ins') {
|
|
334
|
-
out.push(tagged('ctx', op.text,
|
|
253
|
+
out.push(tagged('ctx', op.text, NO_EXTRA));
|
|
335
254
|
continue;
|
|
336
255
|
}
|
|
337
256
|
if (at >= base.length) continue;
|
|
338
|
-
if (op.kind
|
|
339
|
-
at += 1;
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
out.push(copyRow(base[at], op.text));
|
|
257
|
+
if (op.kind !== 'del') out.push(tagged(base[at].type, op.text, base[at]));
|
|
343
258
|
at += 1;
|
|
344
259
|
}
|
|
345
260
|
pushDels(out, base, at);
|
|
346
|
-
if (!out.length) out.push(tagged('ctx', '',
|
|
261
|
+
if (!out.length) out.push(tagged('ctx', '', NO_EXTRA));
|
|
347
262
|
return attachEditSpans(attachInline(out));
|
|
348
263
|
};
|
|
349
264
|
|
|
350
|
-
const fileLines = (text) => {
|
|
351
|
-
const rows = splitFile(text);
|
|
352
|
-
if (!rows.length) rows.push('');
|
|
353
|
-
const { length } = rows;
|
|
354
|
-
const out = new Array(length);
|
|
355
|
-
let offset = 0;
|
|
356
|
-
for (let i = 0; i < length; i++) {
|
|
357
|
-
const row = rows[i];
|
|
358
|
-
const start = offset;
|
|
359
|
-
const end = start + row.length;
|
|
360
|
-
const last = i === length - 1;
|
|
361
|
-
out[i] = {
|
|
362
|
-
type: 'ctx',
|
|
363
|
-
text: row,
|
|
364
|
-
noNl: false,
|
|
365
|
-
wrap: true,
|
|
366
|
-
editStart: start,
|
|
367
|
-
editEnd: end,
|
|
368
|
-
editLast: last,
|
|
369
|
-
blockId: null,
|
|
370
|
-
origin: '',
|
|
371
|
-
item: null,
|
|
372
|
-
};
|
|
373
|
-
offset = last ? end : end + 1;
|
|
374
|
-
}
|
|
375
|
-
return out;
|
|
376
|
-
};
|
|
377
|
-
|
|
378
265
|
module.exports = {
|
|
379
266
|
splitFile,
|
|
380
267
|
splitEditor,
|
|
381
268
|
itemsForPath,
|
|
382
269
|
unitLines,
|
|
383
|
-
sameBlock,
|
|
384
270
|
sameHunk,
|
|
385
271
|
hunkKey,
|
|
386
272
|
blockLineRange,
|
|
@@ -388,7 +274,5 @@ module.exports = {
|
|
|
388
274
|
blockLineIndex,
|
|
389
275
|
fileOffset,
|
|
390
276
|
fileLineIndex,
|
|
391
|
-
attachEditSpans,
|
|
392
277
|
mergeEditRows,
|
|
393
|
-
fileLines,
|
|
394
278
|
};
|