reslop 0.2.3 → 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 +27 -1
- package/README.md +8 -4
- package/bin/reslop.js +4 -2
- package/lib/api.js +2 -1
- package/lib/capabilities.js +0 -4
- package/lib/cli.js +19 -10
- package/lib/clipboard.js +45 -4
- package/lib/deps-diff.js +61 -118
- package/lib/deps.js +166 -235
- package/lib/detect.js +4 -2
- package/lib/diff/align.js +2 -1
- package/lib/diff/diff.js +6 -3
- package/lib/diff/display.js +2 -1
- package/lib/diff/inline.js +68 -2
- package/lib/diff/patch.js +2 -1
- package/lib/diff/unit.js +15 -30
- package/lib/editor.js +91 -13
- package/lib/files.js +54 -27
- package/lib/git-branches.js +107 -154
- package/lib/git-deps.js +78 -155
- package/lib/git-worktree.js +508 -0
- package/lib/git.js +23 -580
- package/lib/github.js +9 -8
- package/lib/gitlab.js +5 -4
- package/lib/highlight/bash.js +2 -1
- package/lib/highlight/core.js +11 -0
- package/lib/highlight/css.js +2 -1
- package/lib/highlight/csv.js +2 -1
- package/lib/highlight/dot.js +3 -12
- package/lib/highlight/html.js +2 -1
- package/lib/highlight/json.js +2 -1
- package/lib/highlight/log.js +5 -11
- package/lib/highlight/txt.js +3 -12
- package/lib/highlight.js +2 -1
- package/lib/keys.js +22 -12
- package/lib/manifest.js +4 -6
- package/lib/npm-commands.js +82 -24
- package/lib/remote.js +21 -20
- package/lib/render/branches.js +9 -27
- package/lib/render/chrome.js +109 -35
- package/lib/render/commits.js +216 -216
- package/lib/render/diff.js +160 -47
- package/lib/render/files.js +9 -26
- package/lib/render/frame.js +97 -118
- package/lib/render/notes.js +74 -26
- package/lib/render/npm.js +104 -30
- package/lib/render/present.js +2 -1
- package/lib/render/primitives.js +128 -52
- package/lib/render/render.js +2 -1
- package/lib/render/unit.js +17 -11
- package/lib/report-model.js +6 -4
- package/lib/report-parse.js +8 -14
- package/lib/report-render.js +38 -21
- package/lib/report-run.js +12 -11
- package/lib/report-test.js +45 -51
- package/lib/report-tools.js +44 -25
- package/lib/review-merge.js +102 -131
- package/lib/review.js +69 -78
- package/lib/select.js +52 -0
- package/lib/session/actions.js +72 -87
- package/lib/session/branches.js +18 -52
- package/lib/session/change-actions.js +175 -147
- package/lib/session/commit.js +65 -61
- package/lib/session/compose.js +152 -83
- package/lib/session/dispatch.js +53 -46
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +30 -51
- package/lib/session/items.js +73 -90
- package/lib/session/lifecycle.js +37 -98
- package/lib/session/load.js +52 -57
- package/lib/session/navigation.js +105 -95
- package/lib/session/npm.js +205 -71
- package/lib/session/ops.js +200 -45
- package/lib/session/pointer.js +33 -8
- package/lib/session/progress.js +9 -6
- package/lib/session/review.js +35 -53
- package/lib/session/tasks.js +292 -0
- package/lib/session/terminal.js +17 -19
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -96
- package/lib/session/view.js +45 -16
- package/lib/session/watch.js +47 -27
- package/lib/session.js +66 -97
- package/lib/source.js +6 -3
- package/lib/update.js +5 -13
- package/lib/utilities.js +25 -3
- package/lib/wrap.js +18 -1
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const files = require('../files.js');
|
|
4
|
+
const { isTasksEntry, TASKS_FILE } = files;
|
|
5
|
+
const review = require('../review.js');
|
|
6
|
+
const { addTask, setTaskText, setTaskDone, removeTask, checkLabel } = review;
|
|
7
|
+
|
|
8
|
+
const TASK_TYPE_SKIP = [
|
|
9
|
+
'enter',
|
|
10
|
+
'escape',
|
|
11
|
+
'tab',
|
|
12
|
+
'backspace',
|
|
13
|
+
'delete',
|
|
14
|
+
'left',
|
|
15
|
+
'right',
|
|
16
|
+
'up',
|
|
17
|
+
'down',
|
|
18
|
+
'home',
|
|
19
|
+
'end',
|
|
20
|
+
'pageUp',
|
|
21
|
+
'pageDown',
|
|
22
|
+
'j',
|
|
23
|
+
'k',
|
|
24
|
+
'n',
|
|
25
|
+
'p',
|
|
26
|
+
'q',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const isTaskTypeKey = (key) => {
|
|
30
|
+
if (!key) return false;
|
|
31
|
+
if (TASK_TYPE_SKIP.includes(key)) return false;
|
|
32
|
+
if (key.startsWith('ctrl-')) return false;
|
|
33
|
+
if (key.startsWith('alt-')) return false;
|
|
34
|
+
return key.charCodeAt(0) >= 32;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const listTasks = (api) => {
|
|
38
|
+
const notes = api.review.store;
|
|
39
|
+
if (!notes) return [];
|
|
40
|
+
return notes.tasks;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const isDraftCompose = (api) => {
|
|
44
|
+
const { state } = api;
|
|
45
|
+
return state.composeKind === 'tasks' && state.composeTaskId === null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const taskTexts = (api) => {
|
|
49
|
+
const nav = api.nav;
|
|
50
|
+
if (!nav.tasksOpen) return [];
|
|
51
|
+
const todos = listTasks(api);
|
|
52
|
+
const texts = new Array(todos.length + 1);
|
|
53
|
+
const { state } = api;
|
|
54
|
+
const editingTodo = state.composeKind === 'tasks';
|
|
55
|
+
const editingId = editingTodo ? state.composeTaskId : null;
|
|
56
|
+
for (let i = 0; i < todos.length; i++) {
|
|
57
|
+
const todo = todos[i];
|
|
58
|
+
const live = editingId === todo.id && state.editor;
|
|
59
|
+
const text = live ? state.editor.text : todo.text;
|
|
60
|
+
texts[i] = checkLabel(text, todo.done);
|
|
61
|
+
}
|
|
62
|
+
const draft = isDraftCompose(api) && state.editor ? state.editor.text : '';
|
|
63
|
+
texts[todos.length] = checkLabel(draft, false);
|
|
64
|
+
return texts;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const taskRowCount = (api) => {
|
|
68
|
+
if (!api.nav.tasksOpen) return 0;
|
|
69
|
+
return listTasks(api).length + 1;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const clampedTaskFocus = (api) => {
|
|
73
|
+
const last = Math.max(0, taskRowCount(api) - 1);
|
|
74
|
+
const focus = api.nav.tasksFocus;
|
|
75
|
+
if (focus < 0) return 0;
|
|
76
|
+
if (focus > last) return last;
|
|
77
|
+
return focus;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const moveTaskFocus = (api, delta) => {
|
|
81
|
+
const nav = api.nav;
|
|
82
|
+
if (!nav.tasksOpen) return;
|
|
83
|
+
const n = taskRowCount(api);
|
|
84
|
+
if (!n) return;
|
|
85
|
+
const next = clampedTaskFocus(api) + delta;
|
|
86
|
+
if (next < 0) nav.tasksFocus = 0;
|
|
87
|
+
else if (next >= n) nav.tasksFocus = n - 1;
|
|
88
|
+
else nav.tasksFocus = next;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const openTasksPage = (api) => {
|
|
92
|
+
const nav = api.nav;
|
|
93
|
+
nav.tasksOpen = true;
|
|
94
|
+
nav.pane = 'diff';
|
|
95
|
+
nav.scroll = 0;
|
|
96
|
+
nav.clearSelection();
|
|
97
|
+
api.ui.syncReviewPath();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const closeTasksPage = (api) => {
|
|
101
|
+
api.nav.tasksOpen = false;
|
|
102
|
+
api.ui.syncReviewPath();
|
|
103
|
+
api.ui.syncFileCursor();
|
|
104
|
+
api.ui.lifecycle.catchUpWatch();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const focusTodoPage = (api, todoId) => {
|
|
108
|
+
openTasksPage(api);
|
|
109
|
+
const todos = listTasks(api);
|
|
110
|
+
let focus = 0;
|
|
111
|
+
if (todoId === null) {
|
|
112
|
+
focus = todos.length;
|
|
113
|
+
} else if (todoId !== undefined) {
|
|
114
|
+
const at = todos.findIndex((todo) => todo.id === todoId);
|
|
115
|
+
if (at >= 0) focus = at;
|
|
116
|
+
else if (todos.length) focus = todos.length - 1;
|
|
117
|
+
}
|
|
118
|
+
api.nav.tasksFocus = focus;
|
|
119
|
+
api.nav.scroll = 0;
|
|
120
|
+
return true;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const startDraftCompose = (api) => {
|
|
124
|
+
focusTodoPage(api, null);
|
|
125
|
+
api.open('tasks', '', null);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const editFocusedTask = (api) => {
|
|
129
|
+
if (!api.nav.tasksOpen) return;
|
|
130
|
+
const todos = listTasks(api);
|
|
131
|
+
const todo = todos[clampedTaskFocus(api)];
|
|
132
|
+
if (!todo) return void startDraftCompose(api);
|
|
133
|
+
api.open('tasks', todo.text, todo.id);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const editNextTask = (api) => {
|
|
137
|
+
if (!api.nav.tasksOpen) return;
|
|
138
|
+
const last = taskRowCount(api) - 1;
|
|
139
|
+
const next = clampedTaskFocus(api) + 1;
|
|
140
|
+
if (next <= last) api.nav.tasksFocus = next;
|
|
141
|
+
editFocusedTask(api);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const moveTaskCompose = (api, delta, width, extend) => {
|
|
145
|
+
if (!api.nav.tasksOpen) return;
|
|
146
|
+
const editor = api.state.editor;
|
|
147
|
+
if (editor && width) {
|
|
148
|
+
const before = editor.cursor;
|
|
149
|
+
editor.moveLine(delta, width, extend);
|
|
150
|
+
if (editor.cursor !== before) return;
|
|
151
|
+
if (extend) return;
|
|
152
|
+
}
|
|
153
|
+
const last = taskRowCount(api) - 1;
|
|
154
|
+
const at = clampedTaskFocus(api);
|
|
155
|
+
let next = at + delta;
|
|
156
|
+
if (next < 0) next = 0;
|
|
157
|
+
if (next > last) next = last;
|
|
158
|
+
if (next === at) return;
|
|
159
|
+
api.commit();
|
|
160
|
+
api.ui.flushReview();
|
|
161
|
+
api.close();
|
|
162
|
+
const max = Math.max(0, taskRowCount(api) - 1);
|
|
163
|
+
api.nav.tasksFocus = Math.min(next, max);
|
|
164
|
+
editFocusedTask(api);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const typeIntoTask = (api, key) => {
|
|
168
|
+
const nav = api.nav;
|
|
169
|
+
if (!nav.tasksOpen) return false;
|
|
170
|
+
if (nav.pane !== 'diff') return false;
|
|
171
|
+
if (api.ui.mode !== 'review') return false;
|
|
172
|
+
if (!isTaskTypeKey(key)) return false;
|
|
173
|
+
editFocusedTask(api);
|
|
174
|
+
api.state.editor.insert(key);
|
|
175
|
+
return true;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const removeFocusedTask = (api) => {
|
|
179
|
+
const nav = api.nav;
|
|
180
|
+
if (nav.pane !== 'diff' || !nav.tasksOpen) return;
|
|
181
|
+
const todos = listTasks(api);
|
|
182
|
+
const todo = todos[clampedTaskFocus(api)];
|
|
183
|
+
if (!todo) return;
|
|
184
|
+
const notes = api.review.store;
|
|
185
|
+
removeTask(notes, todo.id);
|
|
186
|
+
const left = listTasks(api);
|
|
187
|
+
if (nav.tasksFocus >= left.length) {
|
|
188
|
+
nav.tasksFocus = Math.max(0, left.length - 1);
|
|
189
|
+
}
|
|
190
|
+
api.ui.flushReview(true);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const toggleFocusedTask = (api) => {
|
|
194
|
+
const nav = api.nav;
|
|
195
|
+
if (!nav.tasksOpen || nav.pane !== 'diff') return false;
|
|
196
|
+
if (api.ui.mode !== 'review') return false;
|
|
197
|
+
const todo = listTasks(api)[clampedTaskFocus(api)];
|
|
198
|
+
if (!todo) return false;
|
|
199
|
+
setTaskDone(api.review.store, todo.id, !todo.done);
|
|
200
|
+
api.ui.flushReview(true);
|
|
201
|
+
return true;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const onTaskHit = (api, cursor) => {
|
|
205
|
+
if (!api.nav.tasksOpen) return;
|
|
206
|
+
const todos = listTasks(api);
|
|
207
|
+
const draft = cursor === todos.length;
|
|
208
|
+
const target = todos[cursor];
|
|
209
|
+
if (!draft && !target) return;
|
|
210
|
+
const { state } = api;
|
|
211
|
+
if (state.composeKind === 'tasks') {
|
|
212
|
+
if (draft && state.composeTaskId === null) return;
|
|
213
|
+
if (target && target.id === state.composeTaskId) return;
|
|
214
|
+
api.commit();
|
|
215
|
+
api.close();
|
|
216
|
+
}
|
|
217
|
+
api.nav.tasksFocus = cursor;
|
|
218
|
+
editFocusedTask(api);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const onTaskCheck = (api, cursor) => {
|
|
222
|
+
if (!api.nav.tasksOpen) return;
|
|
223
|
+
const todo = listTasks(api)[cursor];
|
|
224
|
+
if (!todo) return void onTaskHit(api, cursor);
|
|
225
|
+
const { state } = api;
|
|
226
|
+
if (state.composeKind === 'tasks' && state.composeTaskId !== todo.id) {
|
|
227
|
+
api.commit();
|
|
228
|
+
api.close();
|
|
229
|
+
}
|
|
230
|
+
setTaskDone(api.review.store, todo.id, !todo.done);
|
|
231
|
+
api.nav.tasksFocus = cursor;
|
|
232
|
+
api.ui.flushReview(true);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const createTask = (api) => {
|
|
236
|
+
startDraftCompose(api);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const onTasks = (api) => {
|
|
240
|
+
const { nav, ui } = api;
|
|
241
|
+
if (nav.pane === 'files') {
|
|
242
|
+
const entry = ui.fileCursorEntry();
|
|
243
|
+
if (entry && !isTasksEntry(entry)) {
|
|
244
|
+
nav.index = entry.openIndex ?? entry.firstIndex;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
createTask(api);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const taskEditView = (api) => {
|
|
251
|
+
const { state } = api;
|
|
252
|
+
if (state.composeKind !== 'tasks') return null;
|
|
253
|
+
if (!state.editor) return null;
|
|
254
|
+
return { cursor: state.editor.cursor };
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const commitTask = (api, text) => {
|
|
258
|
+
const notes = api.review.store;
|
|
259
|
+
const id = api.state.composeTaskId;
|
|
260
|
+
const todos = notes.tasks;
|
|
261
|
+
const prev = id === null ? null : todos.find((entry) => entry.id === id);
|
|
262
|
+
if (prev) return void setTaskText(notes, id, text);
|
|
263
|
+
if (!text.trim()) return;
|
|
264
|
+
const todo = addTask(notes, TASKS_FILE, text);
|
|
265
|
+
api.state.composeTaskId = todo.id;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const createTasksCompose = (api) => ({
|
|
269
|
+
taskTexts: () => taskTexts(api),
|
|
270
|
+
clampedTaskFocus: () => clampedTaskFocus(api),
|
|
271
|
+
taskRowCount: () => taskRowCount(api),
|
|
272
|
+
moveTaskFocus: (delta) => moveTaskFocus(api, delta),
|
|
273
|
+
openTasksPage: () => openTasksPage(api),
|
|
274
|
+
closeTasksPage: () => closeTasksPage(api),
|
|
275
|
+
startDraftCompose: () => startDraftCompose(api),
|
|
276
|
+
editFocusedTask: () => editFocusedTask(api),
|
|
277
|
+
editNextTask: () => editNextTask(api),
|
|
278
|
+
moveTaskCompose: (delta, width, extend) =>
|
|
279
|
+
moveTaskCompose(api, delta, width, extend),
|
|
280
|
+
typeIntoTask: (key) => typeIntoTask(api, key),
|
|
281
|
+
removeFocusedTask: () => removeFocusedTask(api),
|
|
282
|
+
onTaskHit: (cursor) => onTaskHit(api, cursor),
|
|
283
|
+
onTaskCheck: (cursor) => onTaskCheck(api, cursor),
|
|
284
|
+
toggleFocusedTask: () => toggleFocusedTask(api),
|
|
285
|
+
onTasks: () => onTasks(api),
|
|
286
|
+
taskEditView: () => taskEditView(api),
|
|
287
|
+
commitTask: (text) => commitTask(api, text),
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
module.exports = {
|
|
291
|
+
createTasksCompose,
|
|
292
|
+
};
|
package/lib/session/terminal.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
3
|
+
const render = require('../render/render.js');
|
|
4
|
+
const { presentRows, presentCursor } = render;
|
|
5
|
+
const utilities = require('../utilities.js');
|
|
6
|
+
const { listen, watchResize } = utilities;
|
|
5
7
|
|
|
6
8
|
const ENTER_TERM = '\x1b[?1049h\x1b[?25l\x1b[?7l\x1b[?1002h\x1b[?1006h';
|
|
7
9
|
const LEAVE_TERM =
|
|
@@ -15,28 +17,25 @@ const sameCursor = (a, b) => {
|
|
|
15
17
|
|
|
16
18
|
const hasTimer = (api, name) => api.timers.has(name);
|
|
17
19
|
|
|
18
|
-
const
|
|
20
|
+
const cancel = (api, name) => {
|
|
19
21
|
const id = api.timers.get(name);
|
|
20
22
|
if (id === undefined) return;
|
|
21
|
-
|
|
23
|
+
clearTimeout(id);
|
|
22
24
|
api.timers.delete(name);
|
|
23
25
|
};
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
if (api.state.disposed) return;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const later = (api, name, fn, ms) => {
|
|
28
|
+
if (api.state.disposed || api.timers.has(name)) return;
|
|
29
|
+
const id = setTimeout(() => {
|
|
30
|
+
api.timers.delete(name);
|
|
31
|
+
fn();
|
|
32
|
+
}, ms);
|
|
33
|
+
if (typeof id.unref === 'function') id.unref();
|
|
30
34
|
api.timers.set(name, id);
|
|
31
35
|
};
|
|
32
36
|
|
|
33
|
-
const restartTimer = (api, name, fn, ms) => {
|
|
34
|
-
stopTimer(api, name);
|
|
35
|
-
startTimer(api, name, fn, ms);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
37
|
const clearTimers = (api) => {
|
|
39
|
-
for (const name of [...api.timers.keys()])
|
|
38
|
+
for (const name of [...api.timers.keys()]) cancel(api, name);
|
|
40
39
|
};
|
|
41
40
|
|
|
42
41
|
const stopListening = (api) => {
|
|
@@ -96,6 +95,7 @@ const paint = (api, frame, size, cursor) => {
|
|
|
96
95
|
api.state.lastFrame &&
|
|
97
96
|
api.state.lastFrame.text === frame.text
|
|
98
97
|
) {
|
|
98
|
+
api.state.lastFrame = frame;
|
|
99
99
|
if (sameCursor(api.state.lastPresentedCursor, cursor)) return;
|
|
100
100
|
api.state.lastPresentedCursor = cursor;
|
|
101
101
|
api.stdout.write(presentCursor(cursor));
|
|
@@ -146,9 +146,8 @@ const createTerminal = (options) => {
|
|
|
146
146
|
paint: (frame, size, cursor) => paint(api, frame, size, cursor),
|
|
147
147
|
startListening: (handlers) => startListening(api, handlers),
|
|
148
148
|
stopListening: () => stopListening(api),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
restartTimer: (name, fn, ms) => restartTimer(api, name, fn, ms),
|
|
149
|
+
later: (name, fn, ms) => later(api, name, fn, ms),
|
|
150
|
+
cancel: (name) => cancel(api, name),
|
|
152
151
|
clearTimers: () => clearTimers(api),
|
|
153
152
|
hasTimer: (name) => hasTimer(api, name),
|
|
154
153
|
resetCache: () => resetCache(api),
|
|
@@ -158,6 +157,5 @@ const createTerminal = (options) => {
|
|
|
158
157
|
module.exports = {
|
|
159
158
|
ENTER_TERM,
|
|
160
159
|
LEAVE_TERM,
|
|
161
|
-
sameCursor,
|
|
162
160
|
createTerminal,
|
|
163
161
|
};
|
package/lib/session/unit.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const files = require('../files.js');
|
|
4
|
-
const { listPath,
|
|
4
|
+
const { listPath, isTasksEntry } = files;
|
|
5
5
|
const diff = require('../diff/diff.js');
|
|
6
6
|
const { unitLines, itemsForPath, blockLineIndex } = diff;
|
|
7
7
|
const { hunkLineRange, sameHunk, hunkKey } = diff;
|
|
@@ -150,10 +150,10 @@ const moveUnitBlock = (ui, step) => {
|
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
const openUnitFile = (ui, entry) => {
|
|
153
|
-
if (!entry ||
|
|
153
|
+
if (!entry || isTasksEntry(entry)) return;
|
|
154
154
|
const nav = ui.nav;
|
|
155
155
|
nav.reviewPath = entry.path;
|
|
156
|
-
nav.
|
|
156
|
+
nav.tasksOpen = false;
|
|
157
157
|
nav.pane = 'unit';
|
|
158
158
|
nav.scroll = 0;
|
|
159
159
|
nav.unitLine = 0;
|
|
@@ -203,6 +203,5 @@ module.exports = {
|
|
|
203
203
|
openUnitFile,
|
|
204
204
|
setFileScope,
|
|
205
205
|
editCursor,
|
|
206
|
-
ensureVisible,
|
|
207
206
|
followFileCursor,
|
|
208
207
|
};
|
package/lib/session/update.js
CHANGED
|
@@ -1,112 +1,92 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { stateView } = require('./accessors.js');
|
|
4
|
-
|
|
5
3
|
const update = require('../update.js');
|
|
6
4
|
const { checkUpdate, installUpdate, markSkipped } = update;
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const reset = (state) => {
|
|
15
|
-
state.offer = false;
|
|
16
|
-
state.from = '';
|
|
17
|
-
state.to = '';
|
|
18
|
-
state.checkPromise = null;
|
|
19
|
-
state.installPromise = null;
|
|
20
|
-
};
|
|
6
|
+
class UpdateCoordinator {
|
|
7
|
+
constructor(ui) {
|
|
8
|
+
this.ui = ui;
|
|
9
|
+
this.reset();
|
|
10
|
+
}
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
12
|
+
get opts() {
|
|
13
|
+
const value = this.ui.updateOpts;
|
|
14
|
+
if (!value || value === true) return {};
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
await installUpdate(version, optsOf(api));
|
|
37
|
-
ok = true;
|
|
38
|
-
} catch {
|
|
39
|
-
// ignore install errors
|
|
18
|
+
reset() {
|
|
19
|
+
this.offer = false;
|
|
20
|
+
this.from = '';
|
|
21
|
+
this.to = '';
|
|
22
|
+
this.checkPromise = null;
|
|
23
|
+
this.installPromise = null;
|
|
40
24
|
}
|
|
41
|
-
api.ui.progress.stop('install');
|
|
42
|
-
if (api.ui.done || !api.ui.uiOpen) return;
|
|
43
|
-
api.ui.status = ok ? 'updated' : 'update failed';
|
|
44
|
-
api.ui.paint();
|
|
45
|
-
};
|
|
46
25
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
26
|
+
maybePrompt() {
|
|
27
|
+
const { ui } = this;
|
|
28
|
+
if (!this.offer || !ui.loader.didLoad) return;
|
|
29
|
+
if (ui.mode === 'review') ui.mode = 'confirmUpdate';
|
|
30
|
+
}
|
|
53
31
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
32
|
+
async install(version) {
|
|
33
|
+
const { ui } = this;
|
|
34
|
+
ui.status = 'updating reslop';
|
|
35
|
+
ui.progressFrame = 0;
|
|
36
|
+
ui.progress.start('install');
|
|
37
|
+
ui.paint();
|
|
38
|
+
let ok = false;
|
|
39
|
+
try {
|
|
40
|
+
await installUpdate(version, this.opts);
|
|
41
|
+
ok = true;
|
|
42
|
+
} catch {
|
|
43
|
+
// ignore install errors
|
|
44
|
+
}
|
|
45
|
+
ui.progress.stop('install');
|
|
46
|
+
if (ui.done || !ui.uiOpen) return;
|
|
47
|
+
ui.status = ok ? 'updated' : 'update failed';
|
|
48
|
+
ui.paint();
|
|
49
|
+
}
|
|
60
50
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
} catch {
|
|
66
|
-
return;
|
|
51
|
+
accept() {
|
|
52
|
+
this.ui.mode = 'review';
|
|
53
|
+
this.offer = false;
|
|
54
|
+
this.installPromise = this.install(this.to);
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
|
|
57
|
+
decline() {
|
|
58
|
+
this.ui.mode = 'review';
|
|
59
|
+
this.offer = false;
|
|
60
|
+
this.ui.status = '';
|
|
61
|
+
markSkipped(this.to, this.opts);
|
|
73
62
|
}
|
|
74
|
-
if (plan.action !== 'confirm') return;
|
|
75
|
-
api.state.from = plan.current;
|
|
76
|
-
api.state.to = plan.latest;
|
|
77
|
-
api.state.offer = true;
|
|
78
|
-
maybePrompt(api);
|
|
79
|
-
api.ui.paint();
|
|
80
|
-
};
|
|
81
63
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
64
|
+
async check() {
|
|
65
|
+
let plan;
|
|
66
|
+
try {
|
|
67
|
+
plan = await checkUpdate(this.opts);
|
|
68
|
+
} catch {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (this.ui.done) return;
|
|
72
|
+
if (plan.action === 'install') {
|
|
73
|
+
this.installPromise = this.install(plan.latest);
|
|
74
|
+
await this.installPromise;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (plan.action !== 'confirm') return;
|
|
78
|
+
this.from = plan.current;
|
|
79
|
+
this.to = plan.latest;
|
|
80
|
+
this.offer = true;
|
|
81
|
+
this.maybePrompt();
|
|
82
|
+
this.ui.paint();
|
|
83
|
+
}
|
|
88
84
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
installPromise: null,
|
|
96
|
-
};
|
|
97
|
-
const api = { ui, state };
|
|
98
|
-
return stateView(
|
|
99
|
-
state,
|
|
100
|
-
{
|
|
101
|
-
reset: () => reset(state),
|
|
102
|
-
maybePrompt: () => maybePrompt(api),
|
|
103
|
-
accept: () => acceptUpdate(api),
|
|
104
|
-
decline: () => declineUpdate(api),
|
|
105
|
-
open: () => openUpdate(api),
|
|
106
|
-
},
|
|
107
|
-
['offer', 'installPromise'],
|
|
108
|
-
['from', 'to', 'checkPromise'],
|
|
109
|
-
);
|
|
110
|
-
};
|
|
85
|
+
open() {
|
|
86
|
+
if (this.ui.updateOpts === false) return Promise.resolve();
|
|
87
|
+
if (!this.checkPromise) this.checkPromise = this.check();
|
|
88
|
+
return this.checkPromise;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
111
91
|
|
|
112
|
-
module.exports = {
|
|
92
|
+
module.exports = { UpdateCoordinator };
|