reslop 0.2.5 → 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 +12 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +39 -47
- 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 +197 -402
- package/lib/deps.js +113 -240
- 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 +76 -144
- 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 +79 -178
- package/lib/editor.js +52 -69
- package/lib/files.js +71 -89
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +147 -272
- 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 +155 -141
- 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 +14 -14
- 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 +19 -25
- package/lib/highlight/txt.js +7 -10
- package/lib/highlight.js +17 -46
- package/lib/keys.js +49 -82
- package/lib/manifest.js +67 -126
- package/lib/npm-commands.js +120 -169
- package/lib/remote.js +140 -190
- package/lib/render/branches.js +63 -61
- package/lib/render/chrome.js +220 -333
- package/lib/render/commits.js +160 -361
- 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 -258
- package/lib/render/files.js +40 -85
- package/lib/render/frame.js +78 -117
- package/lib/render/notes.js +139 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +72 -174
- 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 -31
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -37
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -77
- package/lib/report-test.js +221 -99
- package/lib/report-tools.js +96 -154
- package/lib/review-merge.js +33 -41
- package/lib/review.js +68 -129
- package/lib/runs.js +225 -0
- package/lib/select.js +53 -91
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +61 -43
- package/lib/session/branches.js +166 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +274 -355
- package/lib/session/compose.js +556 -714
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +162 -170
- package/lib/session/files-pane.js +76 -44
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +393 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +2 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/pointer.js +16 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +276 -235
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +47 -81
- package/lib/session/watch.js +196 -212
- package/lib/session.js +81 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
package/lib/render/chrome.js
CHANGED
|
@@ -6,8 +6,8 @@ const files = require('../files.js');
|
|
|
6
6
|
const primitives = require('./primitives.js');
|
|
7
7
|
|
|
8
8
|
const { itemPath, REPO_TASKS_LABEL, isTasksEntry, fileTotals } = files;
|
|
9
|
-
const { ACTION_IDS,
|
|
10
|
-
const { buttonWord } = keys;
|
|
9
|
+
const { ACTION_IDS, actionLetter } = keys;
|
|
10
|
+
const { DASH_IDS, DASH_HIDDEN, buttonWord } = keys;
|
|
11
11
|
const { FILES_HIDDEN, FILES_GIT_DISABLED, BRANCHES_DISABLED } = keys;
|
|
12
12
|
const { COMMITS_DISABLED, TASKS_DISABLED, DIFF_DISABLED, UNIT_DISABLED } = keys;
|
|
13
13
|
const { NPM_DISABLED } = keys;
|
|
@@ -15,28 +15,14 @@ const { diffGitDisabled, branchGitDisabled, commitGitDisabled } = keys;
|
|
|
15
15
|
const { CONFIRM, confirmPrefix, promptFromChoices } = keys;
|
|
16
16
|
const { THEME, paint, visibleWidth } = ansi;
|
|
17
17
|
const { truncateVisible, fg, RESET, EL, seq } = ansi;
|
|
18
|
-
const { fill, branchLabel } = primitives;
|
|
19
|
-
|
|
20
|
-
const HEADER_ROLE_FG = {
|
|
21
|
-
repo: THEME.headerRepoFg,
|
|
22
|
-
dir: THEME.headerDirFg,
|
|
23
|
-
slash: THEME.headerSlashFg,
|
|
24
|
-
file: THEME.headerFileFg,
|
|
25
|
-
};
|
|
18
|
+
const { fill, branchLabel, isTaskView } = primitives;
|
|
26
19
|
|
|
27
20
|
const WAVE = '·•●•·';
|
|
21
|
+
const BUSY_BAR = Array.from(WAVE, (_, frame) => {
|
|
22
|
+
const start = (WAVE.length - frame) % WAVE.length;
|
|
23
|
+
return WAVE.slice(start) + WAVE.slice(0, start);
|
|
24
|
+
});
|
|
28
25
|
|
|
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);
|
|
40
26
|
const BUSY_PROGRESS = [
|
|
41
27
|
'pulling',
|
|
42
28
|
'pushing',
|
|
@@ -112,154 +98,138 @@ const INFO_STATUS = [
|
|
|
112
98
|
];
|
|
113
99
|
const INFO_PREFIX = ['checked out ', 'created ', 'rebased onto ', 'dropped '];
|
|
114
100
|
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
101
|
+
const LOGO = '👁️';
|
|
102
|
+
const HEADER_LEAD = ` ${LOGO} reslop: `;
|
|
103
|
+
const HEADER_ROLE_FG = {
|
|
104
|
+
chrome: THEME.headerChromeFg,
|
|
105
|
+
repo: THEME.headerRepoFg,
|
|
106
|
+
dir: THEME.headerDirFg,
|
|
107
|
+
slash: THEME.headerSlashFg,
|
|
108
|
+
file: THEME.headerFileFg,
|
|
109
|
+
};
|
|
120
110
|
|
|
121
111
|
const BUTTON_LEAD = ' ';
|
|
122
112
|
const BUTTON_GAP = ' ';
|
|
123
113
|
const BUTTON_EDGE = 1;
|
|
124
|
-
const buttonGap = (index) => (index ? BUTTON_GAP : BUTTON_LEAD);
|
|
125
114
|
const BACK_ARROW = '🢐';
|
|
126
115
|
const STOP_MARK = '⊗';
|
|
127
116
|
const BACK_KEY = 'esc';
|
|
128
|
-
|
|
117
|
+
|
|
118
|
+
const BUTTON_MARK = {
|
|
119
|
+
bgRgb: THEME.buttonBg,
|
|
120
|
+
fgRgb: THEME.buttonFg,
|
|
121
|
+
hotFg: THEME.buttonHotFg,
|
|
122
|
+
missFg: THEME.buttonHotFg,
|
|
123
|
+
missBold: true,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const QUIT_MARK = {
|
|
127
|
+
bgRgb: THEME.chromeBg,
|
|
128
|
+
fgRgb: THEME.mutedFg,
|
|
129
|
+
hotFg: THEME.warnFg,
|
|
130
|
+
missFg: THEME.mutedFg,
|
|
131
|
+
missBold: false,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const STATUS_MARK = /(\+[0-9]+(?:\/[0-9]+)?|-[0-9]+(?:\/[0-9]+)?)/g;
|
|
135
|
+
const OLD_LOGS = /old logs \S+/;
|
|
136
|
+
const SAVE_HINT = 'Press **Ctrl-S** or **Enter** at EOF to save';
|
|
137
|
+
const HINT_HOT_FG = 0xff;
|
|
138
|
+
|
|
139
|
+
const selectedFile = (view) => (view.files ?? [])[view.fileCursor ?? 0];
|
|
140
|
+
|
|
141
|
+
const selectedBranch = (view) => (view.branches ?? [])[view.branchCursor ?? 0];
|
|
142
|
+
|
|
143
|
+
const selectedCommit = (view) => (view.commits ?? [])[view.commitCursor ?? 0];
|
|
144
|
+
|
|
145
|
+
const piecesText = (pieces) => pieces.map((piece) => piece.text).join('');
|
|
129
146
|
|
|
130
147
|
const pathSegments = (rel) => {
|
|
131
148
|
const segs = [];
|
|
132
149
|
if (!rel) return segs;
|
|
133
150
|
const bits = rel.split('/');
|
|
134
151
|
for (let i = 0; i < bits.length; i++) {
|
|
135
|
-
if (i) {
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
if (!bits[i]) {
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
const last = i === bits.length - 1;
|
|
142
|
-
segs.push({ text: bits[i], role: last ? 'file' : 'dir' });
|
|
152
|
+
if (i) segs.push({ text: '/', role: 'slash' });
|
|
153
|
+
const role = i === bits.length - 1 ? 'file' : 'dir';
|
|
154
|
+
if (bits[i]) segs.push({ text: bits[i], role });
|
|
143
155
|
}
|
|
144
156
|
return segs;
|
|
145
157
|
};
|
|
146
158
|
|
|
147
159
|
const headerScreen = (view) => {
|
|
148
|
-
const pane = view
|
|
149
|
-
if (
|
|
160
|
+
const { pane } = view;
|
|
161
|
+
if (
|
|
162
|
+
pane === 'dashboard' ||
|
|
163
|
+
pane === 'branches' ||
|
|
164
|
+
pane === 'npm' ||
|
|
165
|
+
pane === 'tasks'
|
|
166
|
+
) {
|
|
167
|
+
return pane;
|
|
168
|
+
}
|
|
150
169
|
if (pane === 'commits') {
|
|
151
|
-
|
|
152
|
-
return `commits ${mode}`;
|
|
170
|
+
return view.commitView === 'full' ? 'commits full' : 'commits brief';
|
|
153
171
|
}
|
|
154
|
-
if (pane === 'npm') return 'npm';
|
|
155
172
|
if (pane === 'files') {
|
|
156
|
-
|
|
157
|
-
const entry = files[view.fileCursor ?? 0];
|
|
158
|
-
if (isTasksEntry(entry)) return REPO_TASKS_LABEL;
|
|
159
|
-
return '';
|
|
173
|
+
return isTasksEntry(selectedFile(view)) ? REPO_TASKS_LABEL : '';
|
|
160
174
|
}
|
|
161
|
-
|
|
162
|
-
return '';
|
|
175
|
+
return isTaskView(view) ? REPO_TASKS_LABEL : '';
|
|
163
176
|
};
|
|
164
177
|
|
|
165
178
|
const headerTarget = (view) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const entry = (view.files ?? [])[view.fileCursor ?? 0];
|
|
179
|
+
if (view.pane === 'files') {
|
|
180
|
+
const entry = selectedFile(view);
|
|
169
181
|
if (!entry || isTasksEntry(entry)) return '';
|
|
170
182
|
return entry.path;
|
|
171
183
|
}
|
|
172
|
-
if (pane === 'unit') return view.reviewPath ?? '';
|
|
173
|
-
if (
|
|
184
|
+
if (view.pane === 'unit') return view.reviewPath ?? '';
|
|
185
|
+
if (isTaskView(view)) return '';
|
|
174
186
|
return itemPath(view.item);
|
|
175
187
|
};
|
|
176
188
|
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
const headerPrefix = (view, label) => {
|
|
189
|
+
const headerLead = (view) => {
|
|
190
|
+
const screen = headerScreen(view);
|
|
191
|
+
const label = screen || headerTarget(view);
|
|
182
192
|
const repo = view.repoName || '';
|
|
183
|
-
|
|
184
|
-
if (repo)
|
|
185
|
-
|
|
193
|
+
const pieces = [{ text: HEADER_LEAD, role: 'chrome' }];
|
|
194
|
+
if (repo) {
|
|
195
|
+
pieces.push({ text: repo, role: 'repo' });
|
|
196
|
+
if (!label) pieces.push({ text: ' ', role: 'chrome' });
|
|
197
|
+
else if (screen) pieces.push({ text: ': ', role: 'chrome' });
|
|
198
|
+
else pieces.push({ text: '/', role: 'slash' });
|
|
199
|
+
}
|
|
200
|
+
return { pieces, label };
|
|
186
201
|
};
|
|
187
202
|
|
|
188
203
|
const headerText = (view) => {
|
|
189
|
-
const label =
|
|
190
|
-
return `${
|
|
204
|
+
const { pieces, label } = headerLead(view);
|
|
205
|
+
return `${piecesText(pieces)}${label}`;
|
|
191
206
|
};
|
|
192
207
|
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
const path = headerLabel(view);
|
|
208
|
+
const paintHeader = (view, width, color) => {
|
|
209
|
+
const { pieces, label } = headerLead(view);
|
|
196
210
|
const right = ' ';
|
|
197
|
-
const
|
|
198
|
-
const prefixW = visibleWidth(headerPrefix(view, path));
|
|
199
|
-
const used = prefixW + visibleWidth(right);
|
|
211
|
+
const used = visibleWidth(piecesText(pieces)) + visibleWidth(right);
|
|
200
212
|
const room = Math.max(0, width - used);
|
|
201
|
-
const clipped = truncateVisible(
|
|
213
|
+
const clipped = truncateVisible(label, room);
|
|
202
214
|
const pad = Math.max(0, room - visibleWidth(clipped));
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
pieces.push({ text: repo, role: 'repo' });
|
|
206
|
-
if (path) {
|
|
207
|
-
const sep = headerSep(view);
|
|
208
|
-
const role = sep === '/' ? 'slash' : 'chrome';
|
|
209
|
-
pieces.push({ text: sep, role });
|
|
210
|
-
} else {
|
|
211
|
-
pieces.push({ text: ' ', role: 'chrome' });
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
for (const seg of pathSegments(clipped)) {
|
|
215
|
-
pieces.push(seg);
|
|
216
|
-
}
|
|
217
|
-
if (pad) {
|
|
218
|
-
pieces.push({ text: ' '.repeat(pad), role: 'chrome' });
|
|
219
|
-
}
|
|
215
|
+
pieces.push(...pathSegments(clipped));
|
|
216
|
+
if (pad) pieces.push({ text: ' '.repeat(pad), role: 'chrome' });
|
|
220
217
|
pieces.push({ text: right, role: 'chrome' });
|
|
221
|
-
return pieces;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const paintHeader = (view, width, color) => {
|
|
225
|
-
const pieces = headerPieces(view, width);
|
|
226
|
-
if (!color) {
|
|
227
|
-
return pieces.map((piece) => piece.text).join('');
|
|
228
|
-
}
|
|
229
|
-
const bgRgb = THEME.headerBg;
|
|
230
|
-
let out = `${seq(THEME.headerChromeFg, bgRgb)}${EL}`;
|
|
218
|
+
if (!color) return piecesText(pieces);
|
|
219
|
+
let out = `${seq(THEME.headerChromeFg, THEME.headerBg)}${EL}`;
|
|
231
220
|
for (const piece of pieces) {
|
|
232
|
-
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
const roleFg = HEADER_ROLE_FG[piece.role] ?? THEME.headerChromeFg;
|
|
236
|
-
out += `${fg(roleFg)}${piece.text}`;
|
|
221
|
+
out += `${fg(HEADER_ROLE_FG[piece.role])}${piece.text}`;
|
|
237
222
|
}
|
|
238
223
|
return `${out}${RESET}`;
|
|
239
224
|
};
|
|
240
225
|
|
|
241
|
-
const BUTTON_MARK = {
|
|
242
|
-
bgRgb: THEME.buttonBg,
|
|
243
|
-
fgRgb: THEME.buttonFg,
|
|
244
|
-
hotFg: THEME.buttonHotFg,
|
|
245
|
-
missFg: THEME.buttonHotFg,
|
|
246
|
-
missBold: true,
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const QUIT_MARK = {
|
|
250
|
-
bgRgb: THEME.chromeBg,
|
|
251
|
-
fgRgb: THEME.mutedFg,
|
|
252
|
-
hotFg: THEME.warnFg,
|
|
253
|
-
missFg: THEME.mutedFg,
|
|
254
|
-
missBold: false,
|
|
255
|
-
};
|
|
256
|
-
|
|
257
226
|
const backFooterId = (view) => {
|
|
258
|
-
const pane = view
|
|
259
|
-
if (pane === 'branches' || pane === 'commits'
|
|
227
|
+
const { pane } = view;
|
|
228
|
+
if (pane === 'branches' || pane === 'commits' || pane === 'tasks') {
|
|
229
|
+
return 'back';
|
|
230
|
+
}
|
|
260
231
|
if (pane === 'npm') return view.npmView ? 'npmStop' : 'back';
|
|
261
|
-
|
|
262
|
-
return '';
|
|
232
|
+
return isTaskView(view) ? 'back' : '';
|
|
263
233
|
};
|
|
264
234
|
|
|
265
235
|
const backHintMark = (view) => {
|
|
@@ -267,23 +237,20 @@ const backHintMark = (view) => {
|
|
|
267
237
|
return BACK_ARROW;
|
|
268
238
|
};
|
|
269
239
|
|
|
240
|
+
const buttonGap = (index) => (index ? BUTTON_GAP : BUTTON_LEAD);
|
|
241
|
+
|
|
270
242
|
const hintBody = (mark) => {
|
|
271
243
|
const gap = mark === STOP_MARK ? ' ' : '';
|
|
272
244
|
return `${mark}${gap}${BACK_KEY}`;
|
|
273
245
|
};
|
|
274
246
|
|
|
275
|
-
const buttonLabel = (id, short
|
|
276
|
-
if (id === backId) return hintBody(mark);
|
|
277
|
-
if (short) return actionLetter(id);
|
|
278
|
-
return buttonWord(id);
|
|
279
|
-
};
|
|
247
|
+
const buttonLabel = (id, short) => (short ? actionLetter(id) : buttonWord(id));
|
|
280
248
|
|
|
281
249
|
const paintBackHint = (color, mark) => {
|
|
282
250
|
const bgRgb = THEME.buttonBg;
|
|
283
|
-
const
|
|
251
|
+
const rest = hintBody(mark).slice(mark.length);
|
|
284
252
|
const arrow = paint(mark, THEME.buttonHotFg, bgRgb, color, true);
|
|
285
|
-
|
|
286
|
-
return arrow + rest;
|
|
253
|
+
return arrow + paint(rest, THEME.buttonFg, bgRgb, color);
|
|
287
254
|
};
|
|
288
255
|
|
|
289
256
|
const paintMarkedWord = (label, letter, color, mark) => {
|
|
@@ -294,59 +261,46 @@ const paintMarkedWord = (label, letter, color, mark) => {
|
|
|
294
261
|
const before = label.slice(0, at);
|
|
295
262
|
const hot = label.slice(at, at + letter.length);
|
|
296
263
|
const after = label.slice(at + letter.length);
|
|
297
|
-
let out =
|
|
298
|
-
if (before) out += paint(before, mark.fgRgb, mark.bgRgb, color);
|
|
264
|
+
let out = paint(before, mark.fgRgb, mark.bgRgb, color);
|
|
299
265
|
out += paint(hot, mark.hotFg, mark.bgRgb, color, true);
|
|
300
|
-
|
|
301
|
-
return out;
|
|
266
|
+
return out + paint(after, mark.fgRgb, mark.bgRgb, color);
|
|
302
267
|
};
|
|
303
268
|
|
|
304
269
|
const footerIds = (hidden, extra, backId) => {
|
|
305
270
|
const ids = backId ? [backId] : [];
|
|
271
|
+
for (const add of extra) {
|
|
272
|
+
if (!ids.includes(add)) ids.push(add);
|
|
273
|
+
}
|
|
306
274
|
for (const id of ACTION_IDS) {
|
|
307
|
-
if (id
|
|
308
|
-
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
for (const add of extra) {
|
|
312
|
-
if (!ids.includes(add)) ids.push(add);
|
|
313
|
-
}
|
|
275
|
+
if (id === 'quit' || hidden.includes(id) || ids.includes(id)) continue;
|
|
276
|
+
ids.push(id);
|
|
314
277
|
}
|
|
315
278
|
return ids;
|
|
316
279
|
};
|
|
317
280
|
|
|
318
281
|
const layoutButtons = (width, options = {}) => {
|
|
319
|
-
const { compact = false, hidden = [], extra = [] } = options;
|
|
320
|
-
const {
|
|
321
|
-
const hint = mark || BACK_ARROW;
|
|
282
|
+
const { compact = false, hidden = [], extra = [], disabled = [] } = options;
|
|
283
|
+
const { backId = '', mark = BACK_ARROW } = options;
|
|
322
284
|
const ids = footerIds(hidden, extra, backId);
|
|
285
|
+
const limit = Math.max(0, width - BUTTON_EDGE);
|
|
323
286
|
const build = (short) => {
|
|
324
287
|
const hits = [];
|
|
325
288
|
const parts = [];
|
|
326
289
|
let x = 0;
|
|
327
|
-
const limit = Math.max(0, width - BUTTON_EDGE);
|
|
328
290
|
for (const id of ids) {
|
|
329
291
|
const back = id === backId;
|
|
330
292
|
const letter = back ? BACK_KEY : actionLetter(id);
|
|
331
|
-
const label = buttonLabel(id, short
|
|
332
|
-
const
|
|
333
|
-
const piece = `${gap}${label}`;
|
|
293
|
+
const label = back ? hintBody(mark) : buttonLabel(id, short);
|
|
294
|
+
const piece = `${buttonGap(parts.length)}${label}`;
|
|
334
295
|
const w = visibleWidth(piece);
|
|
335
296
|
if (x + w > limit && parts.length) break;
|
|
336
|
-
const off =
|
|
297
|
+
const off = disabled.includes(id);
|
|
337
298
|
if (!off) hits.push({ id, x0: x, x1: x + w });
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
piece,
|
|
341
|
-
letter,
|
|
342
|
-
label,
|
|
343
|
-
disabled: off,
|
|
344
|
-
back,
|
|
345
|
-
mark: back ? hint : '',
|
|
346
|
-
});
|
|
299
|
+
const hint = back ? mark : '';
|
|
300
|
+
parts.push({ id, piece, letter, label, disabled: off, back, mark: hint });
|
|
347
301
|
x += w;
|
|
348
302
|
}
|
|
349
|
-
return { hits, parts
|
|
303
|
+
return { hits, parts };
|
|
350
304
|
};
|
|
351
305
|
if (compact) return build(true);
|
|
352
306
|
const words = build(false);
|
|
@@ -355,48 +309,35 @@ const layoutButtons = (width, options = {}) => {
|
|
|
355
309
|
};
|
|
356
310
|
|
|
357
311
|
const paintButtons = (layout, width, color) => {
|
|
358
|
-
let out = '';
|
|
359
|
-
let used = 0;
|
|
360
312
|
const fgRgb = THEME.buttonFg;
|
|
361
313
|
const bgRgb = THEME.buttonBg;
|
|
314
|
+
let out = '';
|
|
315
|
+
let used = 0;
|
|
362
316
|
for (let i = 0; i < layout.parts.length; i++) {
|
|
363
317
|
const part = layout.parts[i];
|
|
364
|
-
|
|
365
|
-
out += paint(gap, fgRgb, bgRgb, color);
|
|
318
|
+
out += paint(buttonGap(i), fgRgb, bgRgb, color);
|
|
366
319
|
if (part.back) out += paintBackHint(color, part.mark);
|
|
367
320
|
else if (part.disabled) out += paint(part.label, fgRgb, bgRgb, color);
|
|
368
321
|
else out += paintMarkedWord(part.label, part.letter, color, BUTTON_MARK);
|
|
369
322
|
used += visibleWidth(part.piece);
|
|
370
323
|
}
|
|
371
|
-
|
|
372
|
-
out += fill(width - used, THEME.buttonFg, THEME.buttonBg, color);
|
|
373
|
-
}
|
|
374
|
-
return out;
|
|
324
|
+
return out + fill(width - used, fgRgb, bgRgb, color);
|
|
375
325
|
};
|
|
376
326
|
|
|
377
|
-
const isInfoStatus = (status) =>
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (status.startsWith(prefix)) return true;
|
|
381
|
-
}
|
|
382
|
-
return false;
|
|
383
|
-
};
|
|
327
|
+
const isInfoStatus = (status) =>
|
|
328
|
+
INFO_STATUS.includes(status) ||
|
|
329
|
+
INFO_PREFIX.some((prefix) => status.startsWith(prefix));
|
|
384
330
|
|
|
385
|
-
const joinStatus = (parts) =>
|
|
386
|
-
const bits = [];
|
|
387
|
-
for (const part of parts) {
|
|
388
|
-
if (!part) continue;
|
|
389
|
-
bits.push(part);
|
|
390
|
-
}
|
|
391
|
-
return bits.join(' ');
|
|
392
|
-
};
|
|
331
|
+
const joinStatus = (parts) => parts.filter(Boolean).join(' ');
|
|
393
332
|
|
|
394
333
|
const countsKind = (sourceKind, revShort) => {
|
|
395
334
|
if (sourceKind === 'pr' || sourceKind === 'mr') return sourceKind;
|
|
396
|
-
|
|
397
|
-
return 'worktree';
|
|
335
|
+
return revShort ? 'commit' : 'worktree';
|
|
398
336
|
};
|
|
399
337
|
|
|
338
|
+
const isWorktree = (view) =>
|
|
339
|
+
countsKind(view.sourceKind, view.revShort) === 'worktree';
|
|
340
|
+
|
|
400
341
|
const notesLine = (counts) => {
|
|
401
342
|
const feedback = counts.feedback ?? 0;
|
|
402
343
|
const tasks = counts.tasks ?? 0;
|
|
@@ -407,21 +348,16 @@ const notesLine = (counts) => {
|
|
|
407
348
|
const statusLead = (view) => {
|
|
408
349
|
const counts = view.counts ?? {};
|
|
409
350
|
const kind = countsKind(view.sourceKind, view.revShort);
|
|
410
|
-
if (kind === 'worktree') return branchLabel(view.branch
|
|
351
|
+
if (kind === 'worktree') return branchLabel(view.branch);
|
|
411
352
|
if (kind === 'commit') {
|
|
412
|
-
|
|
413
|
-
return `commit ${view.revShort} ${n}`;
|
|
353
|
+
return `commit ${view.revShort} ${counts.commit ?? 0}`;
|
|
414
354
|
}
|
|
415
|
-
const n = counts.pr ?? 0;
|
|
416
355
|
const label = view.sourceLabel || kind;
|
|
417
|
-
return `${kind} ${label} ${
|
|
356
|
+
return `${kind} ${label} ${counts.pr ?? 0}`;
|
|
418
357
|
};
|
|
419
358
|
|
|
420
|
-
const statusLeft = (view) =>
|
|
421
|
-
|
|
422
|
-
if (!body) return '';
|
|
423
|
-
return ` ${body}`;
|
|
424
|
-
};
|
|
359
|
+
const statusLeft = (view) =>
|
|
360
|
+
` ${joinStatus([statusLead(view), notesLine(view.counts ?? {})])}`;
|
|
425
361
|
|
|
426
362
|
const statusDelta = (total) => {
|
|
427
363
|
const stagedAdd = total.stagedAdded ?? 0;
|
|
@@ -433,28 +369,24 @@ const statusDelta = (total) => {
|
|
|
433
369
|
if (!hasDelta && !total.removed) return '';
|
|
434
370
|
const plus = `+${stagedAdd}/${stagedAdd + unstagedAdd}`;
|
|
435
371
|
const minus = `-${stagedDel}/${stagedDel + unstagedDel}`;
|
|
436
|
-
return
|
|
372
|
+
return `${plus} ${minus}`;
|
|
437
373
|
};
|
|
438
374
|
|
|
439
375
|
const statusStats = (view) => {
|
|
440
376
|
const counts = view.counts ?? {};
|
|
377
|
+
const staged = counts.staged ?? 0;
|
|
441
378
|
const total = fileTotals(view.files ?? []);
|
|
442
|
-
const counted = (counts.staged ?? 0) + (counts.unstaged ?? 0);
|
|
443
379
|
const hasGit =
|
|
444
380
|
total.remaining || total.staged || total.added || total.removed;
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
const git = joinStatus([statusDelta(total), `${n}/${m}`]);
|
|
449
|
-
if (!view.npmLogs) return git;
|
|
450
|
-
return joinStatus([view.npmLogs, git]);
|
|
381
|
+
const n = hasGit ? total.staged : staged;
|
|
382
|
+
const m = hasGit ? total.remaining : staged + (counts.unstaged ?? 0);
|
|
383
|
+
return joinStatus([view.npmLogs, statusDelta(total), `${n}/${m}`]);
|
|
451
384
|
};
|
|
452
385
|
|
|
453
386
|
const statusLayout = (view, status, width) => {
|
|
454
|
-
const
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
if (msg && !isInfoStatus(status)) msgFg = THEME.errorFg;
|
|
387
|
+
const msg = formatBusyStatus(status, view.progressFrame ?? 0);
|
|
388
|
+
const isError = msg && !isInfoStatus(status);
|
|
389
|
+
const msgFg = isError ? THEME.errorFg : THEME.chromeFg;
|
|
458
390
|
const stats = statusStats(view);
|
|
459
391
|
const right = stats ? `${stats} ` : '';
|
|
460
392
|
const rightW = visibleWidth(right);
|
|
@@ -470,60 +402,36 @@ const statusLayout = (view, status, width) => {
|
|
|
470
402
|
};
|
|
471
403
|
|
|
472
404
|
const choiceHits = (choices, prefix, y) => {
|
|
473
|
-
const { length } = choices;
|
|
474
|
-
const hits = new Array(length);
|
|
475
405
|
let x = visibleWidth(prefix);
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
const
|
|
479
|
-
const w = visibleWidth(piece);
|
|
480
|
-
hits[i] = { id: choice.letter, y, x0: x, x1: x + w };
|
|
406
|
+
return choices.map((choice) => {
|
|
407
|
+
const w = visibleWidth(`${choice.lead}${choice.label}`);
|
|
408
|
+
const hit = { id: choice.letter, y, x0: x, x1: x + w };
|
|
481
409
|
x += w;
|
|
482
|
-
|
|
483
|
-
|
|
410
|
+
return hit;
|
|
411
|
+
});
|
|
484
412
|
};
|
|
485
413
|
|
|
486
|
-
const paintChoicePrompt = (choices, width, color, prefix
|
|
414
|
+
const paintChoicePrompt = (choices, width, color, prefix) => {
|
|
487
415
|
const bgRgb = THEME.chromeBg;
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (!color) {
|
|
493
|
-
const pad = Math.max(0, width - visibleWidth(body));
|
|
494
|
-
return body + ' '.repeat(pad);
|
|
495
|
-
}
|
|
496
|
-
let out = '';
|
|
497
|
-
if (prefix) out += paint(prefix, THEME.mutedFg, bgRgb, color);
|
|
416
|
+
const body = `${prefix}${promptFromChoices(choices)}`;
|
|
417
|
+
const pad = Math.max(0, width - visibleWidth(body));
|
|
418
|
+
if (!color) return body + ' '.repeat(pad);
|
|
419
|
+
let out = paint(prefix, THEME.mutedFg, bgRgb, color);
|
|
498
420
|
for (const choice of choices) {
|
|
499
421
|
const label = `${choice.lead}${choice.label}`;
|
|
500
422
|
out += paintMarkedWord(label, choice.letter, color, QUIT_MARK);
|
|
501
423
|
}
|
|
502
|
-
const pad = Math.max(0, width - visibleWidth(body));
|
|
503
424
|
return out + fill(pad, THEME.mutedFg, bgRgb, color);
|
|
504
425
|
};
|
|
505
426
|
|
|
506
|
-
const STATUS_MARK = /(\+[0-9]+(?:\/[0-9]+)?|-[0-9]+(?:\/[0-9]+)?)/g;
|
|
507
|
-
const OLD_LOGS = /old logs \S+/;
|
|
508
|
-
|
|
509
|
-
const paintStatusMark = (token, color) => {
|
|
510
|
-
const bgRgb = THEME.chromeBg;
|
|
511
|
-
if (token.startsWith('+')) {
|
|
512
|
-
return paint(token, THEME.addLineFg, bgRgb, color);
|
|
513
|
-
}
|
|
514
|
-
return paint(token, THEME.delLineFg, bgRgb, color);
|
|
515
|
-
};
|
|
516
|
-
|
|
517
427
|
const paintStatusLeft = (text, color) => {
|
|
518
|
-
const bgRgb = THEME.chromeBg;
|
|
519
|
-
const muted = THEME.mutedFg;
|
|
520
428
|
if (!color) return text;
|
|
429
|
+
const bgRgb = THEME.chromeBg;
|
|
521
430
|
const found = text.match(OLD_LOGS);
|
|
522
431
|
if (found) {
|
|
523
|
-
const at = found.index;
|
|
524
432
|
const token = found[0];
|
|
525
|
-
const before = text.slice(0,
|
|
526
|
-
const after = text.slice(
|
|
433
|
+
const before = text.slice(0, found.index);
|
|
434
|
+
const after = text.slice(found.index + token.length);
|
|
527
435
|
return (
|
|
528
436
|
paintStatusLeft(before, color) +
|
|
529
437
|
paint(token, THEME.shaFg, bgRgb, color) +
|
|
@@ -534,24 +442,18 @@ const paintStatusLeft = (text, color) => {
|
|
|
534
442
|
let last = 0;
|
|
535
443
|
for (const match of text.matchAll(STATUS_MARK)) {
|
|
536
444
|
const token = match[0];
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
out += paintStatusMark(token, color);
|
|
542
|
-
last = start + token.length;
|
|
543
|
-
}
|
|
544
|
-
if (last < text.length) {
|
|
545
|
-
out += paint(text.slice(last), muted, bgRgb, color);
|
|
445
|
+
const tokenFg = token.startsWith('+') ? THEME.addLineFg : THEME.delLineFg;
|
|
446
|
+
out += paint(text.slice(last, match.index), THEME.mutedFg, bgRgb, color);
|
|
447
|
+
out += paint(token, tokenFg, bgRgb, color);
|
|
448
|
+
last = match.index + token.length;
|
|
546
449
|
}
|
|
547
|
-
return out;
|
|
450
|
+
return out + paint(text.slice(last), THEME.mutedFg, bgRgb, color);
|
|
548
451
|
};
|
|
549
452
|
|
|
550
453
|
const paintBranchHead = (text, branch, color) => {
|
|
551
454
|
const name = branchLabel(branch);
|
|
552
455
|
if (!name || !text.startsWith(' ')) return null;
|
|
553
|
-
const
|
|
554
|
-
const shown = text.startsWith(head) ? name : text.slice(1);
|
|
456
|
+
const shown = text.startsWith(` ${name}`) ? name : text.slice(1);
|
|
555
457
|
if (!shown || !name.startsWith(shown)) return null;
|
|
556
458
|
const rest = text.slice(1 + shown.length);
|
|
557
459
|
const bgRgb = THEME.chromeBg;
|
|
@@ -562,40 +464,23 @@ const paintBranchHead = (text, branch, color) => {
|
|
|
562
464
|
);
|
|
563
465
|
};
|
|
564
466
|
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const bits = source.split('**');
|
|
570
|
-
const parts = [];
|
|
571
|
-
for (let i = 0; i < bits.length; i++) {
|
|
572
|
-
if (!bits[i]) continue;
|
|
573
|
-
parts.push({ text: bits[i], hot: i % 2 === 1 });
|
|
574
|
-
}
|
|
575
|
-
return parts;
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
const saveHintText = () => SAVE_HINT.replaceAll('**', '');
|
|
579
|
-
|
|
580
|
-
const commitSaveHint = (view) => {
|
|
581
|
-
if (view.mode !== 'compose' || view.commitView !== 'full') return false;
|
|
582
|
-
const compose = view.compose;
|
|
583
|
-
return Boolean(compose && compose.kind === 'commit');
|
|
584
|
-
};
|
|
467
|
+
const commitSaveHint = (view) =>
|
|
468
|
+
view.mode === 'compose' &&
|
|
469
|
+
view.commitView === 'full' &&
|
|
470
|
+
view.compose?.kind === 'commit';
|
|
585
471
|
|
|
586
472
|
const paintSaveHintBar = (width, color) => {
|
|
587
473
|
const bgRgb = THEME.buttonBg;
|
|
588
|
-
const plain = `${BUTTON_LEAD}${
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
return plain + ' '.repeat(pad);
|
|
592
|
-
}
|
|
474
|
+
const plain = `${BUTTON_LEAD}${SAVE_HINT.replaceAll('**', '')}`;
|
|
475
|
+
const pad = Math.max(0, width - visibleWidth(plain));
|
|
476
|
+
if (!color) return plain + ' '.repeat(pad);
|
|
593
477
|
let out = paint(BUTTON_LEAD, THEME.buttonFg, bgRgb, color);
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
478
|
+
const bits = SAVE_HINT.split('**');
|
|
479
|
+
for (let i = 0; i < bits.length; i++) {
|
|
480
|
+
const hot = i % 2 === 1;
|
|
481
|
+
const tone = hot ? HINT_HOT_FG : THEME.buttonFg;
|
|
482
|
+
out += paint(bits[i], tone, bgRgb, color, hot);
|
|
597
483
|
}
|
|
598
|
-
const pad = Math.max(0, width - visibleWidth(plain));
|
|
599
484
|
return out + fill(pad, THEME.buttonFg, bgRgb, color);
|
|
600
485
|
};
|
|
601
486
|
|
|
@@ -604,10 +489,7 @@ const paintFooter = (view, layout, width, color) => {
|
|
|
604
489
|
return paintButtons(layout, width, color);
|
|
605
490
|
};
|
|
606
491
|
|
|
607
|
-
const footerHits = (view, layout) =>
|
|
608
|
-
if (commitSaveHint(view)) return [];
|
|
609
|
-
return layout.hits;
|
|
610
|
-
};
|
|
492
|
+
const footerHits = (view, layout) => (commitSaveHint(view) ? [] : layout.hits);
|
|
611
493
|
|
|
612
494
|
const paintStatusLine = (view, status, width, color) => {
|
|
613
495
|
const confirm = CONFIRM[view.mode];
|
|
@@ -622,8 +504,7 @@ const paintStatusLine = (view, status, width, color) => {
|
|
|
622
504
|
return layout.clipped + leftGap + layout.msg + rightGap + layout.right;
|
|
623
505
|
}
|
|
624
506
|
const bgRgb = THEME.chromeBg;
|
|
625
|
-
const
|
|
626
|
-
const head = worktree
|
|
507
|
+
const head = isWorktree(view)
|
|
627
508
|
? paintBranchHead(layout.clipped, view.branch, color)
|
|
628
509
|
: null;
|
|
629
510
|
const left = head ?? paintStatusLeft(layout.clipped, color);
|
|
@@ -639,79 +520,89 @@ const paintStatusLine = (view, status, width, color) => {
|
|
|
639
520
|
const statusChoiceHits = (view, y) => {
|
|
640
521
|
const spec = CONFIRM[view.mode];
|
|
641
522
|
if (!spec) return [];
|
|
642
|
-
|
|
643
|
-
return choiceHits(spec.choices, prefix, y);
|
|
523
|
+
return choiceHits(spec.choices, confirmPrefix(spec, view), y);
|
|
644
524
|
};
|
|
645
525
|
|
|
646
526
|
const statusBranchHit = (view, width, y) => {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (!branchLabel(branch)) return null;
|
|
651
|
-
if (countsKind(view.sourceKind, view.revShort) !== 'worktree') return null;
|
|
527
|
+
if (CONFIRM[view.mode]) return null;
|
|
528
|
+
const name = branchLabel(view.branch);
|
|
529
|
+
if (!name || !isWorktree(view)) return null;
|
|
652
530
|
const layout = statusLayout(view, view.status ?? '', width);
|
|
653
|
-
const name = branchLabel(branch);
|
|
654
531
|
const at = layout.clipped.indexOf(name);
|
|
655
532
|
if (at < 0) return null;
|
|
656
533
|
return { id: 'branch', y, x0: at, x1: at + visibleWidth(name) };
|
|
657
534
|
};
|
|
658
535
|
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
const selectedCommit = (view) => (view.commits ?? [])[view.commitCursor ?? 0];
|
|
536
|
+
const withHidden = (ids, more) => [...ids, ...more];
|
|
662
537
|
|
|
663
538
|
const hiddenActions = (view) => {
|
|
664
|
-
const pane = view
|
|
539
|
+
const { pane } = view;
|
|
540
|
+
if (pane === 'dashboard') return DASH_HIDDEN;
|
|
665
541
|
if (pane === 'files') return FILES_HIDDEN;
|
|
666
|
-
if (pane === 'unit') return UNIT_DISABLED;
|
|
542
|
+
if (pane === 'unit') return withHidden(UNIT_DISABLED, ['feedback', 'tasks']);
|
|
667
543
|
if (pane === 'branches') return BRANCHES_DISABLED;
|
|
668
544
|
if (pane === 'commits') return COMMITS_DISABLED;
|
|
669
545
|
if (pane === 'npm') return NPM_DISABLED;
|
|
670
|
-
if (
|
|
671
|
-
|
|
546
|
+
if (pane === 'tasks' || isTaskView(view)) {
|
|
547
|
+
return withHidden(TASKS_DISABLED, ['prev', 'next']);
|
|
548
|
+
}
|
|
549
|
+
return withHidden(DIFF_DISABLED, ['feedback', 'tasks']);
|
|
672
550
|
};
|
|
673
551
|
|
|
674
552
|
const dimFooterActions = (view) => {
|
|
675
553
|
const pane = view.pane ?? 'diff';
|
|
676
554
|
if (pane === 'files') {
|
|
677
|
-
|
|
678
|
-
const entry = files[view.fileCursor ?? 0];
|
|
679
|
-
if (!entry || entry.kind !== 'tasks') return [];
|
|
680
|
-
return FILES_GIT_DISABLED;
|
|
555
|
+
return isTasksEntry(selectedFile(view)) ? FILES_GIT_DISABLED : [];
|
|
681
556
|
}
|
|
682
557
|
if (pane === 'diff' || pane === 'unit') return diffGitDisabled(view.item);
|
|
683
558
|
if (pane === 'branches') return branchGitDisabled(selectedBranch(view));
|
|
684
559
|
if (pane === 'commits') {
|
|
685
|
-
const entry = selectedCommit(view);
|
|
686
|
-
const staged = (view.counts?.staged ?? 0) > 0;
|
|
687
|
-
const unstagedCurrent = !view.rev && !view.revShort;
|
|
688
560
|
return commitGitDisabled({
|
|
689
|
-
...
|
|
690
|
-
canCommit: staged,
|
|
691
|
-
unstagedCurrent,
|
|
561
|
+
...selectedCommit(view),
|
|
562
|
+
canCommit: (view.counts?.staged ?? 0) > 0,
|
|
563
|
+
unstagedCurrent: !view.rev && !view.revShort,
|
|
692
564
|
});
|
|
693
565
|
}
|
|
694
|
-
if (pane
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
if (pane === 'npm' && !view.npmLogs) return ['npmLogs'];
|
|
699
|
-
return [];
|
|
566
|
+
if (pane !== 'npm') return [];
|
|
567
|
+
if (view.npmView) return view.npmRunning ? ['npmRerun'] : [];
|
|
568
|
+
return view.npmLogs ? [] : ['npmLogs'];
|
|
700
569
|
};
|
|
701
570
|
|
|
571
|
+
const navExcept = (skip) => DASH_IDS.filter((id) => !skip.includes(id));
|
|
572
|
+
|
|
702
573
|
const extraFooterActions = (view) => {
|
|
703
|
-
const pane = view
|
|
704
|
-
if (pane === '
|
|
705
|
-
|
|
706
|
-
return [
|
|
574
|
+
const { pane } = view;
|
|
575
|
+
if (pane === 'dashboard') return DASH_IDS;
|
|
576
|
+
if (pane === 'branches') {
|
|
577
|
+
return [
|
|
578
|
+
...navExcept(['dashNpm']),
|
|
579
|
+
'newBranch',
|
|
580
|
+
'rebase',
|
|
581
|
+
'drop',
|
|
582
|
+
'pull',
|
|
583
|
+
'push',
|
|
584
|
+
];
|
|
585
|
+
}
|
|
586
|
+
if (pane === 'commits') {
|
|
587
|
+
return [
|
|
588
|
+
...navExcept(['dashCommits']),
|
|
589
|
+
'commit',
|
|
590
|
+
'amend',
|
|
591
|
+
'apply',
|
|
592
|
+
'reword',
|
|
593
|
+
'fixup',
|
|
594
|
+
'drop',
|
|
595
|
+
'view',
|
|
596
|
+
];
|
|
707
597
|
}
|
|
708
|
-
if (pane === 'branches') return Object.keys(BRANCH_ACTIONS);
|
|
709
|
-
if (pane === 'commits') return Object.keys(COMMIT_ACTIONS);
|
|
710
598
|
if (pane === 'npm') {
|
|
711
|
-
if (view.npmView)
|
|
712
|
-
|
|
599
|
+
if (view.npmView) {
|
|
600
|
+
return [...navExcept(['dashRun']), 'npmVerbose', 'npmRerun'];
|
|
601
|
+
}
|
|
602
|
+
return [...DASH_IDS, 'npmEdit', 'npmNew', 'npmDrop', 'npmLogs'];
|
|
713
603
|
}
|
|
714
|
-
return [];
|
|
604
|
+
if (pane === 'tasks' || isTaskView(view)) return [...DASH_IDS, 'drop'];
|
|
605
|
+
return navExcept(['dashDiffs']);
|
|
715
606
|
};
|
|
716
607
|
|
|
717
608
|
const footerLayout = (view, width) =>
|
|
@@ -724,10 +615,6 @@ const footerLayout = (view, width) =>
|
|
|
724
615
|
});
|
|
725
616
|
|
|
726
617
|
module.exports = {
|
|
727
|
-
QUIT_PROMPT,
|
|
728
|
-
PUSH_PROMPT,
|
|
729
|
-
updatePrompt,
|
|
730
|
-
dropPrompt,
|
|
731
618
|
formatBusyStatus,
|
|
732
619
|
headerText,
|
|
733
620
|
paintHeader,
|