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/render/frame.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
4
|
const select = require('../select.js');
|
|
5
|
-
const { overlayRows } = select;
|
|
6
5
|
const primitives = require('./primitives.js');
|
|
7
6
|
const chrome = require('./chrome.js');
|
|
8
7
|
const files = require('./files.js');
|
|
@@ -12,242 +11,189 @@ const notes = require('./notes.js');
|
|
|
12
11
|
const npm = require('./npm.js');
|
|
13
12
|
const diff = require('./diff.js');
|
|
14
13
|
const unit = require('./unit.js');
|
|
14
|
+
const dashboard = require('./dashboard.js');
|
|
15
15
|
|
|
16
16
|
const { RESET } = ansi;
|
|
17
|
-
const {
|
|
17
|
+
const { overlayRows, markEditorSelection } = select;
|
|
18
|
+
const { isListPane, isTaskView, paintBodyFill, paneResult } = primitives;
|
|
18
19
|
const { paintHeader, paintFooter, footerHits, paintStatusLine } = chrome;
|
|
19
|
-
const {
|
|
20
|
-
const { hiddenActions, dimFooterActions, extraFooterActions } = chrome;
|
|
20
|
+
const { footerLayout, statusBranchHit, statusChoiceHits } = chrome;
|
|
21
21
|
const { paintNotePanel, paintBodyTodo } = notes;
|
|
22
|
-
const { paintBodyFiles } = files;
|
|
23
|
-
const { paintBodyBranches } = branches;
|
|
24
|
-
const { paintBodyCommits } = commits;
|
|
25
|
-
const { paintBodyNpm } = npm;
|
|
26
22
|
const { paintBodyDiff } = diff;
|
|
27
|
-
const { paintBodyUnit } = unit;
|
|
28
23
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (view.item.origin === 'todo') return 'todo';
|
|
38
|
-
return 'diff';
|
|
24
|
+
const PANE_BODY = {
|
|
25
|
+
dashboard: dashboard.paintBodyDashboard,
|
|
26
|
+
files: files.paintBodyFiles,
|
|
27
|
+
branches: branches.paintBodyBranches,
|
|
28
|
+
commits: commits.paintBodyCommits,
|
|
29
|
+
npm: npm.paintBodyNpm,
|
|
30
|
+
unit: unit.paintBodyUnit,
|
|
31
|
+
tasks: paintBodyTodo,
|
|
39
32
|
};
|
|
40
33
|
|
|
41
34
|
const paintBodyEmpty = () => paneResult();
|
|
42
35
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
npm: paintBodyNpm,
|
|
48
|
-
empty: paintBodyEmpty,
|
|
49
|
-
todo: paintBodyTodo,
|
|
50
|
-
diff: paintBodyDiff,
|
|
51
|
-
unit: paintBodyUnit,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const paintFrameBody = (view, width, color, bodyH, headerLines) => {
|
|
55
|
-
const paint = BODY_PAINT[bodyKind(view)];
|
|
56
|
-
return paint(view, width, color, bodyH, headerLines);
|
|
36
|
+
const bodyPainter = (view) => {
|
|
37
|
+
if (Object.hasOwn(PANE_BODY, view.pane)) return PANE_BODY[view.pane];
|
|
38
|
+
if (!view.item) return paintBodyEmpty;
|
|
39
|
+
return paintBodyDiff;
|
|
57
40
|
};
|
|
58
41
|
|
|
59
42
|
const frameNotes = (view, width, height, color) => {
|
|
60
43
|
const notesCap = Math.max(0, height - 4);
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
return { notesWanted, noteRows, noteCursor, bodyH };
|
|
44
|
+
const panel = paintNotePanel(view, width, color, notesCap);
|
|
45
|
+
const rows = panel.rows.slice(0, notesCap);
|
|
46
|
+
const inside = panel.cursor && panel.cursor.row < rows.length;
|
|
47
|
+
const cursor = inside ? panel.cursor : null;
|
|
48
|
+
const bodyH = Math.max(1, height - 3 - rows.length);
|
|
49
|
+
return { panel, rows, cursor, bodyH };
|
|
68
50
|
};
|
|
69
51
|
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
|
|
52
|
+
const revealScroll = (owners, focus, height, prefer) => {
|
|
53
|
+
const first = owners.indexOf(focus);
|
|
54
|
+
if (first < 0) return prefer;
|
|
55
|
+
const last = owners.lastIndexOf(focus);
|
|
56
|
+
const room = Math.max(1, height);
|
|
57
|
+
let start = Math.min(prefer, first);
|
|
58
|
+
if (last >= start + room) {
|
|
59
|
+
start = last - first + 1 <= room ? last - room + 1 : first;
|
|
60
|
+
}
|
|
61
|
+
return Math.max(0, Math.min(start, owners.length - room));
|
|
74
62
|
};
|
|
75
63
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (owners[i] !== focus) continue;
|
|
81
|
-
if (first < 0) first = i;
|
|
82
|
-
last = i;
|
|
83
|
-
}
|
|
84
|
-
return { first, last };
|
|
64
|
+
const windowY = (win, row) => {
|
|
65
|
+
const at = row + win.shift - win.scroll;
|
|
66
|
+
if (at < 0 || at >= win.shown) return -1;
|
|
67
|
+
return win.headerLines + at + 1;
|
|
85
68
|
};
|
|
86
69
|
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (span.first < start) start = span.first;
|
|
93
|
-
if (span.last >= start + room) {
|
|
94
|
-
const fits = span.last - span.first + 1 <= room;
|
|
95
|
-
start = fits ? span.last - room + 1 : span.first;
|
|
70
|
+
const mapEditHits = (hits, win) => {
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const hit of hits) {
|
|
73
|
+
const y = windowY(win, hit.row);
|
|
74
|
+
if (y >= 0) out.push({ ...hit, y });
|
|
96
75
|
}
|
|
97
|
-
|
|
98
|
-
if (start > maxStart) start = maxStart;
|
|
99
|
-
if (start < 0) start = 0;
|
|
100
|
-
return start;
|
|
76
|
+
return out;
|
|
101
77
|
};
|
|
102
78
|
|
|
103
|
-
const mapBodyCursor = (cursor,
|
|
79
|
+
const mapBodyCursor = (cursor, win) => {
|
|
104
80
|
if (!cursor) return null;
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
81
|
+
const y = windowY(win, cursor.row);
|
|
82
|
+
if (y < 0) return null;
|
|
83
|
+
const point = { x: cursor.x, y };
|
|
84
|
+
if (typeof cursor.scroll === 'number') point.scroll = cursor.scroll;
|
|
85
|
+
return point;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const bodyFillKind = (listPane, splitBody) => {
|
|
89
|
+
if (listPane) return 'files';
|
|
90
|
+
return splitBody ? 'split' : 'plain';
|
|
111
91
|
};
|
|
112
92
|
|
|
113
|
-
const windowBody = (view,
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
const splitBody = paintedBody.splitBody === true;
|
|
118
|
-
const pane = view.pane ?? 'diff';
|
|
119
|
-
const listPane = LIST_PANES.includes(pane);
|
|
120
|
-
const fillKind = bodyFillKind(listPane, splitBody);
|
|
93
|
+
const windowBody = (view, painted, frame) => {
|
|
94
|
+
const { width, color, bodyH, headerLines } = frame;
|
|
95
|
+
const listPane = isListPane(view.pane);
|
|
96
|
+
const fillKind = bodyFillKind(listPane, painted.splitBody);
|
|
121
97
|
const filler = paintBodyFill(width, color, fillKind);
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
shift = 1;
|
|
129
|
-
}
|
|
130
|
-
for (let i = 0; i < sourceBody.length; i++) body[bodyAt++] = sourceBody[i];
|
|
131
|
-
const ownerLead = lead && sourceOwners.length;
|
|
132
|
-
const todoOwners = new Array(sourceOwners.length + (ownerLead ? 1 : 0));
|
|
133
|
-
let ownerAt = 0;
|
|
134
|
-
if (ownerLead) todoOwners[ownerAt++] = null;
|
|
135
|
-
for (let i = 0; i < sourceOwners.length; i++) {
|
|
136
|
-
todoOwners[ownerAt++] = sourceOwners[i];
|
|
137
|
-
}
|
|
138
|
-
const checkLead = lead && sourceChecks.length;
|
|
139
|
-
const todoChecks = new Array(sourceChecks.length + (checkLead ? 1 : 0));
|
|
140
|
-
let checkAt = 0;
|
|
141
|
-
if (checkLead) todoChecks[checkAt++] = false;
|
|
142
|
-
for (let i = 0; i < sourceChecks.length; i++) {
|
|
143
|
-
todoChecks[checkAt++] = sourceChecks[i];
|
|
144
|
-
}
|
|
145
|
-
const scrollRaw = view.scroll ?? 0;
|
|
98
|
+
const shift = !listPane && painted.body.length > 0 ? 1 : 0;
|
|
99
|
+
const lead = (items, first) =>
|
|
100
|
+
shift && items.length ? [first, ...items] : items;
|
|
101
|
+
const body = lead(painted.body, filler);
|
|
102
|
+
const taskOwners = lead(painted.taskOwners, null);
|
|
103
|
+
const taskChecks = lead(painted.taskChecks, false);
|
|
146
104
|
const scrollMax = Math.max(0, body.length - bodyH);
|
|
147
|
-
let scroll = listPane ? 0 : Math.min(
|
|
148
|
-
if (view
|
|
149
|
-
scroll = revealScroll(
|
|
105
|
+
let scroll = listPane ? 0 : Math.min(view.scroll ?? 0, scrollMax);
|
|
106
|
+
if (isTaskView(view)) {
|
|
107
|
+
scroll = revealScroll(taskOwners, view.tasksFocus ?? 0, bodyH, scroll);
|
|
150
108
|
}
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
for (let i = 0; i <
|
|
155
|
-
|
|
156
|
-
for (let i = 0; i < copied; i++) {
|
|
157
|
-
const owner = todoOwners[scroll + i];
|
|
109
|
+
const slice = body.slice(scroll, scroll + bodyH);
|
|
110
|
+
const win = { shift, scroll, shown: slice.length, headerLines };
|
|
111
|
+
const taskHits = [];
|
|
112
|
+
for (let i = 0; i < slice.length; i++) {
|
|
113
|
+
const owner = taskOwners[scroll + i];
|
|
158
114
|
if (owner === undefined || owner === null) continue;
|
|
159
115
|
const y = headerLines + i + 1;
|
|
160
|
-
if (
|
|
161
|
-
|
|
116
|
+
if (taskChecks[scroll + i]) {
|
|
117
|
+
taskHits.push({ y, cursor: owner, x0: 1, x1: 4, check: true });
|
|
162
118
|
}
|
|
163
|
-
|
|
119
|
+
taskHits.push({ y, cursor: owner });
|
|
164
120
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
121
|
+
while (slice.length < bodyH) slice.push(filler);
|
|
122
|
+
return {
|
|
123
|
+
slice,
|
|
168
124
|
scroll,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
125
|
+
scrollMax,
|
|
126
|
+
listScroll: painted.listScroll,
|
|
127
|
+
taskHits,
|
|
128
|
+
fileHits: painted.fileHits,
|
|
129
|
+
editHits: mapEditHits(painted.editHits, win),
|
|
130
|
+
cursor: mapBodyCursor(painted.cursor, win),
|
|
131
|
+
};
|
|
176
132
|
};
|
|
177
133
|
|
|
178
|
-
const notePointerHits = (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
cursor = { x: noteCursor.x, y: 2 + bodyH + noteCursor.row };
|
|
182
|
-
}
|
|
134
|
+
const notePointerHits = (notes, bodyH) => {
|
|
135
|
+
const { panel, rows, cursor } = notes;
|
|
136
|
+
const top = 2 + bodyH;
|
|
183
137
|
const templateHits = [];
|
|
184
|
-
for (const hit of
|
|
185
|
-
if (hit.row
|
|
186
|
-
|
|
138
|
+
for (const hit of panel.templateHits) {
|
|
139
|
+
if (hit.row < rows.length) {
|
|
140
|
+
templateHits.push({ y: top + hit.row, cursor: hit.cursor });
|
|
141
|
+
}
|
|
187
142
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const status = view.status ?? '';
|
|
195
|
-
rows.push(paintStatusLine(view, status, width, color));
|
|
196
|
-
rows.push(paintFooter(view, layout, width, color));
|
|
197
|
-
return overlayRows(rows, view.selection);
|
|
143
|
+
const editHits = [];
|
|
144
|
+
for (const hit of panel.editHits) {
|
|
145
|
+
if (hit.row < rows.length) editHits.push({ ...hit, y: top + hit.row });
|
|
146
|
+
}
|
|
147
|
+
const point = cursor ? { x: cursor.x, y: top + cursor.row } : null;
|
|
148
|
+
return { cursor: point, templateHits, editHits };
|
|
198
149
|
};
|
|
199
150
|
|
|
200
151
|
const renderFrame = (view, options = {}) => {
|
|
201
152
|
const width = Math.max(20, options.width ?? 80);
|
|
202
153
|
const height = Math.max(6, options.height ?? 24);
|
|
203
154
|
const color = options.color ?? true;
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
const hidden = hiddenActions(view);
|
|
207
|
-
const dimmed = dimFooterActions(view);
|
|
208
|
-
const layout = layoutButtons(width, false, hidden, extra, dimmed);
|
|
155
|
+
const headerLines = 1;
|
|
156
|
+
const layout = footerLayout(view, width);
|
|
209
157
|
const notes = frameNotes(view, width, height, color);
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
158
|
+
const { bodyH } = notes;
|
|
159
|
+
const paint = bodyPainter(view);
|
|
160
|
+
const painted = paint(view, width, color, bodyH, headerLines);
|
|
161
|
+
const frame = { width, color, bodyH, headerLines };
|
|
162
|
+
const windowed = windowBody(view, painted, frame);
|
|
163
|
+
const rows = overlayRows(
|
|
164
|
+
[
|
|
165
|
+
paintHeader(view, width, color),
|
|
166
|
+
...windowed.slice,
|
|
167
|
+
...notes.rows,
|
|
168
|
+
paintStatusLine(view, view.status ?? '', width, color),
|
|
169
|
+
paintFooter(view, layout, width, color),
|
|
170
|
+
],
|
|
171
|
+
view.selection,
|
|
220
172
|
);
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
const hits = notePointerHits(
|
|
224
|
-
notes.notesWanted,
|
|
225
|
-
notes.noteRows,
|
|
226
|
-
notes.noteCursor,
|
|
227
|
-
bodyH,
|
|
228
|
-
);
|
|
229
|
-
const statusY = painted.length - 1;
|
|
173
|
+
const hits = notePointerHits(notes, bodyH);
|
|
174
|
+
const statusY = rows.length - 1;
|
|
230
175
|
const branchHit = statusBranchHit(view, width, statusY);
|
|
231
176
|
const statusHits = branchHit ? [branchHit] : statusChoiceHits(view, statusY);
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
177
|
+
const editHits = [...windowed.editHits, ...hits.editHits];
|
|
178
|
+
const shown = markEditorSelection(rows, view, editHits, color);
|
|
179
|
+
const text = shown.map((row) => (color ? row + RESET : row)).join('\n');
|
|
235
180
|
return {
|
|
236
181
|
text,
|
|
237
|
-
rows:
|
|
182
|
+
rows: shown,
|
|
238
183
|
buttons: footerHits(view, layout),
|
|
239
|
-
fileHits,
|
|
240
|
-
|
|
241
|
-
templateHits,
|
|
184
|
+
fileHits: windowed.fileHits,
|
|
185
|
+
taskHits: windowed.taskHits,
|
|
186
|
+
templateHits: hits.templateHits,
|
|
187
|
+
editHits,
|
|
242
188
|
statusHits,
|
|
243
|
-
footerY,
|
|
244
|
-
height:
|
|
245
|
-
scroll,
|
|
246
|
-
scrollMax,
|
|
247
|
-
listScroll,
|
|
189
|
+
footerY: rows.length,
|
|
190
|
+
height: rows.length,
|
|
191
|
+
scroll: windowed.scroll,
|
|
192
|
+
scrollMax: windowed.scrollMax,
|
|
193
|
+
listScroll: windowed.listScroll,
|
|
248
194
|
cursor: hits.cursor ?? windowed.cursor,
|
|
249
195
|
bodyH,
|
|
250
196
|
};
|
|
251
197
|
};
|
|
252
198
|
|
|
253
|
-
module.exports = {
|
|
199
|
+
module.exports = { renderFrame };
|