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
package/lib/review.js
CHANGED
|
@@ -4,29 +4,31 @@ const fs = require('node:fs');
|
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
|
|
6
6
|
const files = require('./files.js');
|
|
7
|
-
const {
|
|
7
|
+
const { TASKS_FILE, REVIEW_DIR } = files;
|
|
8
8
|
const reviewMerge = require('./review-merge.js');
|
|
9
9
|
const { captureBaseline, mergeReview } = reviewMerge;
|
|
10
|
+
const utilities = require('./utilities.js');
|
|
11
|
+
const { pad2, dateStamp } = utilities;
|
|
10
12
|
|
|
11
13
|
const createStore = (reviewPath, templates = []) => ({
|
|
12
14
|
reviewPath,
|
|
13
15
|
dirty: false,
|
|
14
|
-
|
|
16
|
+
nextTaskId: 1,
|
|
15
17
|
feedback: new Map(),
|
|
16
18
|
code: new Map(),
|
|
17
|
-
|
|
19
|
+
tasks: [],
|
|
18
20
|
templates: [...templates],
|
|
19
21
|
status: 'editing',
|
|
20
22
|
baseline: null,
|
|
21
23
|
});
|
|
22
24
|
|
|
23
25
|
const noteCounts = (store) => {
|
|
24
|
-
const counts = { feedback: 0,
|
|
26
|
+
const counts = { feedback: 0, tasks: 0, tasksDone: 0, code: 0 };
|
|
25
27
|
if (!store) return counts;
|
|
26
|
-
for (const
|
|
27
|
-
if (!
|
|
28
|
-
counts.
|
|
29
|
-
if (
|
|
28
|
+
for (const task of store.tasks) {
|
|
29
|
+
if (!task.text.trim()) continue;
|
|
30
|
+
counts.tasks += 1;
|
|
31
|
+
if (task.done) counts.tasksDone += 1;
|
|
30
32
|
}
|
|
31
33
|
for (const note of store.feedback.values()) {
|
|
32
34
|
if (note.text.trim()) counts.feedback += 1;
|
|
@@ -37,21 +39,20 @@ const noteCounts = (store) => {
|
|
|
37
39
|
|
|
38
40
|
const hasNotes = (store) => {
|
|
39
41
|
const counts = noteCounts(store);
|
|
40
|
-
return counts.feedback > 0 || counts.
|
|
42
|
+
return counts.feedback > 0 || counts.tasks > 0 || counts.code > 0;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const prev = store.feedback.get(key);
|
|
47
|
-
if (!trimmed) {
|
|
45
|
+
const putNote = (store, notes, key, note, clear) => {
|
|
46
|
+
const prev = notes.get(key);
|
|
47
|
+
if (clear) {
|
|
48
48
|
if (!prev) return;
|
|
49
|
-
|
|
49
|
+
notes.delete(key);
|
|
50
50
|
store.dirty = true;
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
+
const text = note.text ?? '';
|
|
53
54
|
if (prev && prev.text === text) return;
|
|
54
|
-
|
|
55
|
+
notes.set(key, {
|
|
55
56
|
file: note.file,
|
|
56
57
|
oldStart: note.oldStart ?? 0,
|
|
57
58
|
newStart: note.newStart ?? 0,
|
|
@@ -64,42 +65,28 @@ const setFeedback = (store, key, note) => {
|
|
|
64
65
|
store.dirty = true;
|
|
65
66
|
};
|
|
66
67
|
|
|
68
|
+
const setFeedback = (store, key, note) => {
|
|
69
|
+
const clear = !(note.text ?? '').trim();
|
|
70
|
+
putNote(store, store.feedback, key, note, clear);
|
|
71
|
+
};
|
|
72
|
+
|
|
67
73
|
const setCode = (store, key, note) => {
|
|
68
|
-
|
|
69
|
-
if (note.clear) {
|
|
70
|
-
if (!prev) return;
|
|
71
|
-
store.code.delete(key);
|
|
72
|
-
store.dirty = true;
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const text = note.text ?? '';
|
|
76
|
-
if (prev && prev.text === text) return;
|
|
77
|
-
store.code.set(key, {
|
|
78
|
-
file: note.file,
|
|
79
|
-
oldStart: note.oldStart ?? 0,
|
|
80
|
-
newStart: note.newStart ?? 0,
|
|
81
|
-
blockId: note.blockId ?? 0,
|
|
82
|
-
origin: note.origin ?? '',
|
|
83
|
-
header: note.header ?? '',
|
|
84
|
-
text,
|
|
85
|
-
done: note.done ?? prev?.done ?? false,
|
|
86
|
-
});
|
|
87
|
-
store.dirty = true;
|
|
74
|
+
putNote(store, store.code, key, note, Boolean(note.clear));
|
|
88
75
|
};
|
|
89
76
|
|
|
90
|
-
const
|
|
91
|
-
const id = store.
|
|
92
|
-
store.
|
|
77
|
+
const addTask = (store, file, text = '') => {
|
|
78
|
+
const id = store.nextTaskId;
|
|
79
|
+
store.nextTaskId += 1;
|
|
93
80
|
const todo = { id, file, text, done: false };
|
|
94
|
-
store.
|
|
81
|
+
store.tasks.push(todo);
|
|
95
82
|
store.dirty = true;
|
|
96
83
|
return todo;
|
|
97
84
|
};
|
|
98
85
|
|
|
99
|
-
const
|
|
86
|
+
const removeTask = (store, id) => {
|
|
100
87
|
const next = [];
|
|
101
88
|
let found = false;
|
|
102
|
-
for (const todo of store.
|
|
89
|
+
for (const todo of store.tasks) {
|
|
103
90
|
if (todo.id === id) {
|
|
104
91
|
found = true;
|
|
105
92
|
continue;
|
|
@@ -107,28 +94,28 @@ const removeTodo = (store, id) => {
|
|
|
107
94
|
next.push(todo);
|
|
108
95
|
}
|
|
109
96
|
if (!found) return false;
|
|
110
|
-
store.
|
|
97
|
+
store.tasks = next;
|
|
111
98
|
store.dirty = true;
|
|
112
99
|
return true;
|
|
113
100
|
};
|
|
114
101
|
|
|
115
|
-
const
|
|
116
|
-
const i = store.
|
|
102
|
+
const setTaskText = (store, id, text) => {
|
|
103
|
+
const i = store.tasks.findIndex((todo) => todo.id === id);
|
|
117
104
|
if (i < 0) return;
|
|
118
|
-
const prev = store.
|
|
105
|
+
const prev = store.tasks[i];
|
|
119
106
|
const trimmed = text.trim();
|
|
120
|
-
if (!trimmed) return void
|
|
107
|
+
if (!trimmed) return void removeTask(store, id);
|
|
121
108
|
if (prev.text === text) return;
|
|
122
|
-
store.
|
|
109
|
+
store.tasks[i] = { id: prev.id, file: prev.file, text, done: prev.done };
|
|
123
110
|
store.dirty = true;
|
|
124
111
|
};
|
|
125
112
|
|
|
126
|
-
const
|
|
127
|
-
const i = store.
|
|
113
|
+
const setTaskDone = (store, id, done) => {
|
|
114
|
+
const i = store.tasks.findIndex((todo) => todo.id === id);
|
|
128
115
|
if (i < 0) return;
|
|
129
|
-
const prev = store.
|
|
116
|
+
const prev = store.tasks[i];
|
|
130
117
|
if (prev.done === done) return;
|
|
131
|
-
store.
|
|
118
|
+
store.tasks[i] = { id: prev.id, file: prev.file, text: prev.text, done };
|
|
132
119
|
store.dirty = true;
|
|
133
120
|
};
|
|
134
121
|
|
|
@@ -164,9 +151,9 @@ const applyImportedNotes = (store, imported) => {
|
|
|
164
151
|
done,
|
|
165
152
|
});
|
|
166
153
|
}
|
|
167
|
-
const todos = imported.todos ?? [];
|
|
154
|
+
const todos = imported.tasks ?? imported.todos ?? [];
|
|
168
155
|
for (const todo of todos) {
|
|
169
|
-
const added =
|
|
156
|
+
const added = addTask(store, todo.file || '', todo.text ?? '');
|
|
170
157
|
if (todo.done) added.done = true;
|
|
171
158
|
}
|
|
172
159
|
};
|
|
@@ -233,6 +220,8 @@ const SECTION_LINE = {
|
|
|
233
220
|
'### Todo': 'todo',
|
|
234
221
|
'### Feedback': 'feedback',
|
|
235
222
|
};
|
|
223
|
+
const BACKLOG_HEAD = 'Backlog';
|
|
224
|
+
const LEGACY_BACKLOG = 'TODOs';
|
|
236
225
|
|
|
237
226
|
const AGENT_INSTRUCTIONS = [
|
|
238
227
|
'- Execute reviews with `status` `ready, partial, editing`',
|
|
@@ -273,9 +262,9 @@ const parseFrontmatterStatus = (text) => {
|
|
|
273
262
|
const isDoneMark = (mark) => mark === 'x' || mark === 'X';
|
|
274
263
|
|
|
275
264
|
const pushTodo = (builder, file, text, done) => {
|
|
276
|
-
const id = builder.
|
|
277
|
-
builder.
|
|
278
|
-
builder.
|
|
265
|
+
const id = builder.nextTaskId;
|
|
266
|
+
builder.nextTaskId += 1;
|
|
267
|
+
builder.tasks.push({ id, file, text, done });
|
|
279
268
|
};
|
|
280
269
|
|
|
281
270
|
const checkboxLine = (text, done) => {
|
|
@@ -350,7 +339,7 @@ const parseFeedSuffix = (textItem) => {
|
|
|
350
339
|
const fileGroup = (groups, file) => {
|
|
351
340
|
let group = groups.get(file);
|
|
352
341
|
if (!group) {
|
|
353
|
-
group = {
|
|
342
|
+
group = { tasks: [], feedback: [], code: [] };
|
|
354
343
|
groups.set(file, group);
|
|
355
344
|
}
|
|
356
345
|
return group;
|
|
@@ -358,9 +347,9 @@ const fileGroup = (groups, file) => {
|
|
|
358
347
|
|
|
359
348
|
const groupReviewNotes = (notes) => {
|
|
360
349
|
const groups = new Map();
|
|
361
|
-
for (const todo of notes.
|
|
350
|
+
for (const todo of notes.tasks) {
|
|
362
351
|
if (!todo.text.trim()) continue;
|
|
363
|
-
fileGroup(groups,
|
|
352
|
+
fileGroup(groups, TASKS_FILE).tasks.push(todo);
|
|
364
353
|
}
|
|
365
354
|
for (const key of notes.feedback.keys()) {
|
|
366
355
|
const note = notes.feedback.get(key);
|
|
@@ -411,12 +400,19 @@ const emitCodeItem = (lines, note) => {
|
|
|
411
400
|
lines.push(fence);
|
|
412
401
|
};
|
|
413
402
|
|
|
403
|
+
const sectionTitle = (file) => (file === TASKS_FILE ? BACKLOG_HEAD : file);
|
|
404
|
+
|
|
405
|
+
const backlogFile = (name) => {
|
|
406
|
+
if (name === BACKLOG_HEAD || name === LEGACY_BACKLOG) return TASKS_FILE;
|
|
407
|
+
return name;
|
|
408
|
+
};
|
|
409
|
+
|
|
414
410
|
const emitReviewGroups = (lines, groups) => {
|
|
415
411
|
for (const file of groups.keys()) {
|
|
416
412
|
const group = groups.get(file);
|
|
417
|
-
lines.push(`## ${file}`);
|
|
413
|
+
lines.push(`## ${sectionTitle(file)}`);
|
|
418
414
|
lines.push('');
|
|
419
|
-
for (const todo of group.
|
|
415
|
+
for (const todo of group.tasks) {
|
|
420
416
|
lines.push(checkboxLine(todo.text, todo.done));
|
|
421
417
|
}
|
|
422
418
|
for (const item of group.feedback) {
|
|
@@ -462,9 +458,9 @@ const flushPendingFeedback = (builder, pending) => {
|
|
|
462
458
|
|
|
463
459
|
const headingFile = (line) => {
|
|
464
460
|
const quoted = FILE_QUOTE.exec(line);
|
|
465
|
-
if (quoted) return quoted[1];
|
|
461
|
+
if (quoted) return backlogFile(quoted[1]);
|
|
466
462
|
if (line.startsWith('## ') && line !== '## Agent instructions') {
|
|
467
|
-
return line.slice(3);
|
|
463
|
+
return backlogFile(line.slice(3));
|
|
468
464
|
}
|
|
469
465
|
return null;
|
|
470
466
|
};
|
|
@@ -646,15 +642,6 @@ const TEMPLATES_FILE = 'templates.json';
|
|
|
646
642
|
const AUTOSAVE_MS = 3000;
|
|
647
643
|
const REVIEW_NAME = /^(\d{4}-\d{2}-\d{2})-(\d+)\.md$/;
|
|
648
644
|
|
|
649
|
-
const pad2 = (n) => `${n}`.padStart(2, '0');
|
|
650
|
-
|
|
651
|
-
const dateStamp = (date) => {
|
|
652
|
-
const y = date.getFullYear();
|
|
653
|
-
const month = pad2(date.getMonth() + 1);
|
|
654
|
-
const day = pad2(date.getDate());
|
|
655
|
-
return `${y}-${month}-${day}`;
|
|
656
|
-
};
|
|
657
|
-
|
|
658
645
|
const allocateReviewPath = (dir, date, existingNames) => {
|
|
659
646
|
const stamp = dateStamp(date);
|
|
660
647
|
let max = -1;
|
|
@@ -802,10 +789,10 @@ module.exports = {
|
|
|
802
789
|
rememberTemplate,
|
|
803
790
|
setFeedback,
|
|
804
791
|
setCode,
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
792
|
+
addTask,
|
|
793
|
+
removeTask,
|
|
794
|
+
setTaskText,
|
|
795
|
+
setTaskDone,
|
|
809
796
|
checkLabel,
|
|
810
797
|
feedbackKey,
|
|
811
798
|
applyImportedNotes,
|
package/lib/select.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const ansi = require('./ansi.js');
|
|
4
4
|
|
|
5
5
|
const { ESC, RESET, THEME, seq, stripAnsi, graphemes, graphemeWidth } = ansi;
|
|
6
|
+
const { visibleWidth } = ansi;
|
|
6
7
|
|
|
7
8
|
const CSI_FINAL = /[@-~]/;
|
|
8
9
|
|
|
@@ -177,6 +178,56 @@ const overlayRange = (line, fromCol, toCol) => {
|
|
|
177
178
|
return out;
|
|
178
179
|
};
|
|
179
180
|
|
|
181
|
+
const selectionOf = (source) => {
|
|
182
|
+
if (!source || typeof source.anchor !== 'number') return null;
|
|
183
|
+
const cursor = source.cursor ?? 0;
|
|
184
|
+
if (source.anchor === cursor) return null;
|
|
185
|
+
return { anchor: source.anchor, cursor };
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const editorSelection = (view) => {
|
|
189
|
+
if (!view) return null;
|
|
190
|
+
if (view.compose) return selectionOf(view.compose);
|
|
191
|
+
return selectionOf(view.codeOverlay);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const spanCols = (hit, lo, hi) => {
|
|
195
|
+
const start = hit.start ?? 0;
|
|
196
|
+
const from = Math.max(lo, start);
|
|
197
|
+
const to = Math.min(hi, hit.limit ?? start);
|
|
198
|
+
if (to <= from) return null;
|
|
199
|
+
const text = hit.text ?? '';
|
|
200
|
+
const head = Math.max(0, from - start);
|
|
201
|
+
const tail = Math.max(0, to - start);
|
|
202
|
+
const c0 = visibleWidth(text.slice(0, head));
|
|
203
|
+
const c1 = visibleWidth(text.slice(0, tail));
|
|
204
|
+
const scroll = hit.scroll ?? 0;
|
|
205
|
+
const room = Math.max(0, (hit.x1 ?? hit.textX ?? 1) - (hit.textX ?? 1));
|
|
206
|
+
const vis0 = Math.max(c0, scroll);
|
|
207
|
+
const vis1 = Math.min(c1, scroll + room);
|
|
208
|
+
if (vis1 <= vis0) return null;
|
|
209
|
+
const origin = (hit.textX ?? 1) - 1;
|
|
210
|
+
return { from: origin + vis0 - scroll, to: origin + vis1 - scroll };
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const markEditorSelection = (rows, view, hits, color) => {
|
|
214
|
+
if (!color || !hits) return rows;
|
|
215
|
+
const sel = editorSelection(view);
|
|
216
|
+
if (!sel) return rows;
|
|
217
|
+
const lo = Math.min(sel.anchor, sel.cursor);
|
|
218
|
+
const hi = Math.max(sel.anchor, sel.cursor);
|
|
219
|
+
const next = rows.slice();
|
|
220
|
+
for (const hit of hits) {
|
|
221
|
+
if (!hit.live || !hit.y) continue;
|
|
222
|
+
const range = spanCols(hit, lo, hi);
|
|
223
|
+
if (!range) continue;
|
|
224
|
+
const i = hit.y - 1;
|
|
225
|
+
if (i < 0 || i >= next.length) continue;
|
|
226
|
+
next[i] = overlayRange(next[i], range.from, range.to);
|
|
227
|
+
}
|
|
228
|
+
return next;
|
|
229
|
+
};
|
|
230
|
+
|
|
180
231
|
const overlayRows = (rows, sel) => {
|
|
181
232
|
if (!isRange(sel)) return rows;
|
|
182
233
|
const { length } = rows;
|
|
@@ -193,4 +244,5 @@ module.exports = {
|
|
|
193
244
|
extractText,
|
|
194
245
|
overlayRange,
|
|
195
246
|
overlayRows,
|
|
247
|
+
markEditorSelection,
|
|
196
248
|
};
|
package/lib/session/actions.js
CHANGED
|
@@ -6,13 +6,14 @@ const ACTIONS = {
|
|
|
6
6
|
add: ['a'],
|
|
7
7
|
unstage: ['u'],
|
|
8
8
|
revert: ['d'],
|
|
9
|
+
ignore: ['i'],
|
|
9
10
|
commit: ['c'],
|
|
10
11
|
prev: ['left', 'p', 'k'],
|
|
11
12
|
next: ['right', 'n', 'j'],
|
|
12
13
|
check: ['x', ' '],
|
|
13
14
|
layout: ['m'],
|
|
14
15
|
feedback: ['f'],
|
|
15
|
-
|
|
16
|
+
tasks: ['t'],
|
|
16
17
|
code: ['e'],
|
|
17
18
|
branch: ['b'],
|
|
18
19
|
file: ['f'],
|
|
@@ -47,6 +48,7 @@ const NPM_ACTIONS = {
|
|
|
47
48
|
npmDrop: ['d'],
|
|
48
49
|
npmLogs: ['c'],
|
|
49
50
|
npmStop: ['escape'],
|
|
51
|
+
npmVerbose: ['v'],
|
|
50
52
|
npmRerun: ['r'],
|
|
51
53
|
};
|
|
52
54
|
|
|
@@ -60,6 +62,7 @@ const ACTION_LABEL = {
|
|
|
60
62
|
revert: 'drop',
|
|
61
63
|
check: 'x',
|
|
62
64
|
layout: 'mode',
|
|
65
|
+
tasks: 'tasks',
|
|
63
66
|
view: 'view',
|
|
64
67
|
code: 'edit',
|
|
65
68
|
newBranch: 'new',
|
|
@@ -68,6 +71,7 @@ const ACTION_LABEL = {
|
|
|
68
71
|
npmDrop: 'delete',
|
|
69
72
|
npmLogs: 'cleanup',
|
|
70
73
|
npmStop: 'esc',
|
|
74
|
+
npmVerbose: 'verbose',
|
|
71
75
|
npmRerun: 're-run',
|
|
72
76
|
quit: 'q',
|
|
73
77
|
prev: '←',
|
|
@@ -82,6 +86,7 @@ const DIFF_DISABLED = [
|
|
|
82
86
|
'push',
|
|
83
87
|
'file',
|
|
84
88
|
'diff',
|
|
89
|
+
'ignore',
|
|
85
90
|
];
|
|
86
91
|
const UNIT_DISABLED = [...DIFF_DISABLED, 'layout'];
|
|
87
92
|
const FILES_DISABLED = ['layout', 'feedback', 'code'];
|
|
@@ -94,16 +99,17 @@ const FILES_HIDDEN = [
|
|
|
94
99
|
'file',
|
|
95
100
|
'diff',
|
|
96
101
|
];
|
|
97
|
-
const FILES_GIT_DISABLED = ['add', 'unstage', 'revert'];
|
|
98
|
-
const
|
|
99
|
-
const
|
|
102
|
+
const FILES_GIT_DISABLED = ['add', 'unstage', 'revert', 'ignore'];
|
|
103
|
+
const FILES_TASKS_DISABLED = [...FILES_GIT_DISABLED, ...FILES_DISABLED];
|
|
104
|
+
const TASKS_DISABLED = [
|
|
100
105
|
'add',
|
|
101
106
|
'unstage',
|
|
102
107
|
'revert',
|
|
108
|
+
'ignore',
|
|
103
109
|
'commit',
|
|
104
110
|
'layout',
|
|
105
111
|
'feedback',
|
|
106
|
-
'
|
|
112
|
+
'tasks',
|
|
107
113
|
'code',
|
|
108
114
|
'branch',
|
|
109
115
|
'file',
|
|
@@ -115,10 +121,11 @@ const BRANCHES_DISABLED = [
|
|
|
115
121
|
'add',
|
|
116
122
|
'unstage',
|
|
117
123
|
'revert',
|
|
124
|
+
'ignore',
|
|
118
125
|
'commit',
|
|
119
126
|
'layout',
|
|
120
127
|
'feedback',
|
|
121
|
-
'
|
|
128
|
+
'tasks',
|
|
122
129
|
'code',
|
|
123
130
|
'check',
|
|
124
131
|
'branch',
|
|
@@ -130,11 +137,11 @@ const BRANCHES_DISABLED = [
|
|
|
130
137
|
const COMMITS_DISABLED = BRANCHES_DISABLED.filter((id) => id !== 'commit');
|
|
131
138
|
const NPM_DISABLED = [...BRANCHES_DISABLED, 'pull', 'push'];
|
|
132
139
|
|
|
133
|
-
const
|
|
134
|
-
!!(item && (item.kind === '
|
|
140
|
+
const isTasksTarget = (item) =>
|
|
141
|
+
!!(item && (item.kind === 'tasks' || item.origin === 'task'));
|
|
135
142
|
|
|
136
143
|
const diffGitDisabled = (item) => {
|
|
137
|
-
if (!item ||
|
|
144
|
+
if (!item || isTasksTarget(item)) return [];
|
|
138
145
|
if (item.origin === 'staged') return ['add'];
|
|
139
146
|
return ['unstage'];
|
|
140
147
|
};
|
|
@@ -171,8 +178,8 @@ const commitGitDisabled = (item) => {
|
|
|
171
178
|
};
|
|
172
179
|
|
|
173
180
|
const disabledActions = (pane, item) => {
|
|
174
|
-
const onTodos =
|
|
175
|
-
if (pane === 'files') return onTodos ?
|
|
181
|
+
const onTodos = isTasksTarget(item);
|
|
182
|
+
if (pane === 'files') return onTodos ? FILES_TASKS_DISABLED : FILES_DISABLED;
|
|
176
183
|
if (pane === 'unit') return [...UNIT_DISABLED, ...diffGitDisabled(item)];
|
|
177
184
|
if (pane === 'branches') {
|
|
178
185
|
return [...BRANCHES_DISABLED, ...branchGitDisabled(item)];
|
|
@@ -181,7 +188,7 @@ const disabledActions = (pane, item) => {
|
|
|
181
188
|
return [...COMMITS_DISABLED, ...commitWriteDisabled(item)];
|
|
182
189
|
}
|
|
183
190
|
if (pane === 'npm') return NPM_DISABLED;
|
|
184
|
-
if (onTodos) return
|
|
191
|
+
if (onTodos) return TASKS_DISABLED;
|
|
185
192
|
return [...DIFF_DISABLED, ...diffGitDisabled(item)];
|
|
186
193
|
};
|
|
187
194
|
|
|
@@ -203,8 +210,8 @@ const SCROLL = {
|
|
|
203
210
|
home: 'home',
|
|
204
211
|
end: 'end',
|
|
205
212
|
enter: 'open',
|
|
206
|
-
backspace: '
|
|
207
|
-
delete: '
|
|
213
|
+
backspace: 'removeTask',
|
|
214
|
+
delete: 'removeTask',
|
|
208
215
|
};
|
|
209
216
|
|
|
210
217
|
const keysForActions = (actions) => {
|
|
@@ -358,28 +365,22 @@ module.exports = {
|
|
|
358
365
|
ACTION_IDS,
|
|
359
366
|
BRANCH_ACTIONS,
|
|
360
367
|
COMMIT_ACTIONS,
|
|
361
|
-
NPM_ACTIONS,
|
|
362
|
-
ACTION_HOT,
|
|
363
|
-
ACTION_LABEL,
|
|
364
368
|
DIFF_DISABLED,
|
|
365
369
|
UNIT_DISABLED,
|
|
366
370
|
FILES_DISABLED,
|
|
367
371
|
FILES_HIDDEN,
|
|
368
372
|
FILES_GIT_DISABLED,
|
|
369
|
-
|
|
370
|
-
|
|
373
|
+
FILES_TASKS_DISABLED,
|
|
374
|
+
TASKS_DISABLED,
|
|
371
375
|
BRANCHES_DISABLED,
|
|
372
376
|
COMMITS_DISABLED,
|
|
373
377
|
NPM_DISABLED,
|
|
374
|
-
SCROLL,
|
|
375
|
-
PANE_ONLY,
|
|
376
378
|
disabledActions,
|
|
377
379
|
diffGitDisabled,
|
|
378
380
|
branchGitDisabled,
|
|
379
381
|
commitGitDisabled,
|
|
380
382
|
isFixupCommit,
|
|
381
383
|
actionFromKey,
|
|
382
|
-
actionKeys,
|
|
383
384
|
actionHot,
|
|
384
385
|
actionLetter,
|
|
385
386
|
buttonWord,
|
package/lib/session/branches.js
CHANGED
|
@@ -47,10 +47,12 @@ const onBranch = (api) => {
|
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
const current = api.state.branches.findIndex((entry) => entry.current);
|
|
50
|
-
api.ui.nav
|
|
51
|
-
|
|
50
|
+
const nav = api.ui.nav;
|
|
51
|
+
nav.branchCursor = current < 0 ? 0 : current;
|
|
52
|
+
nav.pane = 'branches';
|
|
53
|
+
nav.resetListScroll('branches');
|
|
52
54
|
api.ui.status = '';
|
|
53
|
-
|
|
55
|
+
nav.clearSelection();
|
|
54
56
|
};
|
|
55
57
|
|
|
56
58
|
const onBranchMove = (api, delta) => {
|