reslop 0.2.1 → 0.2.3
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 +14 -1
- package/README.md +11 -1
- package/lib/ansi.js +120 -4
- package/lib/cli.js +3 -0
- package/lib/deps.js +43 -3
- package/lib/git-branches.js +47 -15
- package/lib/keys.js +10 -4
- package/lib/npm-commands.js +513 -0
- package/lib/render/branches.js +21 -28
- package/lib/render/chrome.js +137 -122
- package/lib/render/commits.js +604 -54
- package/lib/render/frame.js +38 -4
- package/lib/render/npm.js +228 -0
- package/lib/render/primitives.js +7 -36
- package/lib/report-model.js +127 -0
- package/lib/report-parse.js +94 -0
- package/lib/report-render.js +87 -0
- package/lib/report-run.js +164 -0
- package/lib/report-test.js +506 -0
- package/lib/report-tools.js +311 -0
- package/lib/session/actions.js +51 -2
- package/lib/session/commit.js +94 -19
- package/lib/session/compose.js +48 -5
- package/lib/session/dispatch.js +30 -2
- package/lib/session/files-pane.js +20 -4
- package/lib/session/lifecycle.js +4 -1
- package/lib/session/navigation.js +1 -0
- package/lib/session/npm.js +335 -0
- package/lib/session/pointer.js +8 -0
- package/lib/session/view.js +14 -3
- package/lib/session.js +10 -2
- package/package.json +6 -6
package/lib/render/chrome.js
CHANGED
|
@@ -10,21 +10,33 @@ const { ACTION_IDS, BRANCH_ACTIONS, COMMIT_ACTIONS, actionLetter } = keys;
|
|
|
10
10
|
const { buttonWord } = keys;
|
|
11
11
|
const { FILES_HIDDEN, FILES_GIT_DISABLED, BRANCHES_DISABLED } = keys;
|
|
12
12
|
const { COMMITS_DISABLED, TODO_DISABLED, DIFF_DISABLED, UNIT_DISABLED } = keys;
|
|
13
|
+
const { NPM_DISABLED } = keys;
|
|
13
14
|
const { diffGitDisabled, branchGitDisabled, commitGitDisabled } = keys;
|
|
14
15
|
const { CONFIRM, confirmPrefix, promptFromChoices } = keys;
|
|
15
16
|
const { THEME, paint, visibleWidth } = ansi;
|
|
16
17
|
const { truncateVisible, fg, RESET, EL, seq } = ansi;
|
|
17
|
-
const { fill, branchLabel
|
|
18
|
+
const { fill, branchLabel } = primitives;
|
|
18
19
|
|
|
19
20
|
const HEADER_ROLE_FG = {
|
|
20
21
|
repo: THEME.headerRepoFg,
|
|
21
22
|
dir: THEME.headerDirFg,
|
|
22
23
|
slash: THEME.headerSlashFg,
|
|
23
24
|
file: THEME.headerFileFg,
|
|
24
|
-
meta: THEME.headerMetaFg,
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const WAVE = '·•●•·';
|
|
28
|
+
|
|
29
|
+
const busyBars = (wave) => {
|
|
30
|
+
const n = wave.length;
|
|
31
|
+
const frames = new Array(n);
|
|
32
|
+
for (let frame = 0; frame < n; frame++) {
|
|
33
|
+
const start = (n - frame) % n;
|
|
34
|
+
frames[frame] = wave.slice(start) + wave.slice(0, start);
|
|
35
|
+
}
|
|
36
|
+
return frames;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const BUSY_BAR = busyBars(WAVE);
|
|
28
40
|
const BUSY_PROGRESS = [
|
|
29
41
|
'pulling',
|
|
30
42
|
'pushing',
|
|
@@ -34,6 +46,7 @@ const BUSY_PROGRESS = [
|
|
|
34
46
|
'npm i',
|
|
35
47
|
'npm uninstall',
|
|
36
48
|
'npm audit fix',
|
|
49
|
+
'running',
|
|
37
50
|
'checking out',
|
|
38
51
|
'creating branch',
|
|
39
52
|
'rebasing',
|
|
@@ -105,21 +118,12 @@ const dropPrompt = (name) => ` drop ${name}? y/n`;
|
|
|
105
118
|
const PUSH_REJECT_PREFIX = CONFIRM.confirmPush.prefix;
|
|
106
119
|
const PUSH_PROMPT = `${PUSH_REJECT_PREFIX} force push`;
|
|
107
120
|
|
|
121
|
+
const BUTTON_LEAD = ' ';
|
|
108
122
|
const BUTTON_GAP = ' ';
|
|
123
|
+
const BUTTON_EDGE = 1;
|
|
124
|
+
const buttonGap = (index) => (index ? BUTTON_GAP : BUTTON_LEAD);
|
|
109
125
|
const LOGO = '👁️';
|
|
110
126
|
|
|
111
|
-
const ORIGIN_LABEL = {
|
|
112
|
-
commit: (view) => view.revShort || 'commit',
|
|
113
|
-
pr: (view) => view.sourceLabel || 'pr',
|
|
114
|
-
todo: () => 'todo',
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const originLabel = (origin, view) => {
|
|
118
|
-
const named = ORIGIN_LABEL[origin];
|
|
119
|
-
if (named) return named(view);
|
|
120
|
-
return origin ?? 'unknown';
|
|
121
|
-
};
|
|
122
|
-
|
|
123
127
|
const pathSegments = (rel) => {
|
|
124
128
|
const segs = [];
|
|
125
129
|
if (!rel) return segs;
|
|
@@ -137,84 +141,14 @@ const pathSegments = (rel) => {
|
|
|
137
141
|
return segs;
|
|
138
142
|
};
|
|
139
143
|
|
|
140
|
-
const headerTarget = (view) => {
|
|
141
|
-
const pane = view.pane ?? 'diff';
|
|
142
|
-
if (pane === 'files') {
|
|
143
|
-
const files = view.files ?? [];
|
|
144
|
-
const cursor = view.fileCursor ?? 0;
|
|
145
|
-
const entry = files[cursor];
|
|
146
|
-
const total = files.length;
|
|
147
|
-
const n = total ? cursor + 1 : 0;
|
|
148
|
-
if (!entry) return { path: '', origin: '', n, total };
|
|
149
|
-
if (isTodosEntry(entry)) {
|
|
150
|
-
return { path: TODO_FILE, origin: 'todo', n, total };
|
|
151
|
-
}
|
|
152
|
-
return { path: entry.path, origin: entry.status, n, total };
|
|
153
|
-
}
|
|
154
|
-
if (pane === 'branches') {
|
|
155
|
-
const compose = view.compose;
|
|
156
|
-
const branches = view.branches ?? [];
|
|
157
|
-
if (compose && compose.kind === 'branch') {
|
|
158
|
-
const total = branches.length + 1;
|
|
159
|
-
return { path: compose.text || '', origin: 'new', n: total, total };
|
|
160
|
-
}
|
|
161
|
-
const cursor = view.branchCursor ?? 0;
|
|
162
|
-
const entry = branches[cursor];
|
|
163
|
-
const total = branches.length;
|
|
164
|
-
const n = total ? cursor + 1 : 0;
|
|
165
|
-
if (!entry) return { path: '', origin: 'branch', n, total };
|
|
166
|
-
const origin = entry.current ? 'current' : 'branch';
|
|
167
|
-
return { path: entry.name, origin, n, total };
|
|
168
|
-
}
|
|
169
|
-
if (pane === 'commits') {
|
|
170
|
-
const compose = view.compose;
|
|
171
|
-
const commits = view.commits ?? [];
|
|
172
|
-
if (compose && compose.kind === 'commit') {
|
|
173
|
-
const path = `${compose.text || ''}`.replaceAll('\n', ' ');
|
|
174
|
-
if (compose.commitKind === 'amend' || compose.commitKind === 'reword') {
|
|
175
|
-
const cursor = view.commitCursor ?? 0;
|
|
176
|
-
const entry = commits[cursor];
|
|
177
|
-
const total = commits.length;
|
|
178
|
-
const n = total ? cursor + 1 : 0;
|
|
179
|
-
if (!entry) return { path, origin: 'commit', n, total };
|
|
180
|
-
const origin = entry.head ? 'HEAD' : 'commit';
|
|
181
|
-
return { path, origin, n, total };
|
|
182
|
-
}
|
|
183
|
-
const total = commits.length + 1;
|
|
184
|
-
return { path, origin: 'new', n: 1, total };
|
|
185
|
-
}
|
|
186
|
-
const cursor = view.commitCursor ?? 0;
|
|
187
|
-
const entry = commits[cursor];
|
|
188
|
-
const total = commits.length;
|
|
189
|
-
const n = total ? cursor + 1 : 0;
|
|
190
|
-
if (!entry) return { path: '', origin: 'commit', n, total };
|
|
191
|
-
const origin = entry.head ? 'HEAD' : 'commit';
|
|
192
|
-
return { path: entry.subject ?? '', origin, n, total };
|
|
193
|
-
}
|
|
194
|
-
if (pane === 'unit') {
|
|
195
|
-
const path = view.reviewPath ?? '';
|
|
196
|
-
const lines = view.unitLines ?? [];
|
|
197
|
-
const top = Math.max(0, (view.scroll ?? 0) - 1);
|
|
198
|
-
const n = lines.length ? Math.min(lines.length, top + 1) : 0;
|
|
199
|
-
const origin = view.item ? originLabel(view.item.origin, view) : 'unit';
|
|
200
|
-
return { path, origin, n, total: lines.length };
|
|
201
|
-
}
|
|
202
|
-
if (!view.item) return { path: '', origin: '', n: 0, total: view.total ?? 0 };
|
|
203
|
-
if (view.item.origin === 'todo') {
|
|
204
|
-
return { path: TODO_FILE, origin: 'todo', n: 1, total: 1 };
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
path: itemPath(view.item),
|
|
208
|
-
origin: originLabel(view.item.origin, view),
|
|
209
|
-
n: view.index + 1,
|
|
210
|
-
total: view.total,
|
|
211
|
-
};
|
|
212
|
-
};
|
|
213
|
-
|
|
214
144
|
const headerScreen = (view) => {
|
|
215
145
|
const pane = view.pane ?? 'diff';
|
|
216
146
|
if (pane === 'branches') return 'branches';
|
|
217
|
-
if (pane === 'commits')
|
|
147
|
+
if (pane === 'commits') {
|
|
148
|
+
const mode = view.commitView === 'full' ? 'full' : 'brief';
|
|
149
|
+
return `commits ${mode}`;
|
|
150
|
+
}
|
|
151
|
+
if (pane === 'npm') return 'npm';
|
|
218
152
|
if (pane === 'files') {
|
|
219
153
|
const files = view.files ?? [];
|
|
220
154
|
const entry = files[view.fileCursor ?? 0];
|
|
@@ -225,38 +159,41 @@ const headerScreen = (view) => {
|
|
|
225
159
|
return '';
|
|
226
160
|
};
|
|
227
161
|
|
|
228
|
-
const
|
|
162
|
+
const headerTarget = (view) => {
|
|
163
|
+
const pane = view.pane ?? 'diff';
|
|
164
|
+
if (pane === 'files') {
|
|
165
|
+
const entry = (view.files ?? [])[view.fileCursor ?? 0];
|
|
166
|
+
if (!entry || isTodosEntry(entry)) return '';
|
|
167
|
+
return entry.path;
|
|
168
|
+
}
|
|
169
|
+
if (pane === 'unit') return view.reviewPath ?? '';
|
|
170
|
+
if (!view.item || view.item.origin === 'todo') return '';
|
|
171
|
+
return itemPath(view.item);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const headerLabel = (view) => headerScreen(view) || headerTarget(view);
|
|
229
175
|
|
|
230
176
|
const headerSep = (view) => (headerScreen(view) ? ': ' : '/');
|
|
231
177
|
|
|
232
|
-
const headerPrefix = (view) => {
|
|
178
|
+
const headerPrefix = (view, label) => {
|
|
233
179
|
const repo = view.repoName || '';
|
|
234
|
-
const target = headerTarget(view);
|
|
235
|
-
const label = headerLabel(view, target);
|
|
236
180
|
if (repo && label) return ` ${LOGO} reslop: ${repo}${headerSep(view)}`;
|
|
237
181
|
if (repo) return ` ${LOGO} reslop: ${repo} `;
|
|
238
182
|
return ` ${LOGO} reslop: `;
|
|
239
183
|
};
|
|
240
184
|
|
|
241
|
-
const headerSuffix = ({ origin, n, total }) =>
|
|
242
|
-
origin ? ` ${origin} ${n}/${total}` : ` ${n}/${total}`;
|
|
243
|
-
|
|
244
185
|
const headerText = (view) => {
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
const label = headerLabel(view, target);
|
|
248
|
-
return `${prefix}${label}${headerSuffix(target)}`;
|
|
186
|
+
const label = headerLabel(view);
|
|
187
|
+
return `${headerPrefix(view, label)}${label}`;
|
|
249
188
|
};
|
|
250
189
|
|
|
251
190
|
const headerPieces = (view, width) => {
|
|
252
191
|
const repo = view.repoName || '';
|
|
253
|
-
const
|
|
254
|
-
const path = headerLabel(view, target);
|
|
255
|
-
const suffix = headerSuffix(target);
|
|
192
|
+
const path = headerLabel(view);
|
|
256
193
|
const right = ' ';
|
|
257
194
|
const chrome = ` ${LOGO} reslop: `;
|
|
258
|
-
const prefixW = visibleWidth(headerPrefix(view));
|
|
259
|
-
const used = prefixW + visibleWidth(
|
|
195
|
+
const prefixW = visibleWidth(headerPrefix(view, path));
|
|
196
|
+
const used = prefixW + visibleWidth(right);
|
|
260
197
|
const room = Math.max(0, width - used);
|
|
261
198
|
const clipped = truncateVisible(path, room);
|
|
262
199
|
const pad = Math.max(0, room - visibleWidth(clipped));
|
|
@@ -277,7 +214,6 @@ const headerPieces = (view, width) => {
|
|
|
277
214
|
if (pad) {
|
|
278
215
|
pieces.push({ text: ' '.repeat(pad), role: 'chrome' });
|
|
279
216
|
}
|
|
280
|
-
pieces.push({ text: suffix, role: 'meta' });
|
|
281
217
|
pieces.push({ text: right, role: 'chrome' });
|
|
282
218
|
return pieces;
|
|
283
219
|
};
|
|
@@ -340,6 +276,7 @@ const layoutButtons = (width, compact, hidden, extra, disabled) => {
|
|
|
340
276
|
for (const add of extraIds) {
|
|
341
277
|
if (!ids.includes(add)) ids.push(add);
|
|
342
278
|
}
|
|
279
|
+
continue;
|
|
343
280
|
}
|
|
344
281
|
if (hiddenIds.includes(id)) continue;
|
|
345
282
|
ids.push(id);
|
|
@@ -348,13 +285,15 @@ const layoutButtons = (width, compact, hidden, extra, disabled) => {
|
|
|
348
285
|
const hits = [];
|
|
349
286
|
const parts = [];
|
|
350
287
|
let x = 0;
|
|
288
|
+
const limit = Math.max(0, width - BUTTON_EDGE);
|
|
351
289
|
for (const id of ids) {
|
|
352
290
|
const letter = actionLetter(id);
|
|
353
291
|
const word = buttonWord(id);
|
|
354
292
|
const label = short ? letter : word;
|
|
355
|
-
const
|
|
293
|
+
const gap = buttonGap(parts.length);
|
|
294
|
+
const piece = `${gap}${label}`;
|
|
356
295
|
const w = visibleWidth(piece);
|
|
357
|
-
if (x + w >
|
|
296
|
+
if (x + w > limit && parts.length) break;
|
|
358
297
|
const off = disabledIds.includes(id);
|
|
359
298
|
if (!off) hits.push({ id, x0: x, x1: x + w });
|
|
360
299
|
parts.push({ action: { id }, piece, letter, label, disabled: off });
|
|
@@ -373,8 +312,10 @@ const paintButtons = (layout, width, color) => {
|
|
|
373
312
|
let used = 0;
|
|
374
313
|
const fgRgb = THEME.buttonFg;
|
|
375
314
|
const bgRgb = THEME.buttonBg;
|
|
376
|
-
for (
|
|
377
|
-
|
|
315
|
+
for (let i = 0; i < layout.parts.length; i++) {
|
|
316
|
+
const part = layout.parts[i];
|
|
317
|
+
const gap = buttonGap(i);
|
|
318
|
+
out += paint(gap, fgRgb, bgRgb, color);
|
|
378
319
|
if (part.disabled) out += paint(part.label, fgRgb, bgRgb, color);
|
|
379
320
|
else out += paintMarkedWord(part.label, part.letter, color, BUTTON_MARK);
|
|
380
321
|
used += visibleWidth(part.piece);
|
|
@@ -512,14 +453,10 @@ const paintChoicePrompt = (choices, width, color, prefix = '') => {
|
|
|
512
453
|
return out + fill(pad, THEME.mutedFg, bgRgb, color);
|
|
513
454
|
};
|
|
514
455
|
|
|
515
|
-
const STATUS_MARK = /(
|
|
456
|
+
const STATUS_MARK = /(\+[0-9]+(?:\/[0-9]+)?|-[0-9]+(?:\/[0-9]+)?)/g;
|
|
516
457
|
|
|
517
458
|
const paintStatusMark = (token, color) => {
|
|
518
459
|
const bgRgb = THEME.chromeBg;
|
|
519
|
-
const muted = THEME.mutedFg;
|
|
520
|
-
if (token.startsWith('[')) {
|
|
521
|
-
return paintBracketName(token, THEME.buttonHotFg, muted, bgRgb, color);
|
|
522
|
-
}
|
|
523
460
|
if (token.startsWith('+')) {
|
|
524
461
|
return paint(token, THEME.addLineFg, bgRgb, color);
|
|
525
462
|
}
|
|
@@ -547,6 +484,68 @@ const paintStatusLeft = (text, color) => {
|
|
|
547
484
|
return out;
|
|
548
485
|
};
|
|
549
486
|
|
|
487
|
+
const paintBranchHead = (text, branch, color) => {
|
|
488
|
+
const name = branchLabel(branch);
|
|
489
|
+
if (!name || !text.startsWith(' ')) return null;
|
|
490
|
+
const head = ` ${name}`;
|
|
491
|
+
const shown = text.startsWith(head) ? name : text.slice(1);
|
|
492
|
+
if (!shown || !name.startsWith(shown)) return null;
|
|
493
|
+
const rest = text.slice(1 + shown.length);
|
|
494
|
+
const bgRgb = THEME.chromeBg;
|
|
495
|
+
return (
|
|
496
|
+
paint(' ', THEME.mutedFg, bgRgb, color) +
|
|
497
|
+
paint(shown, THEME.buttonHotFg, bgRgb, color, true) +
|
|
498
|
+
paintStatusLeft(rest, color)
|
|
499
|
+
);
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
const SAVE_HINT = 'Press **Ctrl-S** or **Enter** at EOF to save';
|
|
503
|
+
const HINT_HOT_FG = 0xff;
|
|
504
|
+
|
|
505
|
+
const hintParts = (source) => {
|
|
506
|
+
const bits = source.split('**');
|
|
507
|
+
const parts = [];
|
|
508
|
+
for (let i = 0; i < bits.length; i++) {
|
|
509
|
+
if (!bits[i]) continue;
|
|
510
|
+
parts.push({ text: bits[i], hot: i % 2 === 1 });
|
|
511
|
+
}
|
|
512
|
+
return parts;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const saveHintText = () => SAVE_HINT.replaceAll('**', '');
|
|
516
|
+
|
|
517
|
+
const commitSaveHint = (view) => {
|
|
518
|
+
if (view.mode !== 'compose' || view.commitView !== 'full') return false;
|
|
519
|
+
const compose = view.compose;
|
|
520
|
+
return Boolean(compose && compose.kind === 'commit');
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
const paintSaveHintBar = (width, color) => {
|
|
524
|
+
const bgRgb = THEME.buttonBg;
|
|
525
|
+
const plain = `${BUTTON_LEAD}${saveHintText()}`;
|
|
526
|
+
if (!color) {
|
|
527
|
+
const pad = Math.max(0, width - visibleWidth(plain));
|
|
528
|
+
return plain + ' '.repeat(pad);
|
|
529
|
+
}
|
|
530
|
+
let out = paint(BUTTON_LEAD, THEME.buttonFg, bgRgb, color);
|
|
531
|
+
for (const part of hintParts(SAVE_HINT)) {
|
|
532
|
+
const tone = part.hot ? HINT_HOT_FG : THEME.buttonFg;
|
|
533
|
+
out += paint(part.text, tone, bgRgb, color, part.hot);
|
|
534
|
+
}
|
|
535
|
+
const pad = Math.max(0, width - visibleWidth(plain));
|
|
536
|
+
return out + fill(pad, THEME.buttonFg, bgRgb, color);
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const paintFooter = (view, layout, width, color) => {
|
|
540
|
+
if (commitSaveHint(view)) return paintSaveHintBar(width, color);
|
|
541
|
+
return paintButtons(layout, width, color);
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const footerHits = (view, layout) => {
|
|
545
|
+
if (commitSaveHint(view)) return [];
|
|
546
|
+
return layout.hits;
|
|
547
|
+
};
|
|
548
|
+
|
|
550
549
|
const paintStatusLine = (view, status, width, color) => {
|
|
551
550
|
const confirm = CONFIRM[view.mode];
|
|
552
551
|
if (confirm) {
|
|
@@ -560,8 +559,13 @@ const paintStatusLine = (view, status, width, color) => {
|
|
|
560
559
|
return layout.clipped + leftGap + layout.msg + rightGap + layout.right;
|
|
561
560
|
}
|
|
562
561
|
const bgRgb = THEME.chromeBg;
|
|
562
|
+
const worktree = countsKind(view.sourceKind, view.revShort) === 'worktree';
|
|
563
|
+
const head = worktree
|
|
564
|
+
? paintBranchHead(layout.clipped, view.branch, color)
|
|
565
|
+
: null;
|
|
566
|
+
const left = head ?? paintStatusLeft(layout.clipped, color);
|
|
563
567
|
return (
|
|
564
|
-
|
|
568
|
+
left +
|
|
565
569
|
paint(leftGap, THEME.mutedFg, bgRgb, color) +
|
|
566
570
|
paint(layout.msg, layout.msgFg, bgRgb, color) +
|
|
567
571
|
paint(rightGap, THEME.mutedFg, bgRgb, color) +
|
|
@@ -583,10 +587,10 @@ const statusBranchHit = (view, width, y) => {
|
|
|
583
587
|
if (!branchLabel(branch)) return null;
|
|
584
588
|
if (countsKind(view.sourceKind, view.revShort) !== 'worktree') return null;
|
|
585
589
|
const layout = statusLayout(view, view.status ?? '', width);
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
if (
|
|
589
|
-
return { id: 'branch', y, x0:
|
|
590
|
+
const name = branchLabel(branch);
|
|
591
|
+
const at = layout.clipped.indexOf(name);
|
|
592
|
+
if (at < 0) return null;
|
|
593
|
+
return { id: 'branch', y, x0: at, x1: at + visibleWidth(name) };
|
|
590
594
|
};
|
|
591
595
|
|
|
592
596
|
const selectedBranch = (view) => (view.branches ?? [])[view.branchCursor ?? 0];
|
|
@@ -599,6 +603,7 @@ const hiddenActions = (view) => {
|
|
|
599
603
|
if (pane === 'unit') return UNIT_DISABLED;
|
|
600
604
|
if (pane === 'branches') return BRANCHES_DISABLED;
|
|
601
605
|
if (pane === 'commits') return COMMITS_DISABLED;
|
|
606
|
+
if (pane === 'npm') return NPM_DISABLED;
|
|
602
607
|
if (view.item && view.item.origin === 'todo') return TODO_DISABLED;
|
|
603
608
|
return DIFF_DISABLED;
|
|
604
609
|
};
|
|
@@ -619,6 +624,10 @@ const dimFooterActions = (view) => {
|
|
|
619
624
|
if (!entry) return commitGitDisabled({ canCommit: staged });
|
|
620
625
|
return commitGitDisabled({ ...entry, canCommit: staged });
|
|
621
626
|
}
|
|
627
|
+
if (pane === 'npm' && view.npmView) {
|
|
628
|
+
if (view.npmRunning) return ['npmRerun'];
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
622
631
|
return [];
|
|
623
632
|
};
|
|
624
633
|
|
|
@@ -626,10 +635,14 @@ const extraFooterActions = (view) => {
|
|
|
626
635
|
const pane = view.pane ?? 'diff';
|
|
627
636
|
if (pane === 'files') {
|
|
628
637
|
const scope = view.fileScope === 'file' ? 'diff' : 'file';
|
|
629
|
-
return [scope, 'commit', 'pull', 'push'];
|
|
638
|
+
return ['npm', scope, 'commit', 'pull', 'push'];
|
|
630
639
|
}
|
|
631
640
|
if (pane === 'branches') return Object.keys(BRANCH_ACTIONS);
|
|
632
641
|
if (pane === 'commits') return Object.keys(COMMIT_ACTIONS);
|
|
642
|
+
if (pane === 'npm') {
|
|
643
|
+
if (view.npmView) return ['npmStop', 'npmRerun'];
|
|
644
|
+
return ['npmEdit', 'npmNew'];
|
|
645
|
+
}
|
|
633
646
|
return [];
|
|
634
647
|
};
|
|
635
648
|
|
|
@@ -643,6 +656,8 @@ module.exports = {
|
|
|
643
656
|
paintHeader,
|
|
644
657
|
layoutButtons,
|
|
645
658
|
paintButtons,
|
|
659
|
+
paintFooter,
|
|
660
|
+
footerHits,
|
|
646
661
|
paintStatusLine,
|
|
647
662
|
statusChoiceHits,
|
|
648
663
|
statusBranchHit,
|