reslop 0.1.9 → 0.2.1
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/README.md +3 -1
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +148 -5
- package/lib/api.js +4 -2
- package/lib/capabilities.js +13 -14
- package/lib/cli.js +38 -49
- package/lib/clipboard.js +1 -1
- package/lib/{deps/changes.js → deps-diff.js} +309 -19
- package/lib/deps.js +498 -29
- package/lib/detect.js +1 -7
- package/lib/diff/align.js +7 -10
- package/lib/diff/diff.js +53 -0
- package/lib/diff/display.js +5 -4
- package/lib/diff/inline.js +26 -21
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +1 -3
- package/lib/diff/unit.js +392 -0
- package/lib/files.js +5 -8
- package/lib/{git/branches.js → git-branches.js} +191 -11
- package/lib/{git/dependencies.js → git-deps.js} +111 -38
- package/lib/git-reword-todo.js +20 -0
- package/lib/git.js +606 -68
- package/lib/github.js +28 -197
- package/lib/gitlab.js +24 -195
- package/lib/highlight/bash.js +1 -3
- package/lib/highlight/css.js +1 -3
- package/lib/highlight/js.js +11 -14
- package/lib/highlight.js +6 -9
- package/lib/keys.js +14 -8
- package/lib/manifest.js +330 -0
- package/lib/remote.js +374 -0
- package/lib/render/branches.js +18 -100
- package/lib/render/chrome.js +71 -14
- package/lib/render/commits.js +69 -60
- package/lib/render/diff.js +20 -20
- package/lib/render/files.js +6 -34
- package/lib/render/frame.js +36 -13
- package/lib/render/notes.js +26 -8
- package/lib/render/primitives.js +99 -11
- package/lib/{render.js → render/render.js} +8 -8
- package/lib/render/unit.js +41 -0
- package/lib/review-merge.js +270 -0
- package/lib/review.js +782 -14
- package/lib/select.js +5 -10
- package/lib/session/accessors.js +9 -1
- package/lib/session/actions.js +61 -18
- package/lib/session/branches.js +116 -128
- package/lib/session/change-actions.js +202 -123
- package/lib/session/commit.js +201 -115
- package/lib/session/compose.js +181 -15
- package/lib/session/dispatch.js +110 -60
- package/lib/session/files-pane.js +156 -148
- package/lib/session/items.js +22 -30
- package/lib/session/lifecycle.js +151 -54
- package/lib/session/load.js +19 -33
- package/lib/session/navigation.js +12 -1
- package/lib/session/ops.js +28 -41
- package/lib/session/pointer.js +57 -57
- package/lib/session/review.js +23 -37
- package/lib/session/terminal.js +6 -12
- package/lib/session/todos.js +37 -13
- package/lib/session/unit.js +208 -0
- package/lib/session/update.js +33 -46
- package/lib/session/view.js +78 -9
- package/lib/session/watch.js +128 -24
- package/lib/session.js +22 -246
- package/lib/source.js +3 -3
- package/lib/update.js +40 -75
- package/lib/{git/proc.js → utilities.js} +75 -11
- package/lib/wrap.js +1 -3
- package/package.json +2 -2
- package/lib/deps/items.js +0 -134
- package/lib/deps/manifest.js +0 -152
- package/lib/deps/merge.js +0 -120
- package/lib/deps/proposals.js +0 -164
- package/lib/deps/reports.js +0 -180
- package/lib/deps/rows.js +0 -176
- package/lib/deps/scan.js +0 -138
- package/lib/deps/usage.js +0 -68
- package/lib/deps/versions.js +0 -119
- package/lib/diff.js +0 -33
- package/lib/git/changes.js +0 -164
- package/lib/git/read.js +0 -253
- package/lib/git/run.js +0 -100
- package/lib/npm/commands.js +0 -100
- package/lib/remote/changes.js +0 -37
- package/lib/remote/headers.js +0 -36
- package/lib/remote/http.js +0 -122
- package/lib/remote/notes.js +0 -94
- package/lib/review/format.js +0 -434
- package/lib/review/storage.js +0 -150
- package/lib/review/store.js +0 -178
- package/lib/review/templates.js +0 -49
- package/lib/session/origins.js +0 -7
- package/lib/sys.js +0 -84
package/lib/session/compose.js
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
const wrap = require('../wrap.js');
|
|
4
4
|
const { cursorInWrap, wrapDoc } = wrap;
|
|
5
|
-
const render = require('../render.js');
|
|
5
|
+
const render = require('../render/render.js');
|
|
6
6
|
const { noteInnerWidth, codeInnerWidth, todoBodyWidth } = render;
|
|
7
7
|
const { Editor } = require('../editor.js');
|
|
8
8
|
const files = require('../files.js');
|
|
9
|
-
const { itemPath, isTodoItem } = files;
|
|
10
|
-
const { blockAddText } = require('../diff.js');
|
|
9
|
+
const { itemPath, isTodoItem, listPath, isReadOnlyOrigin } = files;
|
|
10
|
+
const { blockAddText } = require('../diff/diff.js');
|
|
11
11
|
const items = require('./items.js');
|
|
12
12
|
const { itemFeedKey, canEditCode } = items;
|
|
13
|
-
const { isReadOnlyOrigin } = require('./origins.js');
|
|
14
13
|
const review = require('../review.js');
|
|
15
14
|
const { setFeedback, setCode, checkLabel, rememberTemplate } = review;
|
|
16
15
|
const { createTemplatePick } = require('./templates.js');
|
|
17
16
|
const { createTodoCompose } = require('./todos.js');
|
|
17
|
+
const unit = require('./unit.js');
|
|
18
18
|
|
|
19
19
|
const COMPOSE_EDITS = ['backspace', 'delete', 'ctrl-z', 'ctrl-y'];
|
|
20
20
|
const COMPOSE_LEAVE = ['next', 'prev', 'todo'];
|
|
@@ -36,6 +36,14 @@ const KIND = {
|
|
|
36
36
|
command: null,
|
|
37
37
|
view: 'code',
|
|
38
38
|
},
|
|
39
|
+
file: {
|
|
40
|
+
enter: 'newline',
|
|
41
|
+
tab: 'insert-tab',
|
|
42
|
+
escape: 'save',
|
|
43
|
+
move: 'code',
|
|
44
|
+
command: null,
|
|
45
|
+
view: 'code',
|
|
46
|
+
},
|
|
39
47
|
todo: {
|
|
40
48
|
enter: 'edit-next',
|
|
41
49
|
tab: 'template',
|
|
@@ -72,6 +80,8 @@ const initialState = () => ({
|
|
|
72
80
|
templateFocus: false,
|
|
73
81
|
blinkOn: true,
|
|
74
82
|
fileDirty: false,
|
|
83
|
+
fileEditRows: null,
|
|
84
|
+
fileOpened: '',
|
|
75
85
|
});
|
|
76
86
|
|
|
77
87
|
const reset = (state) => {
|
|
@@ -91,6 +101,18 @@ const tickBlink = (api) => {
|
|
|
91
101
|
|
|
92
102
|
const viewSize = (api) => api.ui.lastSize ?? api.ui.getSize();
|
|
93
103
|
|
|
104
|
+
const followFileEdit = (api) => {
|
|
105
|
+
if (api.state.composeKind !== 'file') return;
|
|
106
|
+
const text = api.state.editor ? api.state.editor.text : null;
|
|
107
|
+
const rows = unit.linesFor(
|
|
108
|
+
api.ui,
|
|
109
|
+
api.nav.reviewPath,
|
|
110
|
+
text,
|
|
111
|
+
api.state.fileEditRows,
|
|
112
|
+
);
|
|
113
|
+
unit.followFileCursor(api.nav, api.state.editor, api.ui.lastFrame, rows);
|
|
114
|
+
};
|
|
115
|
+
|
|
94
116
|
const afterClose = (api) => {
|
|
95
117
|
api.ui.clampIndex();
|
|
96
118
|
api.ui.syncReviewPath();
|
|
@@ -103,6 +125,7 @@ const openCompose = (api, kind, text, todoId) => {
|
|
|
103
125
|
state.composeKind = kind;
|
|
104
126
|
state.composeTodoId = todoId ?? null;
|
|
105
127
|
state.composeBaseline = text;
|
|
128
|
+
state.fileOpened = kind === 'file' ? text : '';
|
|
106
129
|
state.editor = new Editor(text);
|
|
107
130
|
state.templateIndex = -1;
|
|
108
131
|
state.templateFocus = false;
|
|
@@ -119,8 +142,10 @@ const closeCompose = (api) => {
|
|
|
119
142
|
state.commitKind = null;
|
|
120
143
|
state.composeTodoId = null;
|
|
121
144
|
state.composeBaseline = '';
|
|
145
|
+
state.fileOpened = '';
|
|
122
146
|
state.templateIndex = -1;
|
|
123
147
|
state.templateFocus = false;
|
|
148
|
+
state.fileEditRows = null;
|
|
124
149
|
afterClose(api);
|
|
125
150
|
};
|
|
126
151
|
|
|
@@ -167,8 +192,7 @@ const saveCodeNote = (api, item, text) => {
|
|
|
167
192
|
const key = itemFeedKey(item);
|
|
168
193
|
const note = itemNote(item, text);
|
|
169
194
|
if (text === original) {
|
|
170
|
-
setCode(notes, key, { ...note, clear: true });
|
|
171
|
-
return;
|
|
195
|
+
return void setCode(notes, key, { ...note, clear: true });
|
|
172
196
|
}
|
|
173
197
|
setCode(notes, key, note);
|
|
174
198
|
};
|
|
@@ -198,6 +222,91 @@ const commitCode = (api, text) => {
|
|
|
198
222
|
return true;
|
|
199
223
|
};
|
|
200
224
|
|
|
225
|
+
const saveUnitFile = (api, text) => {
|
|
226
|
+
const rel = api.nav.reviewPath;
|
|
227
|
+
const repo = api.ui.repo;
|
|
228
|
+
if (!rel || !repo || typeof repo.writeFile !== 'function') return true;
|
|
229
|
+
const caps = api.ui.capabilities;
|
|
230
|
+
if (!caps || caps.changes !== true) {
|
|
231
|
+
api.ui.status = 'read only';
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
repo.writeFile(api.ui.top, rel, text);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
api.ui.status = error.message;
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (typeof api.ui.ignoreWatch === 'function') api.ui.ignoreWatch();
|
|
241
|
+
api.state.composeBaseline = text;
|
|
242
|
+
api.state.fileDirty = true;
|
|
243
|
+
return true;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const stageEditedFile = (api, rel) => {
|
|
247
|
+
if (!rel) return false;
|
|
248
|
+
const repo = api.ui.repo;
|
|
249
|
+
if (!repo) return false;
|
|
250
|
+
const caps = api.ui.capabilities;
|
|
251
|
+
if (!caps || caps.changes !== true) return false;
|
|
252
|
+
if (typeof repo.stagePath === 'function') {
|
|
253
|
+
try {
|
|
254
|
+
repo.stagePath(api.ui.top, rel);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
api.ui.status = error.message;
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
if (typeof api.ui.ignoreWatch === 'function') api.ui.ignoreWatch();
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
if (typeof repo.add !== 'function') return false;
|
|
263
|
+
let staged = 0;
|
|
264
|
+
for (const item of api.ui.items ?? []) {
|
|
265
|
+
if (listPath(item) !== rel) continue;
|
|
266
|
+
if (isReadOnlyOrigin(item.origin)) continue;
|
|
267
|
+
if (item.origin === 'staged') continue;
|
|
268
|
+
try {
|
|
269
|
+
repo.add(api.ui.top, item);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
api.ui.status = error.message;
|
|
272
|
+
return staged > 0;
|
|
273
|
+
}
|
|
274
|
+
if (api.ui.collection && api.ui.collection.keepOrigin) {
|
|
275
|
+
api.ui.collection.keepOrigin(item, 'staged');
|
|
276
|
+
}
|
|
277
|
+
staged += 1;
|
|
278
|
+
}
|
|
279
|
+
if (staged && typeof api.ui.ignoreWatch === 'function') {
|
|
280
|
+
api.ui.ignoreWatch();
|
|
281
|
+
}
|
|
282
|
+
return staged > 0;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const saveFileCompose = (api) => {
|
|
286
|
+
const rel = api.nav.reviewPath;
|
|
287
|
+
const opened = api.state.fileOpened;
|
|
288
|
+
const text = api.state.editor ? api.state.editor.text : '';
|
|
289
|
+
if (api.state.editor) {
|
|
290
|
+
api.nav.unitLine = api.state.editor.linePos().line;
|
|
291
|
+
}
|
|
292
|
+
const result = saveUnitFile(api, text);
|
|
293
|
+
if (result === false) return { kind: 'error' };
|
|
294
|
+
const changed = text !== opened;
|
|
295
|
+
const reload = api.state.fileDirty === true;
|
|
296
|
+
if (changed) stageEditedFile(api, rel);
|
|
297
|
+
api.ui.flushReview();
|
|
298
|
+
closeCompose(api);
|
|
299
|
+
const doneStatus = changed ? 'staged' : 'saved';
|
|
300
|
+
if (!reload || typeof api.ui.reloadAfterChange !== 'function') {
|
|
301
|
+
if (!api.ui.status) api.ui.status = doneStatus;
|
|
302
|
+
return { kind: 'saved' };
|
|
303
|
+
}
|
|
304
|
+
api.ui.reloadAfterChange(() => {
|
|
305
|
+
if (!api.ui.status) api.ui.status = doneStatus;
|
|
306
|
+
});
|
|
307
|
+
return { kind: 'saved' };
|
|
308
|
+
};
|
|
309
|
+
|
|
201
310
|
const commitCompose = (api) => {
|
|
202
311
|
const { state } = api;
|
|
203
312
|
if (!state.composeKind || !state.editor) return true;
|
|
@@ -211,6 +320,7 @@ const commitCompose = (api) => {
|
|
|
211
320
|
return true;
|
|
212
321
|
}
|
|
213
322
|
if (state.composeKind === 'code') return commitCode(api, text);
|
|
323
|
+
if (state.composeKind === 'file') return saveUnitFile(api, text);
|
|
214
324
|
return true;
|
|
215
325
|
};
|
|
216
326
|
|
|
@@ -219,6 +329,14 @@ const saveCompose = (api, extra) => {
|
|
|
219
329
|
const spec = KIND[api.state.composeKind];
|
|
220
330
|
if (spec && spec.command) return { kind: spec.command };
|
|
221
331
|
const kind = api.state.composeKind;
|
|
332
|
+
if (kind === 'file') return saveFileCompose(api);
|
|
333
|
+
const item = api.ui.current ? api.ui.current() : null;
|
|
334
|
+
const shouldStage =
|
|
335
|
+
kind === 'code' &&
|
|
336
|
+
writesCodeFile(api, item) &&
|
|
337
|
+
item &&
|
|
338
|
+
item.origin !== 'staged';
|
|
339
|
+
const rel = itemPath(item);
|
|
222
340
|
const baseline = api.state.composeBaseline;
|
|
223
341
|
const result = commitCompose(api);
|
|
224
342
|
if (result === false) return { kind: 'error' };
|
|
@@ -229,12 +347,17 @@ const saveCompose = (api, extra) => {
|
|
|
229
347
|
const next = editor ? editor.text : '';
|
|
230
348
|
if (notes) rememberTemplate(notes, baseline, next);
|
|
231
349
|
}
|
|
350
|
+
if (shouldStage && reload) stageEditedFile(api, rel);
|
|
232
351
|
api.ui.flushReview();
|
|
233
352
|
closeCompose(api);
|
|
353
|
+
const doneStatus = shouldStage && reload ? 'staged' : 'saved';
|
|
234
354
|
if (reload && typeof api.ui.reloadAfterChange === 'function') {
|
|
235
|
-
api.ui.reloadAfterChange()
|
|
355
|
+
api.ui.reloadAfterChange(() => {
|
|
356
|
+
if (!api.ui.status) api.ui.status = doneStatus;
|
|
357
|
+
});
|
|
358
|
+
} else {
|
|
359
|
+
api.ui.status = doneStatus;
|
|
236
360
|
}
|
|
237
|
-
api.ui.status = 'saved';
|
|
238
361
|
if (opts.editNext === true) api.todos.editNextTodo();
|
|
239
362
|
return { kind: 'saved' };
|
|
240
363
|
};
|
|
@@ -243,6 +366,10 @@ const autosave = (api) => {
|
|
|
243
366
|
const { state } = api;
|
|
244
367
|
const spec = KIND[state.composeKind];
|
|
245
368
|
const text = state.editor ? state.editor.text : '';
|
|
369
|
+
if (state.composeKind === 'file' && state.editor) {
|
|
370
|
+
if (text === state.composeBaseline) return;
|
|
371
|
+
return void saveUnitFile(api, text);
|
|
372
|
+
}
|
|
246
373
|
const editingCode = state.composeKind === 'code';
|
|
247
374
|
const composing = state.composeKind !== null;
|
|
248
375
|
const reviewKind = composing && (!spec || !spec.command);
|
|
@@ -263,13 +390,14 @@ const composeView = (api) => {
|
|
|
263
390
|
const kind = state.composeKind;
|
|
264
391
|
const text = state.editor.text;
|
|
265
392
|
const cursor = state.editor.cursor;
|
|
266
|
-
return { kind, text, cursor };
|
|
393
|
+
return { kind, text, cursor, commitKind: state.commitKind };
|
|
267
394
|
};
|
|
268
395
|
|
|
269
396
|
const liveCodeText = (api) => {
|
|
397
|
+
const { state } = api;
|
|
398
|
+
if (state.composeKind === 'file' && state.editor) return state.editor.text;
|
|
270
399
|
const item = api.ui.current();
|
|
271
400
|
if (!canEditCode(item)) return null;
|
|
272
|
-
const { state } = api;
|
|
273
401
|
if (state.composeKind === 'code' && state.editor) return state.editor.text;
|
|
274
402
|
if (writesCodeFile(api, item)) return null;
|
|
275
403
|
const notes = api.review.store;
|
|
@@ -282,7 +410,8 @@ const liveCodeText = (api) => {
|
|
|
282
410
|
const codeOverlayView = (api) => {
|
|
283
411
|
const text = liveCodeText(api);
|
|
284
412
|
if (text === null) return null;
|
|
285
|
-
const editing =
|
|
413
|
+
const editing =
|
|
414
|
+
api.state.composeKind === 'code' || api.state.composeKind === 'file';
|
|
286
415
|
const editor = api.state.editor;
|
|
287
416
|
const cursor = editing && editor ? editor.cursor : null;
|
|
288
417
|
return { text, keepEmpty: editing, cursor };
|
|
@@ -351,14 +480,12 @@ const moveComposeLine = (api, delta) => {
|
|
|
351
480
|
if (move === 'todo') {
|
|
352
481
|
const size = viewSize(api);
|
|
353
482
|
const inner = todoBodyWidth(size.width);
|
|
354
|
-
api.todos.moveTodoCompose(delta, inner);
|
|
355
|
-
return;
|
|
483
|
+
return void api.todos.moveTodoCompose(delta, inner);
|
|
356
484
|
}
|
|
357
485
|
if (move === 'code') {
|
|
358
486
|
const size = viewSize(api);
|
|
359
487
|
const inner = codeInnerWidth(size.width, api.ui.layout);
|
|
360
|
-
api.state.editor.moveLine(delta, inner);
|
|
361
|
-
return;
|
|
488
|
+
return void api.state.editor.moveLine(delta, inner);
|
|
362
489
|
}
|
|
363
490
|
moveNoteLine(api, delta);
|
|
364
491
|
};
|
|
@@ -410,7 +537,26 @@ const onFeedback = (api) => {
|
|
|
410
537
|
openCompose(api, 'feedback', text);
|
|
411
538
|
};
|
|
412
539
|
|
|
540
|
+
const onUnitEdit = (api) => {
|
|
541
|
+
const rel = api.nav.reviewPath;
|
|
542
|
+
if (!rel) {
|
|
543
|
+
api.ui.status = 'not a diff block';
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const caps = api.ui.capabilities;
|
|
547
|
+
if (!caps || caps.changes !== true) {
|
|
548
|
+
api.ui.status = 'read only';
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const at = unit.editCursor(api.ui);
|
|
552
|
+
openCompose(api, 'file', at.text);
|
|
553
|
+
api.state.fileEditRows = at.rows ?? null;
|
|
554
|
+
api.state.editor.cursor = Math.min(at.cursor, at.text.length);
|
|
555
|
+
followFileEdit(api);
|
|
556
|
+
};
|
|
557
|
+
|
|
413
558
|
const onCode = (api) => {
|
|
559
|
+
if (api.nav.pane === 'unit') return void onUnitEdit(api);
|
|
414
560
|
if (api.nav.pane === 'files') {
|
|
415
561
|
api.ui.status = 'not a diff block';
|
|
416
562
|
return;
|
|
@@ -438,6 +584,7 @@ const enterCompose = (api) => {
|
|
|
438
584
|
if (spec && spec.enter === 'newline') {
|
|
439
585
|
state.editor.insert('\n');
|
|
440
586
|
resetBlink(api);
|
|
587
|
+
followFileEdit(api);
|
|
441
588
|
return null;
|
|
442
589
|
}
|
|
443
590
|
if (spec && spec.enter === 'edit-next') {
|
|
@@ -484,6 +631,7 @@ const handleKey = (api, key) => {
|
|
|
484
631
|
const result = special(api);
|
|
485
632
|
if (COMPOSE_EDITS.includes(key)) api.templates.clearTemplatePick();
|
|
486
633
|
resetBlink(api);
|
|
634
|
+
followFileEdit(api);
|
|
487
635
|
return result ?? null;
|
|
488
636
|
}
|
|
489
637
|
if (!key.length) return null;
|
|
@@ -492,10 +640,22 @@ const handleKey = (api, key) => {
|
|
|
492
640
|
api.templates.clearTemplatePick();
|
|
493
641
|
api.state.editor.insert(key);
|
|
494
642
|
resetBlink(api);
|
|
643
|
+
followFileEdit(api);
|
|
495
644
|
}
|
|
496
645
|
return null;
|
|
497
646
|
};
|
|
498
647
|
|
|
648
|
+
const applyDiskText = (api, text) => {
|
|
649
|
+
if (api.state.composeKind !== 'file' || !api.state.editor) return;
|
|
650
|
+
if (text === api.state.editor.text) return;
|
|
651
|
+
const cursor = api.state.editor.cursor;
|
|
652
|
+
api.state.editor.text = text;
|
|
653
|
+
api.state.editor.cursor = Math.min(cursor, text.length);
|
|
654
|
+
api.state.composeBaseline = text;
|
|
655
|
+
api.state.fileEditRows = unit.linesFor(api.ui, api.nav.reviewPath, null);
|
|
656
|
+
followFileEdit(api);
|
|
657
|
+
};
|
|
658
|
+
|
|
499
659
|
const composerMethods = (api) => ({
|
|
500
660
|
reset: () => reset(api.state),
|
|
501
661
|
openCompose: (kind, text, todoId) => openCompose(api, kind, text, todoId),
|
|
@@ -511,6 +671,12 @@ const composerMethods = (api) => ({
|
|
|
511
671
|
onFeedback: () => onFeedback(api),
|
|
512
672
|
onCode: () => onCode(api),
|
|
513
673
|
handleKey: (key) => handleKey(api, key),
|
|
674
|
+
liveFileText: () => {
|
|
675
|
+
if (api.state.composeKind !== 'file' || !api.state.editor) return null;
|
|
676
|
+
return api.state.editor.text;
|
|
677
|
+
},
|
|
678
|
+
fileEditRows: () => api.state.fileEditRows,
|
|
679
|
+
applyDiskText: (text) => applyDiskText(api, text),
|
|
514
680
|
});
|
|
515
681
|
|
|
516
682
|
const createComposer = ({ nav, review, ui, restartBlink }) => {
|
package/lib/session/dispatch.js
CHANGED
|
@@ -5,67 +5,92 @@ const { COMPOSE_LEAVE } = compose;
|
|
|
5
5
|
const actions = require('./actions.js');
|
|
6
6
|
const { CONFIRM_MODE, disabledActions, actionFromKey, applyConfirm } = actions;
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const targetHasStaged = (session) => {
|
|
9
|
+
if (session.repo.hasStaged) return session.repo.hasStaged(session.top);
|
|
10
|
+
return session.items.some((item) => item.origin === 'staged');
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const currentTarget = (ui) => {
|
|
14
|
+
if (ui.pane === 'files') return ui.fileCursorEntry();
|
|
15
|
+
if (ui.pane === 'branches') {
|
|
16
|
+
return ui.branches[ui.branchCursor];
|
|
17
|
+
}
|
|
18
|
+
if (ui.pane === 'commits') {
|
|
19
|
+
const entry = ui.commits.commits[ui.commitCursor];
|
|
20
|
+
const staged = targetHasStaged(ui);
|
|
21
|
+
if (!entry) return { canCommit: staged };
|
|
22
|
+
return { ...entry, canCommit: staged };
|
|
23
|
+
}
|
|
24
|
+
return ui.current();
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const createDispatcher = (ui) => {
|
|
9
28
|
const handlers = {
|
|
10
|
-
add:
|
|
11
|
-
unstage:
|
|
12
|
-
revert:
|
|
13
|
-
next:
|
|
14
|
-
prev:
|
|
15
|
-
layout:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
add: ui.changeActions.onAdd,
|
|
30
|
+
unstage: ui.changeActions.onUnstage,
|
|
31
|
+
revert: ui.changeActions.onRevert,
|
|
32
|
+
next: ui.filesPane.onNext,
|
|
33
|
+
prev: ui.filesPane.onPrev,
|
|
34
|
+
layout: ui.filesPane.onLayout,
|
|
35
|
+
theme: ui.filesPane.onTheme,
|
|
36
|
+
files: ui.filesPane.onFiles,
|
|
37
|
+
feedback: ui.composer.onFeedback,
|
|
38
|
+
todo: ui.composer.onTodo,
|
|
39
|
+
code: ui.composer.onCode,
|
|
40
|
+
reload: ui.lifecycle.onReload,
|
|
41
|
+
commit: ui.commits.onCommit,
|
|
42
|
+
amend: ui.commits.onAmend,
|
|
43
|
+
reword: ui.commits.onReword,
|
|
44
|
+
apply: ui.commits.onApply,
|
|
45
|
+
fixup: ui.commits.onFixup,
|
|
46
|
+
branch: ui.gitBranches.onBranch,
|
|
47
|
+
pull: ui.gitBranches.onPull,
|
|
48
|
+
push: ui.gitBranches.onPush,
|
|
49
|
+
newBranch: ui.gitBranches.onNewBranch,
|
|
50
|
+
rebase: ui.gitBranches.onRebaseBranch,
|
|
29
51
|
drop: () => {
|
|
30
|
-
if (
|
|
31
|
-
return void
|
|
52
|
+
if (ui.pane === 'commits') {
|
|
53
|
+
return void ui.commits.onDropCommit();
|
|
32
54
|
}
|
|
33
|
-
|
|
55
|
+
ui.gitBranches.onDropBranch();
|
|
34
56
|
},
|
|
35
|
-
open:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
open: ui.filesPane.onOpenFile,
|
|
58
|
+
file: ui.filesPane.onFileScope,
|
|
59
|
+
diff: ui.filesPane.onDiffScope,
|
|
60
|
+
check: () => ui.composer.toggleFocusedTodo(),
|
|
61
|
+
removeTodo: ui.composer.removeFocusedTodo,
|
|
62
|
+
quit: () => ui.onQuit(),
|
|
63
|
+
scrollUp: () => ui.filesPane.onScroll(-1),
|
|
64
|
+
scrollDown: () => ui.filesPane.onScroll(1),
|
|
65
|
+
pageUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-1)),
|
|
66
|
+
pageDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(1)),
|
|
67
|
+
halfUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-0.5)),
|
|
68
|
+
halfDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(0.5)),
|
|
69
|
+
home: ui.filesPane.onHome,
|
|
70
|
+
end: ui.filesPane.onEnd,
|
|
46
71
|
};
|
|
47
72
|
|
|
48
73
|
const dispatch = (action) => {
|
|
49
|
-
if (CONFIRM_MODE.includes(
|
|
50
|
-
if (
|
|
74
|
+
if (CONFIRM_MODE.includes(ui.mode)) return;
|
|
75
|
+
if (ui.mode === 'compose') {
|
|
51
76
|
if (!COMPOSE_LEAVE.includes(action)) return;
|
|
52
|
-
const result =
|
|
77
|
+
const result = ui.composer.saveCompose();
|
|
53
78
|
if (result && result.kind === 'error') return;
|
|
54
79
|
}
|
|
55
|
-
const pane =
|
|
80
|
+
const pane = ui.pane;
|
|
56
81
|
if (pane === 'files') {
|
|
57
|
-
if (action === 'next') return void
|
|
58
|
-
if (action === 'prev') return void
|
|
82
|
+
if (action === 'next') return void ui.filesPane.onFileMove(1);
|
|
83
|
+
if (action === 'prev') return void ui.filesPane.onFileMove(-1);
|
|
59
84
|
}
|
|
60
85
|
if (pane === 'branches') {
|
|
61
|
-
if (action === 'next') return void
|
|
62
|
-
if (action === 'prev') return void
|
|
86
|
+
if (action === 'next') return void ui.gitBranches.onBranchMove(1);
|
|
87
|
+
if (action === 'prev') return void ui.gitBranches.onBranchMove(-1);
|
|
63
88
|
}
|
|
64
89
|
if (pane === 'commits') {
|
|
65
|
-
if (action === 'next') return void
|
|
66
|
-
if (action === 'prev') return void
|
|
90
|
+
if (action === 'next') return void ui.commits.onCommitMove(1);
|
|
91
|
+
if (action === 'prev') return void ui.commits.onCommitMove(-1);
|
|
67
92
|
}
|
|
68
|
-
const hidden = disabledActions(pane,
|
|
93
|
+
const hidden = disabledActions(pane, currentTarget(ui));
|
|
69
94
|
if (hidden.includes(action)) return;
|
|
70
95
|
const handler = handlers[action];
|
|
71
96
|
if (!handler) return;
|
|
@@ -75,38 +100,63 @@ const createDispatcher = (options) => {
|
|
|
75
100
|
return { dispatch, handlers };
|
|
76
101
|
};
|
|
77
102
|
|
|
78
|
-
const createInput = (
|
|
103
|
+
const createInput = (ui) => {
|
|
79
104
|
const confirmations = {
|
|
80
|
-
confirmQuit:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
105
|
+
confirmQuit: {
|
|
106
|
+
ready: () => ui.finishQuit('ready'),
|
|
107
|
+
editing: () => ui.finishQuit('editing'),
|
|
108
|
+
cancel: () => ui.cancelQuit(),
|
|
109
|
+
},
|
|
110
|
+
confirmUpdate: {
|
|
111
|
+
accept: ui.updater.accept,
|
|
112
|
+
decline: ui.updater.decline,
|
|
113
|
+
},
|
|
114
|
+
confirmDrop: {
|
|
115
|
+
confirm: () => {
|
|
116
|
+
if (ui.commits.dropName) {
|
|
117
|
+
return void ui.commits.confirmDropCommit();
|
|
118
|
+
}
|
|
119
|
+
ui.gitBranches.confirmDropBranch();
|
|
120
|
+
},
|
|
121
|
+
cancel: () => {
|
|
122
|
+
if (ui.commits.dropName) {
|
|
123
|
+
return void ui.commits.cancelDropCommit();
|
|
124
|
+
}
|
|
125
|
+
ui.gitBranches.cancelDropBranch();
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
confirmPush: {
|
|
129
|
+
force: ui.gitBranches.onForcePush,
|
|
130
|
+
cancel: ui.gitBranches.cancelPush,
|
|
131
|
+
},
|
|
84
132
|
};
|
|
85
133
|
|
|
86
134
|
const confirmChoice = (key) => {
|
|
87
|
-
const mode =
|
|
135
|
+
const mode = ui.mode;
|
|
88
136
|
if (!CONFIRM_MODE.includes(mode)) return;
|
|
89
137
|
applyConfirm(mode, key, confirmations[mode]);
|
|
90
138
|
};
|
|
91
139
|
|
|
92
140
|
const handleKey = (key) => {
|
|
93
|
-
const mode =
|
|
141
|
+
const mode = ui.mode;
|
|
94
142
|
if (CONFIRM_MODE.includes(mode)) return void confirmChoice(key);
|
|
95
143
|
if (mode === 'compose') {
|
|
96
|
-
if (key === 'ctrl-c') return void
|
|
97
|
-
const command =
|
|
98
|
-
return void
|
|
144
|
+
if (key === 'ctrl-c') return void ui.onQuit();
|
|
145
|
+
const command = ui.composer.handleKey(key);
|
|
146
|
+
return void ui.runComposeCommand(command);
|
|
99
147
|
}
|
|
100
|
-
if (key === 'escape') return void
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
148
|
+
if (key === 'escape') return void ui.filesPane.onEscape();
|
|
149
|
+
const toggle = key === 'x' || key === ' ';
|
|
150
|
+
if (toggle && ui.composer.toggleFocusedTodo()) return;
|
|
151
|
+
if (ui.composer.typeIntoTodo(key)) return;
|
|
152
|
+
const action = actionFromKey(key, ui.pane, ui.fileScope);
|
|
153
|
+
if (action) ui.dispatch(action);
|
|
104
154
|
};
|
|
105
155
|
|
|
106
156
|
const handleEvent = (event) => {
|
|
107
157
|
if (event.type === 'key') return void handleKey(event.key);
|
|
108
158
|
if (event.type !== 'mouse') return;
|
|
109
|
-
|
|
159
|
+
ui.pointer.handle(event);
|
|
110
160
|
};
|
|
111
161
|
|
|
112
162
|
return { handleEvent, confirmChoice };
|