reslop 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -1
- package/LICENSE +1 -1
- package/README.md +12 -13
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -12
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +48 -18
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +332 -0
- package/lib/dashboard/npm.js +193 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +196 -404
- package/lib/deps.js +240 -399
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +138 -141
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +90 -206
- package/lib/editor.js +98 -55
- package/lib/files.js +86 -103
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +182 -344
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +141 -212
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +157 -132
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +16 -26
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +22 -35
- package/lib/highlight/txt.js +9 -22
- package/lib/highlight.js +17 -46
- package/lib/keys.js +62 -85
- package/lib/manifest.js +67 -130
- package/lib/npm-commands.js +119 -189
- package/lib/remote.js +141 -197
- package/lib/render/branches.js +66 -73
- package/lib/render/chrome.js +264 -323
- package/lib/render/commits.js +187 -500
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +245 -0
- package/lib/render/dash-table.js +290 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -228
- package/lib/render/files.js +45 -99
- package/lib/render/frame.js +129 -183
- package/lib/render/notes.js +144 -160
- package/lib/render/npm.js +234 -112
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +131 -170
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/tiles.js +260 -0
- package/lib/render/unit.js +15 -28
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -38
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -78
- package/lib/report-test.js +256 -141
- package/lib/report-tools.js +96 -161
- package/lib/review-merge.js +114 -152
- package/lib/review.js +115 -189
- package/lib/runs.js +225 -0
- package/lib/select.js +89 -75
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +82 -63
- package/lib/session/branches.js +193 -247
- package/lib/session/change-actions.js +171 -214
- package/lib/session/commit.js +280 -342
- package/lib/session/compose.js +559 -674
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +164 -157
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +85 -53
- package/lib/session/items.js +73 -104
- package/lib/session/lifecycle.js +403 -541
- package/lib/session/load.js +48 -68
- package/lib/session/navigation.js +96 -87
- package/lib/session/npm.js +409 -345
- package/lib/session/ops.js +196 -63
- package/lib/session/pointer.js +23 -15
- package/lib/session/progress.js +33 -21
- package/lib/session/review.js +33 -54
- package/lib/session/tasks.js +333 -0
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -136
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +52 -83
- package/lib/session/watch.js +208 -204
- package/lib/session.js +112 -237
- package/lib/update.js +45 -116
- package/lib/utilities.js +67 -89
- package/lib/wrap.js +33 -44
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
46
|
-
if (!entry ||
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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 (
|
|
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
|
-
|
|
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,
|
|
122
|
+
const applyGit = (ui, label, write, after) => {
|
|
102
123
|
try {
|
|
103
|
-
write(ui.top
|
|
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
|
-
|
|
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 (
|
|
117
|
-
const current = liveItem(ui,
|
|
135
|
+
for (const target of targets) {
|
|
136
|
+
const current = liveItem(ui, target);
|
|
118
137
|
write(ui.top, current);
|
|
119
138
|
afterItem(current);
|
|
120
|
-
|
|
139
|
+
written++;
|
|
121
140
|
}
|
|
122
|
-
completed.length = n;
|
|
123
141
|
ui.status = label;
|
|
124
|
-
return { ok: true,
|
|
142
|
+
return { ok: true, written };
|
|
125
143
|
} catch (error) {
|
|
126
|
-
completed.length = n;
|
|
127
144
|
ui.status = error.message;
|
|
128
|
-
return { ok: false,
|
|
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.
|
|
151
|
+
if (result.written) ui.reloadAfterChange();
|
|
135
152
|
return true;
|
|
136
153
|
};
|
|
137
154
|
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
144
|
-
const busy = npmBusyKind(item);
|
|
189
|
+
const unstageLazy = (ui, targets, extra = {}) => {
|
|
145
190
|
const repo = ui.repo;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
|
214
|
+
(top) => ui.repo.add(top, item),
|
|
156
215
|
() => {
|
|
157
|
-
|
|
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
|
|
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
|
|
237
|
+
(top) => ui.repo.revert(top, item),
|
|
181
238
|
() => {
|
|
182
|
-
|
|
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
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
|
236
|
-
const
|
|
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 (
|
|
252
|
-
|
|
272
|
+
if (reload) ui.reloadAfterChange();
|
|
273
|
+
if (after) after();
|
|
253
274
|
};
|
|
254
275
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
ui
|
|
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
|
-
|
|
275
|
-
|
|
284
|
+
ui.repo.unstage,
|
|
285
|
+
keepUnstaged,
|
|
276
286
|
);
|
|
277
287
|
if (reconcilePartial(ui, result)) return;
|
|
278
|
-
|
|
288
|
+
if (after) after();
|
|
279
289
|
};
|
|
280
290
|
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
|
305
|
-
add:
|
|
306
|
-
unstage:
|
|
307
|
-
revert:
|
|
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
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
);
|
|
339
|
-
if (
|
|
340
|
-
|
|
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
|
-
|
|
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
|
|
372
|
-
|
|
373
|
-
|
|
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
|
-
|
|
351
|
+
TARGETS[name](ui, targets);
|
|
388
352
|
};
|
|
389
353
|
|
|
390
354
|
const onCommand = (ui, name) => {
|
|
391
|
-
if (ui.nav.pane === 'files') return void
|
|
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
|
-
|
|
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 };
|