reslop 0.2.4 → 0.2.5
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 +1 -2
- package/lib/capabilities.js +0 -4
- package/lib/clipboard.js +39 -1
- package/lib/deps-diff.js +0 -3
- package/lib/deps.js +144 -176
- package/lib/diff/inline.js +66 -1
- package/lib/diff/unit.js +11 -28
- package/lib/editor.js +69 -9
- package/lib/files.js +17 -16
- package/lib/git-deps.js +58 -95
- package/lib/github.js +7 -7
- package/lib/gitlab.js +3 -3
- package/lib/highlight/core.js +11 -0
- package/lib/highlight/dot.js +2 -12
- package/lib/highlight/log.js +4 -11
- package/lib/highlight/txt.js +2 -12
- package/lib/keys.js +22 -12
- package/lib/manifest.js +0 -4
- package/lib/npm-commands.js +1 -22
- package/lib/remote.js +1 -7
- package/lib/render/branches.js +4 -13
- package/lib/render/chrome.js +85 -31
- package/lib/render/commits.js +95 -207
- package/lib/render/diff.js +31 -1
- package/lib/render/files.js +7 -16
- package/lib/render/frame.js +95 -110
- package/lib/render/notes.js +71 -16
- package/lib/render/npm.js +104 -18
- package/lib/render/primitives.js +108 -45
- package/lib/render/unit.js +4 -1
- package/lib/report-parse.js +0 -1
- package/lib/report-run.js +0 -1
- package/lib/report-test.js +40 -47
- package/lib/report-tools.js +0 -7
- package/lib/review-merge.js +101 -131
- package/lib/review.js +64 -77
- package/lib/select.js +52 -0
- package/lib/session/actions.js +23 -22
- package/lib/session/branches.js +5 -3
- package/lib/session/change-actions.js +173 -146
- package/lib/session/commit.js +32 -13
- package/lib/session/compose.js +120 -77
- package/lib/session/dispatch.js +36 -21
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +24 -24
- package/lib/session/items.js +69 -89
- package/lib/session/lifecycle.js +31 -96
- package/lib/session/load.js +51 -58
- package/lib/session/navigation.js +105 -96
- package/lib/session/npm.js +158 -77
- package/lib/session/ops.js +192 -51
- package/lib/session/pointer.js +11 -5
- package/lib/session/progress.js +9 -6
- package/lib/session/review.js +35 -54
- package/lib/session/tasks.js +292 -0
- package/lib/session/terminal.js +13 -17
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +17 -14
- package/lib/session/watch.js +47 -27
- package/lib/session.js +34 -79
- package/lib/update.js +1 -5
- package/lib/utilities.js +21 -1
- package/lib/wrap.js +15 -0
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
3
6
|
const files = require('../files.js');
|
|
4
|
-
const { listPath,
|
|
7
|
+
const { listPath, isTaskItem, isTasksEntry, isReadOnlyOrigin } = files;
|
|
5
8
|
const items = require('./items.js');
|
|
6
9
|
const { needsReload, npmBusyKind, sameBlock } = items;
|
|
7
10
|
const diff = require('../diff/diff.js');
|
|
@@ -24,13 +27,63 @@ const COMMANDS = {
|
|
|
24
27
|
revert: {
|
|
25
28
|
match: () => true,
|
|
26
29
|
},
|
|
30
|
+
ignore: {
|
|
31
|
+
match: () => true,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const IGNORE_FILES = ['.gitignore', '.npmignore'];
|
|
36
|
+
|
|
37
|
+
const ignorePatternListed = (text, pattern) => {
|
|
38
|
+
for (const line of `${text ?? ''}`.split('\n')) {
|
|
39
|
+
if (line.trim() === pattern) return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const appendIgnorePattern = (text, pattern) => {
|
|
45
|
+
if (ignorePatternListed(text, pattern)) return text;
|
|
46
|
+
const base = text.length && !text.endsWith('\n') ? `${text}\n` : text;
|
|
47
|
+
return `${base}${pattern}\n`;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const appendIgnoreFile = (top, name, pattern) => {
|
|
51
|
+
const abs = path.join(top, name);
|
|
52
|
+
if (name === '.npmignore' && !fs.existsSync(abs)) return false;
|
|
53
|
+
const text = fs.existsSync(abs) ? fs.readFileSync(abs, 'utf8') : '';
|
|
54
|
+
const next = appendIgnorePattern(text, pattern);
|
|
55
|
+
if (next === text) return false;
|
|
56
|
+
fs.writeFileSync(abs, next);
|
|
57
|
+
return true;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const ignoreRelPath = (ui, rel) => {
|
|
61
|
+
const pattern = `${rel ?? ''}`.replace(/^\//, '');
|
|
62
|
+
if (!pattern) {
|
|
63
|
+
ui.status = 'not a diff block';
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let changed = false;
|
|
67
|
+
for (const name of IGNORE_FILES) {
|
|
68
|
+
if (appendIgnoreFile(ui.top, name, pattern)) changed = true;
|
|
69
|
+
}
|
|
70
|
+
if (!changed) {
|
|
71
|
+
ui.status = 'already ignored';
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
ui.ignoreWatch();
|
|
75
|
+
ui.nav.clearSelection();
|
|
76
|
+
ui.reloadAfterChange();
|
|
77
|
+
ui.status = 'ignored';
|
|
27
78
|
};
|
|
28
79
|
|
|
80
|
+
const sameEntry = (entry) => entry;
|
|
81
|
+
|
|
29
82
|
const keepOrigin = (ui, item, origin) => {
|
|
30
83
|
ui.collection.keepOrigin(item, origin);
|
|
31
84
|
const idx = ui.collection.findRestoredIndex({ ...item, origin });
|
|
32
85
|
if (idx >= 0) ui.nav.index = idx;
|
|
33
|
-
|
|
86
|
+
ui.ignoreWatch();
|
|
34
87
|
ui.nav.clearSelection();
|
|
35
88
|
ui.syncReviewPath();
|
|
36
89
|
ui.syncFileCursor();
|
|
@@ -43,11 +96,11 @@ const fileCursorEntry = (ui) => {
|
|
|
43
96
|
|
|
44
97
|
const fileActionItems = (ui) => {
|
|
45
98
|
const entry = fileCursorEntry(ui);
|
|
46
|
-
if (!entry ||
|
|
99
|
+
if (!entry || isTasksEntry(entry)) return [];
|
|
47
100
|
const rel = entry.path;
|
|
48
101
|
const selected = [];
|
|
49
102
|
for (const item of ui.items) {
|
|
50
|
-
if (
|
|
103
|
+
if (isTaskItem(item)) continue;
|
|
51
104
|
if (listPath(item) !== rel) continue;
|
|
52
105
|
selected.push(item);
|
|
53
106
|
}
|
|
@@ -57,7 +110,7 @@ const fileActionItems = (ui) => {
|
|
|
57
110
|
const activeDiffItem = (ui) => {
|
|
58
111
|
const item = ui.current();
|
|
59
112
|
if (!item) return null;
|
|
60
|
-
if (
|
|
113
|
+
if (isTaskItem(item)) {
|
|
61
114
|
ui.status = 'not a diff block';
|
|
62
115
|
return null;
|
|
63
116
|
}
|
|
@@ -140,13 +193,60 @@ const applyBlockAdd = (ui, item) => {
|
|
|
140
193
|
keepOrigin(ui, item, 'staged');
|
|
141
194
|
};
|
|
142
195
|
|
|
196
|
+
const enqueueOrigins = (ui, targets, spec) => {
|
|
197
|
+
const writes = new Array(targets.length);
|
|
198
|
+
for (let i = 0; i < targets.length; i++) {
|
|
199
|
+
const current = liveItem(ui, targets[i]);
|
|
200
|
+
writes[i] = current;
|
|
201
|
+
keepOrigin(ui, current, spec.originOf(current));
|
|
202
|
+
}
|
|
203
|
+
if (spec.afterUi) spec.afterUi();
|
|
204
|
+
if (!spec.busy) ui.status = spec.done;
|
|
205
|
+
ui.ops.enqueueLazy({
|
|
206
|
+
kind: spec.busy || spec.done,
|
|
207
|
+
done: spec.done,
|
|
208
|
+
reload: spec.reload === true,
|
|
209
|
+
write: async (top) => {
|
|
210
|
+
for (const item of writes) await spec.write(top, item);
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const stageLazy = (ui, targets, extra = {}) => {
|
|
216
|
+
const busy = extra.busy || '';
|
|
217
|
+
const repo = ui.repo;
|
|
218
|
+
enqueueOrigins(ui, targets, {
|
|
219
|
+
done: 'staged',
|
|
220
|
+
busy,
|
|
221
|
+
reload: extra.reload === true,
|
|
222
|
+
originOf: () => 'staged',
|
|
223
|
+
afterUi: extra.afterUi,
|
|
224
|
+
write: (top, item) => {
|
|
225
|
+
if (busy && repo.addAsync) return repo.addAsync(top, item);
|
|
226
|
+
return repo.add(top, item);
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const unstageLazy = (ui, targets, extra = {}) => {
|
|
232
|
+
const repo = ui.repo;
|
|
233
|
+
enqueueOrigins(ui, targets, {
|
|
234
|
+
done: 'unstaged',
|
|
235
|
+
busy: '',
|
|
236
|
+
originOf: nextUnstageOrigin,
|
|
237
|
+
afterUi: extra.afterUi,
|
|
238
|
+
write: (top, item) => repo.unstage(top, item),
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
|
|
143
242
|
const onBlockAdd = (ui, item) => {
|
|
144
243
|
const busy = npmBusyKind(item);
|
|
145
244
|
const repo = ui.repo;
|
|
146
|
-
if (ui.uiOpen
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
245
|
+
if (ui.uiOpen) {
|
|
246
|
+
return void stageLazy(ui, [item], {
|
|
247
|
+
busy,
|
|
248
|
+
reload: needsReload(item),
|
|
249
|
+
});
|
|
150
250
|
}
|
|
151
251
|
applyGit(
|
|
152
252
|
ui,
|
|
@@ -160,6 +260,7 @@ const onBlockAdd = (ui, item) => {
|
|
|
160
260
|
};
|
|
161
261
|
|
|
162
262
|
const onBlockUnstage = (ui, item) => {
|
|
263
|
+
if (ui.uiOpen) return void unstageLazy(ui, [item]);
|
|
163
264
|
const origin = nextUnstageOrigin(item);
|
|
164
265
|
const repo = ui.repo;
|
|
165
266
|
applyGit(
|
|
@@ -171,6 +272,12 @@ const onBlockUnstage = (ui, item) => {
|
|
|
171
272
|
);
|
|
172
273
|
};
|
|
173
274
|
|
|
275
|
+
const dismissReloadable = (ui, targets) => {
|
|
276
|
+
for (const item of targets) {
|
|
277
|
+
if (needsReload(item)) ui.collection.dismiss(item);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
174
281
|
const onBlockRevert = (ui, item) => {
|
|
175
282
|
const repo = ui.repo;
|
|
176
283
|
applyGit(
|
|
@@ -179,7 +286,7 @@ const onBlockRevert = (ui, item) => {
|
|
|
179
286
|
'dropped',
|
|
180
287
|
(top, current) => repo.revert(top, current),
|
|
181
288
|
() => {
|
|
182
|
-
|
|
289
|
+
dismissReloadable(ui, [item]);
|
|
183
290
|
ui.reloadAfterChange();
|
|
184
291
|
},
|
|
185
292
|
);
|
|
@@ -195,6 +302,7 @@ const onBlockCommand = (ui, name) => {
|
|
|
195
302
|
const command = COMMANDS[name];
|
|
196
303
|
const item = activeDiffItem(ui);
|
|
197
304
|
if (!guardWritable(ui, item)) return;
|
|
305
|
+
if (name === 'ignore') return void ignoreRelPath(ui, listPath(item));
|
|
198
306
|
if (!command.match(item)) {
|
|
199
307
|
ui.status = command.skipStatus;
|
|
200
308
|
return;
|
|
@@ -202,109 +310,83 @@ const onBlockCommand = (ui, name) => {
|
|
|
202
310
|
BLOCK[name](ui, item);
|
|
203
311
|
};
|
|
204
312
|
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
keepOrigin(ui, current, 'staged');
|
|
313
|
+
const stageTargets = (ui, targets, after = null) => {
|
|
314
|
+
const reload = targets.some(needsReload);
|
|
315
|
+
const busy = targets.map(npmBusyKind).find((kind) => kind) || '';
|
|
316
|
+
if (ui.uiOpen) {
|
|
317
|
+
return void stageLazy(ui, targets, { busy, reload, afterUi: after });
|
|
211
318
|
}
|
|
319
|
+
const keepStaged = (entry) => keepOrigin(ui, entry, 'staged');
|
|
320
|
+
const result = applyFileGit(ui, targets, 'staged', ui.repo.add, keepStaged);
|
|
321
|
+
if (reconcilePartial(ui, result)) return;
|
|
322
|
+
if (reload) ui.reloadAfterChange();
|
|
323
|
+
if (after) after();
|
|
212
324
|
};
|
|
213
325
|
|
|
214
|
-
const
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
selectNextFileAfter(ui, rel);
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
const onFileAdd = (ui) => {
|
|
222
|
-
const selected = fileActionItems(ui);
|
|
223
|
-
if (!selected.length) {
|
|
224
|
-
ui.status = 'not a diff block';
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (!guardWritable(ui, selected[0])) return;
|
|
228
|
-
const rel = listPath(selected[0]);
|
|
229
|
-
const targets = selected.filter(COMMANDS.add.match);
|
|
230
|
-
if (!targets.length) {
|
|
231
|
-
ui.status = 'already staged';
|
|
232
|
-
selectNextFileAfter(ui, rel);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
const proposed = targets.some(needsReload);
|
|
236
|
-
const busy = targets.map(npmBusyKind).find((kind) => kind);
|
|
237
|
-
const repo = ui.repo;
|
|
238
|
-
if (ui.uiOpen && busy && repo.addAsync) {
|
|
239
|
-
const write = writeFileAddAsync(ui, targets);
|
|
240
|
-
const after = afterFileAdd(ui, rel, proposed);
|
|
241
|
-
return void ui.ops.runBusy(busy, 'staged', write, after);
|
|
242
|
-
}
|
|
326
|
+
const unstageTargets = (ui, targets, after = null) => {
|
|
327
|
+
if (ui.uiOpen) return void unstageLazy(ui, targets, { afterUi: after });
|
|
328
|
+
const keepUnstaged = (entry) =>
|
|
329
|
+
keepOrigin(ui, entry, nextUnstageOrigin(entry));
|
|
243
330
|
const result = applyFileGit(
|
|
244
331
|
ui,
|
|
245
332
|
targets,
|
|
246
|
-
'
|
|
247
|
-
|
|
248
|
-
|
|
333
|
+
'unstaged',
|
|
334
|
+
ui.repo.unstage,
|
|
335
|
+
keepUnstaged,
|
|
249
336
|
);
|
|
250
337
|
if (reconcilePartial(ui, result)) return;
|
|
251
|
-
if (
|
|
252
|
-
selectNextFileAfter(ui, rel);
|
|
338
|
+
if (after) after();
|
|
253
339
|
};
|
|
254
340
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
if (!selected.length) {
|
|
258
|
-
ui.status = 'not a diff block';
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
if (!guardWritable(ui, selected[0])) return;
|
|
262
|
-
const rel = listPath(selected[0]);
|
|
263
|
-
const targets = selected.filter(COMMANDS.unstage.match);
|
|
264
|
-
if (!targets.length) {
|
|
265
|
-
ui.status = 'not staged';
|
|
266
|
-
selectNextFileAfter(ui, rel);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
const repo = ui.repo;
|
|
341
|
+
const revertTargets = (ui, targets) => {
|
|
342
|
+
dismissReloadable(ui, targets);
|
|
270
343
|
const result = applyFileGit(
|
|
271
344
|
ui,
|
|
272
345
|
targets,
|
|
273
|
-
'
|
|
274
|
-
|
|
275
|
-
|
|
346
|
+
'dropped',
|
|
347
|
+
ui.repo.revert,
|
|
348
|
+
sameEntry,
|
|
276
349
|
);
|
|
277
|
-
if (
|
|
278
|
-
|
|
350
|
+
if (!result.ok && !result.completed.length) return;
|
|
351
|
+
ui.reloadAfterChange();
|
|
279
352
|
};
|
|
280
353
|
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
if (!selected.length) {
|
|
284
|
-
ui.status = 'not a diff block';
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
if (!guardWritable(ui, selected[0])) return;
|
|
288
|
-
const rel = listPath(selected[0]);
|
|
289
|
-
for (const item of selected) {
|
|
290
|
-
if (needsReload(item)) ui.collection.dismiss(item);
|
|
291
|
-
}
|
|
292
|
-
let ok = false;
|
|
354
|
+
const revertFile = (ui, rel, selected, after) => {
|
|
355
|
+
dismissReloadable(ui, selected);
|
|
293
356
|
try {
|
|
294
357
|
ui.repo.revertFile(ui.top, rel, selected);
|
|
295
358
|
ui.status = 'dropped';
|
|
296
|
-
ok = true;
|
|
297
359
|
} catch (error) {
|
|
298
360
|
ui.status = error.message;
|
|
361
|
+
return void ui.reloadAfterChange();
|
|
299
362
|
}
|
|
300
|
-
const after = ok ? () => selectNextFileAfter(ui, rel) : null;
|
|
301
363
|
ui.reloadAfterChange(after);
|
|
302
364
|
};
|
|
303
365
|
|
|
304
|
-
const
|
|
305
|
-
add:
|
|
306
|
-
unstage:
|
|
307
|
-
revert:
|
|
366
|
+
const TARGETS = {
|
|
367
|
+
add: stageTargets,
|
|
368
|
+
unstage: unstageTargets,
|
|
369
|
+
revert: revertTargets,
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const onFileCommand = (ui, name) => {
|
|
373
|
+
const selected = fileActionItems(ui);
|
|
374
|
+
if (!selected.length) {
|
|
375
|
+
ui.status = 'not a diff block';
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (!guardWritable(ui, selected[0])) return;
|
|
379
|
+
const rel = listPath(selected[0]);
|
|
380
|
+
const next = () => selectNextFileAfter(ui, rel);
|
|
381
|
+
if (name === 'ignore') return void ignoreRelPath(ui, rel);
|
|
382
|
+
if (name === 'revert') return void revertFile(ui, rel, selected, next);
|
|
383
|
+
const command = COMMANDS[name];
|
|
384
|
+
const targets = selected.filter(command.match);
|
|
385
|
+
if (!targets.length) {
|
|
386
|
+
ui.status = command.skipStatus;
|
|
387
|
+
return void next();
|
|
388
|
+
}
|
|
389
|
+
TARGETS[name](ui, targets, next);
|
|
308
390
|
};
|
|
309
391
|
|
|
310
392
|
const hunkActionItems = (ui, item) => {
|
|
@@ -318,62 +400,6 @@ const hunkActionItems = (ui, item) => {
|
|
|
318
400
|
return selected;
|
|
319
401
|
};
|
|
320
402
|
|
|
321
|
-
const onUnitAdd = (ui, targets) => {
|
|
322
|
-
const proposed = targets.some(needsReload);
|
|
323
|
-
const busy = targets.map(npmBusyKind).find((kind) => kind);
|
|
324
|
-
const repo = ui.repo;
|
|
325
|
-
if (ui.uiOpen && busy && repo.addAsync) {
|
|
326
|
-
const write = writeFileAddAsync(ui, targets);
|
|
327
|
-
const after = () => {
|
|
328
|
-
if (proposed) ui.reloadAfterChange();
|
|
329
|
-
};
|
|
330
|
-
return void ui.ops.runBusy(busy, 'staged', write, after);
|
|
331
|
-
}
|
|
332
|
-
const result = applyFileGit(
|
|
333
|
-
ui,
|
|
334
|
-
targets,
|
|
335
|
-
'staged',
|
|
336
|
-
(top, current) => repo.add(top, current),
|
|
337
|
-
(entry) => keepOrigin(ui, entry, 'staged'),
|
|
338
|
-
);
|
|
339
|
-
if (reconcilePartial(ui, result)) return;
|
|
340
|
-
if (proposed) ui.reloadAfterChange();
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
const onUnitUnstage = (ui, targets) => {
|
|
344
|
-
const repo = ui.repo;
|
|
345
|
-
const result = applyFileGit(
|
|
346
|
-
ui,
|
|
347
|
-
targets,
|
|
348
|
-
'unstaged',
|
|
349
|
-
(top, current) => repo.unstage(top, current),
|
|
350
|
-
(entry) => keepOrigin(ui, entry, nextUnstageOrigin(entry)),
|
|
351
|
-
);
|
|
352
|
-
reconcilePartial(ui, result);
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
const onUnitRevert = (ui, targets) => {
|
|
356
|
-
for (const item of targets) {
|
|
357
|
-
if (needsReload(item)) ui.collection.dismiss(item);
|
|
358
|
-
}
|
|
359
|
-
const repo = ui.repo;
|
|
360
|
-
const result = applyFileGit(
|
|
361
|
-
ui,
|
|
362
|
-
targets,
|
|
363
|
-
'dropped',
|
|
364
|
-
(top, current) => repo.revert(top, current),
|
|
365
|
-
(entry) => entry,
|
|
366
|
-
);
|
|
367
|
-
if (!result.ok && !result.completed.length) return;
|
|
368
|
-
ui.reloadAfterChange();
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
const UNIT = {
|
|
372
|
-
add: onUnitAdd,
|
|
373
|
-
unstage: onUnitUnstage,
|
|
374
|
-
revert: onUnitRevert,
|
|
375
|
-
};
|
|
376
|
-
|
|
377
403
|
const onUnitCommand = (ui, name) => {
|
|
378
404
|
const command = COMMANDS[name];
|
|
379
405
|
const item = activeDiffItem(ui);
|
|
@@ -384,11 +410,11 @@ const onUnitCommand = (ui, name) => {
|
|
|
384
410
|
ui.status = command.skipStatus ?? 'not a diff block';
|
|
385
411
|
return;
|
|
386
412
|
}
|
|
387
|
-
|
|
413
|
+
TARGETS[name](ui, targets);
|
|
388
414
|
};
|
|
389
415
|
|
|
390
416
|
const onCommand = (ui, name) => {
|
|
391
|
-
if (ui.nav.pane === 'files') return void
|
|
417
|
+
if (ui.nav.pane === 'files') return void onFileCommand(ui, name);
|
|
392
418
|
if (ui.nav.pane === 'unit') return void onUnitCommand(ui, name);
|
|
393
419
|
onBlockCommand(ui, name);
|
|
394
420
|
};
|
|
@@ -398,6 +424,7 @@ const createChangeActions = (ui) => ({
|
|
|
398
424
|
onAdd: () => onCommand(ui, 'add'),
|
|
399
425
|
onUnstage: () => onCommand(ui, 'unstage'),
|
|
400
426
|
onRevert: () => onCommand(ui, 'revert'),
|
|
427
|
+
onIgnore: () => onCommand(ui, 'ignore'),
|
|
401
428
|
});
|
|
402
429
|
|
|
403
430
|
module.exports = { createChangeActions };
|
package/lib/session/commit.js
CHANGED
|
@@ -43,6 +43,13 @@ const briefCommit = (ui) => ui.commits.commitView !== 'full';
|
|
|
43
43
|
|
|
44
44
|
const joinMessage = (line, rest) => (rest ? `${line}\n${rest}` : line);
|
|
45
45
|
|
|
46
|
+
const tidyCommitMessage = (message) => {
|
|
47
|
+
const lines = `${message ?? ''}`.split('\n').map((line) => line.trim());
|
|
48
|
+
while (lines.length && lines[0] === '') lines.shift();
|
|
49
|
+
while (lines.length && lines[lines.length - 1] === '') lines.pop();
|
|
50
|
+
return lines.join('\n');
|
|
51
|
+
};
|
|
52
|
+
|
|
46
53
|
const keepBriefBody = (ui, text) => {
|
|
47
54
|
if (!briefCommit(ui)) return text;
|
|
48
55
|
const parts = splitMessage(text);
|
|
@@ -91,6 +98,24 @@ const clampCommitCursor = (api) => {
|
|
|
91
98
|
if (nav.commitCursor > last) nav.commitCursor = Math.max(0, last);
|
|
92
99
|
};
|
|
93
100
|
|
|
101
|
+
const commitIndexForView = (api) => {
|
|
102
|
+
const ui = api.ui;
|
|
103
|
+
if (hasStagedChanges(ui)) return 0;
|
|
104
|
+
const list = listedCommits(api.state.commits);
|
|
105
|
+
const want = `${ui.rev ?? ''}`;
|
|
106
|
+
const short = `${ui.revShort ?? ''}`;
|
|
107
|
+
if (!want && !short) return 0;
|
|
108
|
+
for (let i = 0; i < list.length; i++) {
|
|
109
|
+
const entry = list[i];
|
|
110
|
+
if (!entry || entry.pending) continue;
|
|
111
|
+
const sha = `${entry.sha ?? ''}`;
|
|
112
|
+
const brief = `${entry.shortSha ?? ''}`;
|
|
113
|
+
if (want && sha === want) return i;
|
|
114
|
+
if (short && (brief === short || sha.startsWith(short))) return i;
|
|
115
|
+
}
|
|
116
|
+
return 0;
|
|
117
|
+
};
|
|
118
|
+
|
|
94
119
|
const refreshCommitList = (api) => {
|
|
95
120
|
const repo = api.ui.repo;
|
|
96
121
|
if (!repo.listCommits) return;
|
|
@@ -121,10 +146,12 @@ const showCommits = (api) => {
|
|
|
121
146
|
api.ui.status = error.message;
|
|
122
147
|
return;
|
|
123
148
|
}
|
|
124
|
-
api.ui.nav
|
|
125
|
-
|
|
149
|
+
const nav = api.ui.nav;
|
|
150
|
+
nav.commitCursor = commitIndexForView(api);
|
|
151
|
+
nav.pane = 'commits';
|
|
152
|
+
nav.resetListScroll('commits');
|
|
126
153
|
api.ui.status = '';
|
|
127
|
-
|
|
154
|
+
nav.clearSelection();
|
|
128
155
|
};
|
|
129
156
|
|
|
130
157
|
const onCommitMove = (api, delta) => {
|
|
@@ -183,7 +210,7 @@ const onCommit = (api) => {
|
|
|
183
210
|
};
|
|
184
211
|
|
|
185
212
|
const openLoadedDiff = (ui) => {
|
|
186
|
-
ui.nav.
|
|
213
|
+
ui.nav.tasksOpen = false;
|
|
187
214
|
ui.nav.scroll = 0;
|
|
188
215
|
ui.nav.index = 0;
|
|
189
216
|
ui.nav.pane = ui.items.length ? 'diff' : 'files';
|
|
@@ -252,12 +279,6 @@ const onFixup = (api) => {
|
|
|
252
279
|
startGitCommit(api, 'fixup');
|
|
253
280
|
};
|
|
254
281
|
|
|
255
|
-
const cancelCommit = (api) => {
|
|
256
|
-
api.ui.mode = 'review';
|
|
257
|
-
api.ui.composer.state.commitKind = null;
|
|
258
|
-
api.ui.status = '';
|
|
259
|
-
};
|
|
260
|
-
|
|
261
282
|
const finishAsyncCommit = (api, kind, message, done, write) => {
|
|
262
283
|
const ui = api.ui;
|
|
263
284
|
ui.composer.closeCompose();
|
|
@@ -321,6 +342,7 @@ const finishGitCommit = (api) => {
|
|
|
321
342
|
if (isInPlaceCommit(kind) && briefCommit(ui)) {
|
|
322
343
|
message = joinMessage(message, ui.composer.state.commitBody);
|
|
323
344
|
}
|
|
345
|
+
message = tidyCommitMessage(message);
|
|
324
346
|
if (!message.trim()) {
|
|
325
347
|
ui.status = 'empty commit message';
|
|
326
348
|
return;
|
|
@@ -412,8 +434,6 @@ const createCommitController = (ui) => {
|
|
|
412
434
|
onCommitMove: (delta) => onCommitMove(api, delta),
|
|
413
435
|
onShowDiff: () => showSelectedDiff(api),
|
|
414
436
|
onView: () => onView(api),
|
|
415
|
-
cancelCommit: () => cancelCommit(api),
|
|
416
|
-
startGitCommit: (kind) => startGitCommit(api, kind),
|
|
417
437
|
finishGitCommit: () => finishGitCommit(api),
|
|
418
438
|
refresh: () => refreshCommitList(api),
|
|
419
439
|
onDropCommit: () => onDropCommit(api),
|
|
@@ -425,7 +445,6 @@ const createCommitController = (ui) => {
|
|
|
425
445
|
};
|
|
426
446
|
|
|
427
447
|
module.exports = {
|
|
428
|
-
COMMIT_STATUS,
|
|
429
448
|
hasStagedChanges,
|
|
430
449
|
createCommitController,
|
|
431
450
|
listedCommits,
|