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.
Files changed (109) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/LICENSE +1 -1
  3. package/README.md +12 -13
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +32 -19
  6. package/lib/capabilities.js +8 -12
  7. package/lib/cli.js +40 -74
  8. package/lib/clipboard.js +48 -18
  9. package/lib/dashboard/git.js +128 -0
  10. package/lib/dashboard/model.js +332 -0
  11. package/lib/dashboard/npm.js +193 -0
  12. package/lib/dashboard/tree.js +278 -0
  13. package/lib/deps-diff.js +196 -404
  14. package/lib/deps.js +240 -399
  15. package/lib/detect.js +8 -18
  16. package/lib/diff/align.js +41 -113
  17. package/lib/diff/diff.js +12 -43
  18. package/lib/diff/display.js +25 -36
  19. package/lib/diff/edit.js +6 -20
  20. package/lib/diff/inline.js +138 -141
  21. package/lib/diff/items.js +33 -47
  22. package/lib/diff/parse.js +28 -56
  23. package/lib/diff/patch.js +12 -33
  24. package/lib/diff/unit.js +90 -206
  25. package/lib/editor.js +98 -55
  26. package/lib/files.js +86 -103
  27. package/lib/git-branches.js +254 -416
  28. package/lib/git-deps.js +182 -344
  29. package/lib/git-reword-todo.js +5 -13
  30. package/lib/git-worktree.js +141 -212
  31. package/lib/git.js +21 -49
  32. package/lib/github.js +67 -181
  33. package/lib/gitlab.js +40 -90
  34. package/lib/highlight/bash.js +55 -177
  35. package/lib/highlight/core.js +157 -132
  36. package/lib/highlight/css.js +25 -58
  37. package/lib/highlight/csv.js +19 -37
  38. package/lib/highlight/dart.js +72 -213
  39. package/lib/highlight/dot.js +16 -26
  40. package/lib/highlight/html.js +42 -63
  41. package/lib/highlight/js.js +177 -506
  42. package/lib/highlight/json.js +17 -37
  43. package/lib/highlight/log.js +22 -35
  44. package/lib/highlight/txt.js +9 -22
  45. package/lib/highlight.js +17 -46
  46. package/lib/keys.js +62 -85
  47. package/lib/manifest.js +67 -130
  48. package/lib/npm-commands.js +119 -189
  49. package/lib/remote.js +141 -197
  50. package/lib/render/branches.js +66 -73
  51. package/lib/render/chrome.js +264 -323
  52. package/lib/render/commits.js +187 -500
  53. package/lib/render/dash-activity.js +212 -0
  54. package/lib/render/dash-blocks.js +245 -0
  55. package/lib/render/dash-table.js +290 -0
  56. package/lib/render/dashboard.js +62 -0
  57. package/lib/render/diff.js +123 -228
  58. package/lib/render/files.js +45 -99
  59. package/lib/render/frame.js +129 -183
  60. package/lib/render/notes.js +144 -160
  61. package/lib/render/npm.js +234 -112
  62. package/lib/render/present.js +4 -11
  63. package/lib/render/primitives.js +131 -170
  64. package/lib/render/render.js +5 -14
  65. package/lib/render/report.js +43 -0
  66. package/lib/render/tiles.js +260 -0
  67. package/lib/render/unit.js +15 -28
  68. package/lib/report-model.js +110 -33
  69. package/lib/report-parse.js +56 -38
  70. package/lib/report-render.js +102 -59
  71. package/lib/report-run.js +87 -78
  72. package/lib/report-test.js +256 -141
  73. package/lib/report-tools.js +96 -161
  74. package/lib/review-merge.js +114 -152
  75. package/lib/review.js +115 -189
  76. package/lib/runs.js +225 -0
  77. package/lib/select.js +89 -75
  78. package/lib/session/accessors.js +14 -21
  79. package/lib/session/actions.js +82 -63
  80. package/lib/session/branches.js +193 -247
  81. package/lib/session/change-actions.js +171 -214
  82. package/lib/session/commit.js +280 -342
  83. package/lib/session/compose.js +559 -674
  84. package/lib/session/dashboard.js +385 -0
  85. package/lib/session/dispatch.js +164 -157
  86. package/lib/session/edit-click.js +57 -0
  87. package/lib/session/files-pane.js +85 -53
  88. package/lib/session/items.js +73 -104
  89. package/lib/session/lifecycle.js +403 -541
  90. package/lib/session/load.js +48 -68
  91. package/lib/session/navigation.js +96 -87
  92. package/lib/session/npm.js +409 -345
  93. package/lib/session/ops.js +196 -63
  94. package/lib/session/pointer.js +23 -15
  95. package/lib/session/progress.js +33 -21
  96. package/lib/session/review.js +33 -54
  97. package/lib/session/tasks.js +333 -0
  98. package/lib/session/templates.js +51 -59
  99. package/lib/session/terminal.js +85 -136
  100. package/lib/session/unit.js +3 -4
  101. package/lib/session/update.js +76 -97
  102. package/lib/session/view.js +52 -83
  103. package/lib/session/watch.js +208 -204
  104. package/lib/session.js +112 -237
  105. package/lib/update.js +45 -116
  106. package/lib/utilities.js +67 -89
  107. package/lib/wrap.js +33 -44
  108. package/package.json +1 -1
  109. package/lib/session/todos.js +0 -293
@@ -1,16 +1,17 @@
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, isTodoItem, isTodosEntry, isReadOnlyOrigin } = files;
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');
8
11
  const { hunkKey } = diff;
9
12
 
10
- const nextUnstageOrigin = (item) => {
11
- if (item.file.isNew === true) return 'untracked';
12
- return 'unstaged';
13
- };
13
+ const nextUnstageOrigin = (item) =>
14
+ item.file.isNew === true ? 'untracked' : 'unstaged';
14
15
 
15
16
  const COMMANDS = {
16
17
  add: {
@@ -24,40 +25,64 @@ const COMMANDS = {
24
25
  revert: {
25
26
  match: () => true,
26
27
  },
28
+ ignore: {
29
+ match: () => true,
30
+ },
31
+ };
32
+
33
+ const IGNORE_FILES = ['.gitignore', '.npmignore'];
34
+
35
+ const appendIgnoreFile = (top, name, pattern) => {
36
+ const abs = path.join(top, name);
37
+ const exists = fs.existsSync(abs);
38
+ if (name === '.npmignore' && !exists) return false;
39
+ const text = exists ? fs.readFileSync(abs, 'utf8') : '';
40
+ const lines = text.split('\n');
41
+ if (lines.some((line) => line.trim() === pattern)) return false;
42
+ const base = text && !text.endsWith('\n') ? `${text}\n` : text;
43
+ fs.writeFileSync(abs, `${base}${pattern}\n`);
44
+ return true;
45
+ };
46
+
47
+ const ignoreRelPath = (ui, rel) => {
48
+ const pattern = `${rel ?? ''}`.replace(/^\//, '');
49
+ if (!pattern) {
50
+ ui.status = 'not a diff block';
51
+ return;
52
+ }
53
+ const append = (name) => appendIgnoreFile(ui.top, name, pattern);
54
+ if (!IGNORE_FILES.map(append).includes(true)) {
55
+ ui.status = 'already ignored';
56
+ return;
57
+ }
58
+ ui.ignoreWatch();
59
+ ui.nav.clearSelection();
60
+ ui.reloadAfterChange();
61
+ ui.status = 'ignored';
27
62
  };
28
63
 
29
64
  const keepOrigin = (ui, item, origin) => {
30
65
  ui.collection.keepOrigin(item, origin);
31
66
  const idx = ui.collection.findRestoredIndex({ ...item, origin });
32
67
  if (idx >= 0) ui.nav.index = idx;
33
- if (ui.ignoreWatch) ui.ignoreWatch();
68
+ ui.ignoreWatch();
34
69
  ui.nav.clearSelection();
35
70
  ui.syncReviewPath();
36
71
  ui.syncFileCursor();
37
72
  };
38
73
 
39
- const fileCursorEntry = (ui) => {
40
- const list = ui.fileList();
41
- return list[ui.nav.fileCursor] ?? null;
42
- };
43
-
44
74
  const fileActionItems = (ui) => {
45
- const entry = fileCursorEntry(ui);
46
- if (!entry || isTodosEntry(entry)) return [];
47
- const rel = entry.path;
48
- const selected = [];
49
- for (const item of ui.items) {
50
- if (isTodoItem(item)) continue;
51
- if (listPath(item) !== rel) continue;
52
- selected.push(item);
53
- }
54
- return selected;
75
+ const entry = ui.fileCursorEntry();
76
+ if (!entry || isTasksEntry(entry)) return [];
77
+ return ui.items.filter(
78
+ (item) => !isTaskItem(item) && listPath(item) === entry.path,
79
+ );
55
80
  };
56
81
 
57
82
  const activeDiffItem = (ui) => {
58
83
  const item = ui.current();
59
84
  if (!item) return null;
60
- if (isTodoItem(item)) {
85
+ if (isTaskItem(item)) {
61
86
  ui.status = 'not a diff block';
62
87
  return null;
63
88
  }
@@ -91,16 +116,12 @@ const selectNextFileAfter = (ui, rel) => {
91
116
  nav.index = entry.firstIndex;
92
117
  };
93
118
 
94
- const liveItem = (ui, item) => {
95
- for (const entry of ui.items) {
96
- if (sameBlock(entry, item)) return entry;
97
- }
98
- return item;
99
- };
119
+ const liveItem = (ui, item) =>
120
+ ui.items.find((entry) => sameBlock(entry, item)) ?? item;
100
121
 
101
- const applyGit = (ui, item, label, write, after) => {
122
+ const applyGit = (ui, label, write, after) => {
102
123
  try {
103
- write(ui.top, item);
124
+ write(ui.top);
104
125
  ui.status = label;
105
126
  after();
106
127
  } catch (error) {
@@ -108,78 +129,114 @@ const applyGit = (ui, item, label, write, after) => {
108
129
  }
109
130
  };
110
131
 
111
- const applyFileGit = (ui, targets, label, write, afterItem) => {
112
- const { length } = targets;
113
- const completed = new Array(length);
114
- let n = 0;
132
+ const applyFileGit = (ui, targets, label, write, afterItem = () => {}) => {
133
+ let written = 0;
115
134
  try {
116
- for (let i = 0; i < length; i++) {
117
- const current = liveItem(ui, targets[i]);
135
+ for (const target of targets) {
136
+ const current = liveItem(ui, target);
118
137
  write(ui.top, current);
119
138
  afterItem(current);
120
- completed[n++] = current;
139
+ written++;
121
140
  }
122
- completed.length = n;
123
141
  ui.status = label;
124
- return { ok: true, completed };
142
+ return { ok: true, written };
125
143
  } catch (error) {
126
- completed.length = n;
127
144
  ui.status = error.message;
128
- return { ok: false, completed };
145
+ return { ok: false, written };
129
146
  }
130
147
  };
131
148
 
132
149
  const reconcilePartial = (ui, result) => {
133
150
  if (result.ok) return false;
134
- if (result.completed.length) ui.reloadAfterChange();
151
+ if (result.written) ui.reloadAfterChange();
135
152
  return true;
136
153
  };
137
154
 
138
- const applyBlockAdd = (ui, item) => {
139
- if (needsReload(item)) return void ui.reloadAfterChange();
140
- keepOrigin(ui, item, 'staged');
155
+ const enqueueOrigins = (ui, targets, spec) => {
156
+ const writes = targets.map((target) => {
157
+ const item = liveItem(ui, target);
158
+ keepOrigin(ui, item, spec.originOf(item));
159
+ return item;
160
+ });
161
+ if (spec.afterUi) spec.afterUi();
162
+ if (!spec.busy) ui.status = spec.done;
163
+ ui.ops.enqueueLazy({
164
+ kind: spec.busy || spec.done,
165
+ done: spec.done,
166
+ reload: spec.reload === true,
167
+ write: async (top) => {
168
+ for (const item of writes) await spec.write(top, item);
169
+ },
170
+ });
171
+ };
172
+
173
+ const stageLazy = (ui, targets, extra = {}) => {
174
+ const busy = extra.busy || '';
175
+ const repo = ui.repo;
176
+ enqueueOrigins(ui, targets, {
177
+ done: 'staged',
178
+ busy,
179
+ reload: extra.reload === true,
180
+ originOf: () => 'staged',
181
+ afterUi: extra.afterUi,
182
+ write: (top, item) => {
183
+ if (busy && repo.addAsync) return repo.addAsync(top, item);
184
+ return repo.add(top, item);
185
+ },
186
+ });
141
187
  };
142
188
 
143
- const onBlockAdd = (ui, item) => {
144
- const busy = npmBusyKind(item);
189
+ const unstageLazy = (ui, targets, extra = {}) => {
145
190
  const repo = ui.repo;
146
- if (ui.uiOpen && busy && repo.addAsync) {
147
- const after = () => applyBlockAdd(ui, item);
148
- const write = (top) => repo.addAsync(top, item);
149
- return void ui.ops.runBusy(busy, 'staged', write, after);
191
+ enqueueOrigins(ui, targets, {
192
+ done: 'unstaged',
193
+ busy: '',
194
+ originOf: nextUnstageOrigin,
195
+ afterUi: extra.afterUi,
196
+ write: (top, item) => repo.unstage(top, item),
197
+ });
198
+ };
199
+
200
+ const dismissReloadable = (ui, targets) => {
201
+ for (const item of targets) {
202
+ if (needsReload(item)) ui.collection.dismiss(item);
203
+ }
204
+ };
205
+
206
+ const onBlockAdd = (ui, item) => {
207
+ const reload = needsReload(item);
208
+ if (ui.uiOpen) {
209
+ return void stageLazy(ui, [item], { busy: npmBusyKind(item), reload });
150
210
  }
151
211
  applyGit(
152
212
  ui,
153
- item,
154
213
  'staged',
155
- (top, current) => repo.add(top, current),
214
+ (top) => ui.repo.add(top, item),
156
215
  () => {
157
- applyBlockAdd(ui, item);
216
+ if (reload) ui.reloadAfterChange();
217
+ else keepOrigin(ui, item, 'staged');
158
218
  },
159
219
  );
160
220
  };
161
221
 
162
222
  const onBlockUnstage = (ui, item) => {
223
+ if (ui.uiOpen) return void unstageLazy(ui, [item]);
163
224
  const origin = nextUnstageOrigin(item);
164
- const repo = ui.repo;
165
225
  applyGit(
166
226
  ui,
167
- item,
168
227
  'unstaged',
169
- (top, current) => repo.unstage(top, current),
228
+ (top) => ui.repo.unstage(top, item),
170
229
  () => keepOrigin(ui, item, origin),
171
230
  );
172
231
  };
173
232
 
174
233
  const onBlockRevert = (ui, item) => {
175
- const repo = ui.repo;
176
234
  applyGit(
177
235
  ui,
178
- item,
179
236
  'dropped',
180
- (top, current) => repo.revert(top, current),
237
+ (top) => ui.repo.revert(top, item),
181
238
  () => {
182
- if (needsReload(item)) ui.collection.dismiss(item);
239
+ dismissReloadable(ui, [item]);
183
240
  ui.reloadAfterChange();
184
241
  },
185
242
  );
@@ -195,6 +252,7 @@ const onBlockCommand = (ui, name) => {
195
252
  const command = COMMANDS[name];
196
253
  const item = activeDiffItem(ui);
197
254
  if (!guardWritable(ui, item)) return;
255
+ if (name === 'ignore') return void ignoreRelPath(ui, listPath(item));
198
256
  if (!command.match(item)) {
199
257
  ui.status = command.skipStatus;
200
258
  return;
@@ -202,176 +260,82 @@ const onBlockCommand = (ui, name) => {
202
260
  BLOCK[name](ui, item);
203
261
  };
204
262
 
205
- const writeFileAddAsync = (ui, targets) => async (top) => {
206
- const repo = ui.repo;
207
- for (const item of targets) {
208
- const current = liveItem(ui, item);
209
- await repo.addAsync(top, current);
210
- keepOrigin(ui, current, 'staged');
211
- }
212
- };
213
-
214
- const afterFileAdd = (ui, rel, proposed) => () => {
215
- if (proposed) {
216
- return void ui.reloadAfterChange(() => selectNextFileAfter(ui, rel));
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;
263
+ const stageTargets = (ui, targets, after = null) => {
264
+ const reload = targets.some(needsReload);
265
+ const busy = targets.map(npmBusyKind).find((kind) => kind) || '';
266
+ if (ui.uiOpen) {
267
+ return void stageLazy(ui, targets, { busy, reload, afterUi: after });
234
268
  }
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
- }
243
- const result = applyFileGit(
244
- ui,
245
- targets,
246
- 'staged',
247
- (top, current) => repo.add(top, current),
248
- (item) => keepOrigin(ui, item, 'staged'),
249
- );
269
+ const keepStaged = (entry) => keepOrigin(ui, entry, 'staged');
270
+ const result = applyFileGit(ui, targets, 'staged', ui.repo.add, keepStaged);
250
271
  if (reconcilePartial(ui, result)) return;
251
- if (proposed) ui.reloadAfterChange();
252
- selectNextFileAfter(ui, rel);
272
+ if (reload) ui.reloadAfterChange();
273
+ if (after) after();
253
274
  };
254
275
 
255
- const onFileUnstage = (ui) => {
256
- const selected = fileActionItems(ui);
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;
276
+ const unstageTargets = (ui, targets, after = null) => {
277
+ if (ui.uiOpen) return void unstageLazy(ui, targets, { afterUi: after });
278
+ const keepUnstaged = (entry) =>
279
+ keepOrigin(ui, entry, nextUnstageOrigin(entry));
270
280
  const result = applyFileGit(
271
281
  ui,
272
282
  targets,
273
283
  'unstaged',
274
- (top, current) => repo.unstage(top, current),
275
- (item) => keepOrigin(ui, item, nextUnstageOrigin(item)),
284
+ ui.repo.unstage,
285
+ keepUnstaged,
276
286
  );
277
287
  if (reconcilePartial(ui, result)) return;
278
- selectNextFileAfter(ui, rel);
288
+ if (after) after();
279
289
  };
280
290
 
281
- const onFileRevert = (ui) => {
282
- const selected = fileActionItems(ui);
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;
291
+ const revertTargets = (ui, targets) => {
292
+ dismissReloadable(ui, targets);
293
+ const result = applyFileGit(ui, targets, 'dropped', ui.repo.revert);
294
+ if (!result.ok && !result.written) return;
295
+ ui.reloadAfterChange();
296
+ };
297
+
298
+ const revertFile = (ui, rel, selected, after) => {
299
+ dismissReloadable(ui, selected);
293
300
  try {
294
301
  ui.repo.revertFile(ui.top, rel, selected);
295
302
  ui.status = 'dropped';
296
- ok = true;
297
303
  } catch (error) {
298
304
  ui.status = error.message;
305
+ return void ui.reloadAfterChange();
299
306
  }
300
- const after = ok ? () => selectNextFileAfter(ui, rel) : null;
301
307
  ui.reloadAfterChange(after);
302
308
  };
303
309
 
304
- const FILE = {
305
- add: onFileAdd,
306
- unstage: onFileUnstage,
307
- revert: onFileRevert,
308
- };
309
-
310
- const hunkActionItems = (ui, item) => {
311
- const key = hunkKey(item);
312
- const selected = [];
313
- if (!key) return selected;
314
- for (const entry of ui.items) {
315
- if (hunkKey(entry) !== key) continue;
316
- selected.push(entry);
317
- }
318
- return selected;
310
+ const TARGETS = {
311
+ add: stageTargets,
312
+ unstage: unstageTargets,
313
+ revert: revertTargets,
319
314
  };
320
315
 
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);
316
+ const onFileCommand = (ui, name) => {
317
+ const selected = fileActionItems(ui);
318
+ if (!selected.length) {
319
+ ui.status = 'not a diff block';
320
+ return;
331
321
  }
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);
322
+ if (!guardWritable(ui, selected[0])) return;
323
+ const rel = listPath(selected[0]);
324
+ const next = () => selectNextFileAfter(ui, rel);
325
+ if (name === 'ignore') return void ignoreRelPath(ui, rel);
326
+ if (name === 'revert') return void revertFile(ui, rel, selected, next);
327
+ const command = COMMANDS[name];
328
+ const targets = selected.filter(command.match);
329
+ if (!targets.length) {
330
+ ui.status = command.skipStatus;
331
+ return void next();
358
332
  }
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();
333
+ TARGETS[name](ui, targets, next);
369
334
  };
370
335
 
371
- const UNIT = {
372
- add: onUnitAdd,
373
- unstage: onUnitUnstage,
374
- revert: onUnitRevert,
336
+ const hunkActionItems = (ui, item) => {
337
+ const key = hunkKey(item);
338
+ return key ? ui.items.filter((entry) => hunkKey(entry) === key) : [];
375
339
  };
376
340
 
377
341
  const onUnitCommand = (ui, name) => {
@@ -384,20 +348,13 @@ const onUnitCommand = (ui, name) => {
384
348
  ui.status = command.skipStatus ?? 'not a diff block';
385
349
  return;
386
350
  }
387
- UNIT[name](ui, targets);
351
+ TARGETS[name](ui, targets);
388
352
  };
389
353
 
390
354
  const onCommand = (ui, name) => {
391
- if (ui.nav.pane === 'files') return void FILE[name](ui);
355
+ if (ui.nav.pane === 'files') return void onFileCommand(ui, name);
392
356
  if (ui.nav.pane === 'unit') return void onUnitCommand(ui, name);
393
357
  onBlockCommand(ui, name);
394
358
  };
395
359
 
396
- const createChangeActions = (ui) => ({
397
- fileCursorEntry: () => fileCursorEntry(ui),
398
- onAdd: () => onCommand(ui, 'add'),
399
- onUnstage: () => onCommand(ui, 'unstage'),
400
- onRevert: () => onCommand(ui, 'revert'),
401
- });
402
-
403
- module.exports = { createChangeActions };
360
+ module.exports = { onCommand };