reslop 0.2.1 → 0.2.4
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 +19 -4
- package/bin/reslop.js +4 -2
- package/lib/ansi.js +120 -4
- package/lib/api.js +2 -1
- package/lib/cli.js +21 -9
- package/lib/clipboard.js +6 -3
- package/lib/deps-diff.js +61 -115
- package/lib/deps.js +57 -54
- 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 +2 -1
- package/lib/diff/patch.js +2 -1
- package/lib/diff/unit.js +4 -2
- package/lib/editor.js +22 -4
- package/lib/files.js +38 -12
- package/lib/git-branches.js +150 -165
- package/lib/git-deps.js +20 -60
- package/lib/git-worktree.js +508 -0
- package/lib/git.js +23 -580
- package/lib/github.js +2 -1
- package/lib/gitlab.js +2 -1
- package/lib/highlight/bash.js +2 -1
- package/lib/highlight/css.js +2 -1
- package/lib/highlight/csv.js +2 -1
- package/lib/highlight/dot.js +2 -1
- package/lib/highlight/html.js +2 -1
- package/lib/highlight/json.js +2 -1
- package/lib/highlight/log.js +2 -1
- package/lib/highlight/txt.js +2 -1
- package/lib/highlight.js +2 -1
- package/lib/keys.js +12 -6
- package/lib/manifest.js +4 -2
- package/lib/npm-commands.js +592 -0
- package/lib/remote.js +20 -13
- package/lib/render/branches.js +25 -41
- package/lib/render/chrome.js +163 -128
- package/lib/render/commits.js +727 -65
- package/lib/render/diff.js +130 -47
- package/lib/render/files.js +4 -12
- package/lib/render/frame.js +41 -13
- package/lib/render/notes.js +4 -11
- package/lib/render/npm.js +216 -0
- package/lib/render/present.js +2 -1
- package/lib/render/primitives.js +34 -50
- package/lib/render/render.js +2 -1
- package/lib/render/unit.js +14 -11
- package/lib/report-model.js +129 -0
- package/lib/report-parse.js +89 -0
- package/lib/report-render.js +104 -0
- package/lib/report-run.js +166 -0
- package/lib/report-test.js +507 -0
- package/lib/report-tools.js +337 -0
- package/lib/review-merge.js +2 -1
- package/lib/review.js +6 -2
- package/lib/session/actions.js +77 -44
- package/lib/session/branches.js +13 -49
- package/lib/session/change-actions.js +2 -1
- package/lib/session/commit.js +113 -53
- package/lib/session/compose.js +83 -14
- package/lib/session/dispatch.js +42 -22
- package/lib/session/files-pane.js +16 -21
- package/lib/session/items.js +6 -3
- package/lib/session/lifecycle.js +12 -5
- package/lib/session/load.js +4 -2
- package/lib/session/navigation.js +2 -0
- package/lib/session/npm.js +388 -0
- package/lib/session/ops.js +15 -1
- package/lib/session/pointer.js +30 -3
- package/lib/session/review.js +2 -1
- package/lib/session/terminal.js +4 -2
- package/lib/session/update.js +2 -1
- package/lib/session/view.js +41 -4
- package/lib/session.js +44 -22
- package/lib/source.js +6 -3
- package/lib/update.js +5 -9
- package/lib/utilities.js +4 -2
- package/lib/wrap.js +3 -1
- package/package.json +6 -6
package/lib/session/commit.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const {
|
|
3
|
+
const accessors = require('./accessors.js');
|
|
4
|
+
const { stateView } = accessors;
|
|
5
|
+
|
|
6
|
+
const files = require('../files.js');
|
|
7
|
+
const { isReadOnlyOrigin } = files;
|
|
8
|
+
const actions = require('./actions.js');
|
|
9
|
+
const { isFixupCommit } = actions;
|
|
10
|
+
const ops = require('./ops.js');
|
|
11
|
+
const { pickRepoWrite } = ops;
|
|
12
|
+
const commits = require('../render/commits.js');
|
|
13
|
+
const { commitLine, commitText, splitMessage } = commits;
|
|
8
14
|
|
|
9
15
|
const COMMIT_STATUS = {
|
|
10
16
|
commit: 'committed',
|
|
@@ -15,8 +21,37 @@ const COMMIT_STATUS = {
|
|
|
15
21
|
|
|
16
22
|
const isInPlaceCommit = (kind) => kind === 'amend' || kind === 'reword';
|
|
17
23
|
|
|
24
|
+
const PENDING_COMMIT = {
|
|
25
|
+
pending: true,
|
|
26
|
+
subject: 'uncommitted changes',
|
|
27
|
+
sha: '',
|
|
28
|
+
shortSha: '',
|
|
29
|
+
author: '',
|
|
30
|
+
email: '',
|
|
31
|
+
date: '',
|
|
32
|
+
when: '',
|
|
33
|
+
refs: '',
|
|
34
|
+
body: '',
|
|
35
|
+
head: false,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const listedCommits = (commits) => [PENDING_COMMIT].concat(commits ?? []);
|
|
39
|
+
|
|
40
|
+
const isPending = (entry) => Boolean(entry && entry.pending);
|
|
41
|
+
|
|
42
|
+
const briefCommit = (ui) => ui.commits.commitView !== 'full';
|
|
43
|
+
|
|
44
|
+
const joinMessage = (line, rest) => (rest ? `${line}\n${rest}` : line);
|
|
45
|
+
|
|
46
|
+
const keepBriefBody = (ui, text) => {
|
|
47
|
+
if (!briefCommit(ui)) return text;
|
|
48
|
+
const parts = splitMessage(text);
|
|
49
|
+
ui.composer.state.commitBody = parts.rest;
|
|
50
|
+
return parts.line;
|
|
51
|
+
};
|
|
52
|
+
|
|
18
53
|
const fixupMessage = (entry) => {
|
|
19
|
-
const subject =
|
|
54
|
+
const subject = commitLine(entry).trim();
|
|
20
55
|
if (!subject) return 'fixup!';
|
|
21
56
|
return `fixup! ${subject}`;
|
|
22
57
|
};
|
|
@@ -47,11 +82,11 @@ const hasStagedChanges = (ui) => {
|
|
|
47
82
|
|
|
48
83
|
const selectedCommit = (api) => {
|
|
49
84
|
const cursor = api.ui.nav.commitCursor;
|
|
50
|
-
return api.state.commits[cursor] ?? null;
|
|
85
|
+
return listedCommits(api.state.commits)[cursor] ?? null;
|
|
51
86
|
};
|
|
52
87
|
|
|
53
88
|
const clampCommitCursor = (api) => {
|
|
54
|
-
const last = api.state.commits.length - 1;
|
|
89
|
+
const last = listedCommits(api.state.commits).length - 1;
|
|
55
90
|
const nav = api.ui.nav;
|
|
56
91
|
if (nav.commitCursor > last) nav.commitCursor = Math.max(0, last);
|
|
57
92
|
};
|
|
@@ -75,7 +110,6 @@ const refreshAfterWrite = (api, extra = {}) => {
|
|
|
75
110
|
|
|
76
111
|
const showCommits = (api) => {
|
|
77
112
|
if (api.ui.mode === 'compose') return;
|
|
78
|
-
if (!canCommit(api.ui)) return;
|
|
79
113
|
const repo = api.ui.repo;
|
|
80
114
|
if (!repo.listCommits) {
|
|
81
115
|
api.ui.status = 'read only';
|
|
@@ -94,11 +128,8 @@ const showCommits = (api) => {
|
|
|
94
128
|
};
|
|
95
129
|
|
|
96
130
|
const onCommitMove = (api, delta) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
api.ui.status = 'nothing to review';
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
131
|
+
if (api.ui.mode === 'compose') return;
|
|
132
|
+
const commits = listedCommits(api.state.commits);
|
|
102
133
|
const next = Math.min(
|
|
103
134
|
commits.length - 1,
|
|
104
135
|
Math.max(0, api.ui.nav.commitCursor + delta),
|
|
@@ -117,15 +148,13 @@ const startGitCommit = (api, kind) => {
|
|
|
117
148
|
return;
|
|
118
149
|
}
|
|
119
150
|
let text = '';
|
|
120
|
-
if (kind === 'fixup')
|
|
121
|
-
|
|
122
|
-
}
|
|
151
|
+
if (kind === 'fixup') text = fixupMessage(selectedCommit(api));
|
|
152
|
+
if (kind === 'commit') api.ui.nav.commitCursor = 0;
|
|
123
153
|
if (kind === 'amend') {
|
|
124
154
|
const headAt = api.state.commits.findIndex((entry) => entry.head);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
155
|
+
const at = headAt < 0 ? 0 : headAt;
|
|
156
|
+
api.ui.nav.commitCursor = api.state.commits.length ? at + 1 : 0;
|
|
157
|
+
if (ui.repo.lastMessage) text = ui.repo.lastMessage(ui.top) ?? '';
|
|
129
158
|
}
|
|
130
159
|
if (kind === 'reword') {
|
|
131
160
|
const entry = selectedCommit(api);
|
|
@@ -133,19 +162,56 @@ const startGitCommit = (api, kind) => {
|
|
|
133
162
|
if (typeof ui.repo.commitMessage === 'function') {
|
|
134
163
|
text = ui.repo.commitMessage(ui.top, entry.sha) ?? '';
|
|
135
164
|
} else {
|
|
136
|
-
text =
|
|
165
|
+
text = commitText(entry);
|
|
137
166
|
}
|
|
138
167
|
}
|
|
168
|
+
ui.composer.state.commitBody = '';
|
|
169
|
+
if (isInPlaceCommit(kind)) text = keepBriefBody(ui, text);
|
|
139
170
|
ui.composer.state.commitKind = kind;
|
|
140
171
|
ui.composer.openCompose('commit', text);
|
|
172
|
+
const editor = ui.composer.state.editor;
|
|
173
|
+
if (!editor) return;
|
|
174
|
+
const lineEnd = editor.text.indexOf('\n');
|
|
175
|
+
editor.cursor = lineEnd < 0 ? editor.text.length : lineEnd;
|
|
141
176
|
};
|
|
142
177
|
|
|
143
178
|
const onCommit = (api) => {
|
|
144
179
|
if (api.ui.nav.pane !== 'commits') return void showCommits(api);
|
|
145
180
|
if (!canCommit(api.ui)) return;
|
|
181
|
+
api.ui.nav.commitCursor = 0;
|
|
146
182
|
startGitCommit(api, 'commit');
|
|
147
183
|
};
|
|
148
184
|
|
|
185
|
+
const openLoadedDiff = (ui) => {
|
|
186
|
+
ui.nav.todoOpen = false;
|
|
187
|
+
ui.nav.scroll = 0;
|
|
188
|
+
ui.nav.index = 0;
|
|
189
|
+
ui.nav.pane = ui.items.length ? 'diff' : 'files';
|
|
190
|
+
ui.syncReviewPath();
|
|
191
|
+
ui.syncFileCursor();
|
|
192
|
+
ui.status = '';
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const showSelectedDiff = (api) => {
|
|
196
|
+
if (api.ui.mode === 'compose') return;
|
|
197
|
+
const entry = selectedCommit(api);
|
|
198
|
+
if (!entry) return;
|
|
199
|
+
const ui = api.ui;
|
|
200
|
+
const viewingCommit = Boolean(ui.rev || ui.revShort);
|
|
201
|
+
if (isPending(entry) && !viewingCommit) return void onCommit(api);
|
|
202
|
+
if (isPending(entry) || !entry.sha) {
|
|
203
|
+
ui.rev = '';
|
|
204
|
+
ui.revShort = '';
|
|
205
|
+
} else {
|
|
206
|
+
ui.rev = entry.sha;
|
|
207
|
+
ui.revShort = entry.shortSha || '';
|
|
208
|
+
}
|
|
209
|
+
ui.refreshFromRepo({
|
|
210
|
+
keepEmpty: true,
|
|
211
|
+
afterLoad: () => openLoadedDiff(ui),
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
|
|
149
215
|
const onAmend = (api) => {
|
|
150
216
|
if (api.ui.nav.pane !== 'commits') return;
|
|
151
217
|
if (!canCommit(api.ui)) return;
|
|
@@ -167,18 +233,9 @@ const applyFixupNow = (api) => {
|
|
|
167
233
|
api.ui.status = 'read only';
|
|
168
234
|
return;
|
|
169
235
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const after = () => refreshAfterWrite(api, { doneStatus: done });
|
|
174
|
-
return void api.ui.ops.runBusy('applying', done, run, after);
|
|
175
|
-
}
|
|
176
|
-
const ok = api.ui.ops.runRepo(done, (top) => {
|
|
177
|
-
repo.applyFixup(top, entry.sha);
|
|
178
|
-
});
|
|
179
|
-
if (!ok) return;
|
|
180
|
-
refreshAfterWrite(api);
|
|
181
|
-
if (!api.ui.status) api.ui.status = done;
|
|
236
|
+
api.ui.ops.runWrite('applyFixup', [entry.sha], 'applying', done, (extra) =>
|
|
237
|
+
refreshAfterWrite(api, extra),
|
|
238
|
+
);
|
|
182
239
|
};
|
|
183
240
|
|
|
184
241
|
const onApply = (api) => {
|
|
@@ -260,7 +317,10 @@ const finishGitCommit = (api) => {
|
|
|
260
317
|
const ui = api.ui;
|
|
261
318
|
const kind = ui.composer.state.commitKind;
|
|
262
319
|
const editor = ui.composer.state.editor;
|
|
263
|
-
|
|
320
|
+
let message = editor ? editor.text : '';
|
|
321
|
+
if (isInPlaceCommit(kind) && briefCommit(ui)) {
|
|
322
|
+
message = joinMessage(message, ui.composer.state.commitBody);
|
|
323
|
+
}
|
|
264
324
|
if (!message.trim()) {
|
|
265
325
|
ui.status = 'empty commit message';
|
|
266
326
|
return;
|
|
@@ -298,12 +358,6 @@ const cancelDropCommit = (api) => {
|
|
|
298
358
|
api.ui.status = '';
|
|
299
359
|
};
|
|
300
360
|
|
|
301
|
-
const dropAsync = (api, sha, done, write) => {
|
|
302
|
-
const run = (top) => write(top, sha);
|
|
303
|
-
const after = () => refreshAfterWrite(api, { doneStatus: done });
|
|
304
|
-
return void api.ui.ops.runBusy('dropping', done, run, after);
|
|
305
|
-
};
|
|
306
|
-
|
|
307
361
|
const confirmDropCommit = (api) => {
|
|
308
362
|
const sha = api.state.dropSha;
|
|
309
363
|
const name = api.state.dropName;
|
|
@@ -317,23 +371,24 @@ const confirmDropCommit = (api) => {
|
|
|
317
371
|
api.ui.status = 'read only';
|
|
318
372
|
return;
|
|
319
373
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
374
|
+
api.ui.ops.runWrite('dropCommit', [sha], 'dropping', done, (extra) =>
|
|
375
|
+
refreshAfterWrite(api, extra),
|
|
376
|
+
);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const onView = (api) => {
|
|
380
|
+
if (api.ui.nav.pane !== 'commits') return;
|
|
381
|
+
const next = api.state.commitView === 'full' ? 'brief' : 'full';
|
|
382
|
+
api.state.commitView = next;
|
|
383
|
+
api.ui.nav.listScroll = 0;
|
|
384
|
+
api.ui.status = next;
|
|
331
385
|
};
|
|
332
386
|
|
|
333
387
|
const reset = (state) => {
|
|
334
388
|
state.commits = [];
|
|
335
389
|
state.dropName = '';
|
|
336
390
|
state.dropSha = '';
|
|
391
|
+
state.commitView = 'brief';
|
|
337
392
|
};
|
|
338
393
|
|
|
339
394
|
const createCommitController = (ui) => {
|
|
@@ -341,6 +396,7 @@ const createCommitController = (ui) => {
|
|
|
341
396
|
commits: [],
|
|
342
397
|
dropName: '',
|
|
343
398
|
dropSha: '',
|
|
399
|
+
commitView: 'brief',
|
|
344
400
|
};
|
|
345
401
|
const api = { ui, state };
|
|
346
402
|
return stateView(
|
|
@@ -354,6 +410,8 @@ const createCommitController = (ui) => {
|
|
|
354
410
|
onApply: () => onApply(api),
|
|
355
411
|
onFixup: () => onFixup(api),
|
|
356
412
|
onCommitMove: (delta) => onCommitMove(api, delta),
|
|
413
|
+
onShowDiff: () => showSelectedDiff(api),
|
|
414
|
+
onView: () => onView(api),
|
|
357
415
|
cancelCommit: () => cancelCommit(api),
|
|
358
416
|
startGitCommit: (kind) => startGitCommit(api, kind),
|
|
359
417
|
finishGitCommit: () => finishGitCommit(api),
|
|
@@ -362,11 +420,13 @@ const createCommitController = (ui) => {
|
|
|
362
420
|
cancelDropCommit: () => cancelDropCommit(api),
|
|
363
421
|
confirmDropCommit: () => confirmDropCommit(api),
|
|
364
422
|
},
|
|
365
|
-
['commits', 'dropName'],
|
|
423
|
+
['commits', 'dropName', 'commitView'],
|
|
366
424
|
);
|
|
367
425
|
};
|
|
368
426
|
|
|
369
427
|
module.exports = {
|
|
370
428
|
COMMIT_STATUS,
|
|
429
|
+
hasStagedChanges,
|
|
371
430
|
createCommitController,
|
|
431
|
+
listedCommits,
|
|
372
432
|
};
|
package/lib/session/compose.js
CHANGED
|
@@ -4,16 +4,24 @@ const wrap = require('../wrap.js');
|
|
|
4
4
|
const { cursorInWrap, wrapDoc } = wrap;
|
|
5
5
|
const render = require('../render/render.js');
|
|
6
6
|
const { noteInnerWidth, codeInnerWidth, todoBodyWidth } = render;
|
|
7
|
-
const
|
|
7
|
+
const commits = require('../render/commits.js');
|
|
8
|
+
const { commitMessageWidth } = commits;
|
|
9
|
+
const commit = require('./commit.js');
|
|
10
|
+
const { listedCommits } = commit;
|
|
11
|
+
const editor = require('../editor.js');
|
|
12
|
+
const { Editor } = editor;
|
|
8
13
|
const files = require('../files.js');
|
|
9
14
|
const { itemPath, isTodoItem, listPath, isReadOnlyOrigin } = files;
|
|
10
|
-
const
|
|
15
|
+
const diff = require('../diff/diff.js');
|
|
16
|
+
const { blockAddText } = diff;
|
|
11
17
|
const items = require('./items.js');
|
|
12
18
|
const { itemFeedKey, canEditCode } = items;
|
|
13
19
|
const review = require('../review.js');
|
|
14
20
|
const { setFeedback, setCode, checkLabel, rememberTemplate } = review;
|
|
15
|
-
const
|
|
16
|
-
const {
|
|
21
|
+
const templates = require('./templates.js');
|
|
22
|
+
const { createTemplatePick } = templates;
|
|
23
|
+
const todos = require('./todos.js');
|
|
24
|
+
const { createTodoCompose } = todos;
|
|
17
25
|
const unit = require('./unit.js');
|
|
18
26
|
|
|
19
27
|
const COMPOSE_EDITS = ['backspace', 'delete', 'ctrl-z', 'ctrl-y'];
|
|
@@ -68,12 +76,21 @@ const KIND = {
|
|
|
68
76
|
command: 'branch',
|
|
69
77
|
view: 'note',
|
|
70
78
|
},
|
|
79
|
+
npm: {
|
|
80
|
+
enter: 'save',
|
|
81
|
+
tab: 'insert-tab',
|
|
82
|
+
escape: 'cancel',
|
|
83
|
+
move: 'note',
|
|
84
|
+
command: 'npm',
|
|
85
|
+
view: 'note',
|
|
86
|
+
},
|
|
71
87
|
};
|
|
72
88
|
|
|
73
89
|
const initialState = () => ({
|
|
74
90
|
editor: null,
|
|
75
91
|
composeKind: null,
|
|
76
92
|
commitKind: null,
|
|
93
|
+
commitBody: '',
|
|
77
94
|
composeTodoId: null,
|
|
78
95
|
composeBaseline: '',
|
|
79
96
|
templateIndex: -1,
|
|
@@ -101,6 +118,16 @@ const tickBlink = (api) => {
|
|
|
101
118
|
|
|
102
119
|
const viewSize = (api) => api.ui.lastSize ?? api.ui.getSize();
|
|
103
120
|
|
|
121
|
+
const syncCodeScroll = (api) => {
|
|
122
|
+
const kind = api.state.composeKind;
|
|
123
|
+
if (kind !== 'code' && kind !== 'file') return;
|
|
124
|
+
const ed = api.state.editor;
|
|
125
|
+
if (!ed) return;
|
|
126
|
+
const size = viewSize(api);
|
|
127
|
+
const inner = codeInnerWidth(size.width, api.ui.layout);
|
|
128
|
+
ed.reveal(inner);
|
|
129
|
+
};
|
|
130
|
+
|
|
104
131
|
const followFileEdit = (api) => {
|
|
105
132
|
if (api.state.composeKind !== 'file') return;
|
|
106
133
|
const text = api.state.editor ? api.state.editor.text : null;
|
|
@@ -140,6 +167,7 @@ const closeCompose = (api) => {
|
|
|
140
167
|
state.editor = null;
|
|
141
168
|
state.composeKind = null;
|
|
142
169
|
state.commitKind = null;
|
|
170
|
+
state.commitBody = '';
|
|
143
171
|
state.composeTodoId = null;
|
|
144
172
|
state.composeBaseline = '';
|
|
145
173
|
state.fileOpened = '';
|
|
@@ -414,7 +442,9 @@ const codeOverlayView = (api) => {
|
|
|
414
442
|
api.state.composeKind === 'code' || api.state.composeKind === 'file';
|
|
415
443
|
const editor = api.state.editor;
|
|
416
444
|
const cursor = editing && editor ? editor.cursor : null;
|
|
417
|
-
|
|
445
|
+
const picked = editing && editor ? editor.scrollCol : 0;
|
|
446
|
+
const scrollCol = picked ?? 0;
|
|
447
|
+
return { text, keepEmpty: editing, cursor, scrollCol };
|
|
418
448
|
};
|
|
419
449
|
|
|
420
450
|
const idleNoteText = (api) => {
|
|
@@ -474,6 +504,22 @@ const moveNoteLine = (api, delta) => {
|
|
|
474
504
|
api.state.editor.moveLine(delta, width);
|
|
475
505
|
};
|
|
476
506
|
|
|
507
|
+
const fullCommitEdit = (api) =>
|
|
508
|
+
api.state.composeKind === 'commit' && api.ui.commits.commitView === 'full';
|
|
509
|
+
|
|
510
|
+
const editedCommitEntry = (api) => {
|
|
511
|
+
const kind = api.state.commitKind;
|
|
512
|
+
if (kind !== 'amend' && kind !== 'reword') return null;
|
|
513
|
+
const list = listedCommits(api.ui.commits.commits);
|
|
514
|
+
return list[api.nav.commitCursor] ?? null;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
const moveCommitLine = (api, delta) => {
|
|
518
|
+
const size = viewSize(api);
|
|
519
|
+
const width = commitMessageWidth(editedCommitEntry(api), size.width);
|
|
520
|
+
api.state.editor.moveLine(delta, width);
|
|
521
|
+
};
|
|
522
|
+
|
|
477
523
|
const moveComposeLine = (api, delta) => {
|
|
478
524
|
const spec = KIND[api.state.composeKind];
|
|
479
525
|
const move = spec ? spec.move : 'note';
|
|
@@ -483,10 +529,10 @@ const moveComposeLine = (api, delta) => {
|
|
|
483
529
|
return void api.todos.moveTodoCompose(delta, inner);
|
|
484
530
|
}
|
|
485
531
|
if (move === 'code') {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
return void api.state.editor.moveLine(delta, inner);
|
|
532
|
+
api.state.editor.moveLine(delta);
|
|
533
|
+
return void syncCodeScroll(api);
|
|
489
534
|
}
|
|
535
|
+
if (fullCommitEdit(api)) return void moveCommitLine(api, delta);
|
|
490
536
|
moveNoteLine(api, delta);
|
|
491
537
|
};
|
|
492
538
|
|
|
@@ -552,6 +598,7 @@ const onUnitEdit = (api) => {
|
|
|
552
598
|
openCompose(api, 'file', at.text);
|
|
553
599
|
api.state.fileEditRows = at.rows ?? null;
|
|
554
600
|
api.state.editor.cursor = Math.min(at.cursor, at.text.length);
|
|
601
|
+
syncCodeScroll(api);
|
|
555
602
|
followFileEdit(api);
|
|
556
603
|
};
|
|
557
604
|
|
|
@@ -573,6 +620,22 @@ const onCode = (api) => {
|
|
|
573
620
|
: notes.code.get(itemFeedKey(item));
|
|
574
621
|
const text = prev ? prev.text : original;
|
|
575
622
|
openCompose(api, 'code', text);
|
|
623
|
+
syncCodeScroll(api);
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
const insertNewline = (api) => {
|
|
627
|
+
api.state.editor.insert('\n');
|
|
628
|
+
resetBlink(api);
|
|
629
|
+
followFileEdit(api);
|
|
630
|
+
return null;
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
const onEmptyLastLine = (editor) => {
|
|
634
|
+
if (!editor) return false;
|
|
635
|
+
const text = editor.text;
|
|
636
|
+
const lastBreak = text.lastIndexOf('\n');
|
|
637
|
+
if (editor.cursor < lastBreak + 1) return false;
|
|
638
|
+
return text.slice(lastBreak + 1).trim() === '';
|
|
576
639
|
};
|
|
577
640
|
|
|
578
641
|
const enterCompose = (api) => {
|
|
@@ -581,11 +644,10 @@ const enterCompose = (api) => {
|
|
|
581
644
|
return api.templates.selectTemplate(state.templateIndex);
|
|
582
645
|
}
|
|
583
646
|
const spec = KIND[state.composeKind];
|
|
584
|
-
if (spec && spec.enter === 'newline')
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
return null;
|
|
647
|
+
if (spec && spec.enter === 'newline') return insertNewline(api);
|
|
648
|
+
if (fullCommitEdit(api)) {
|
|
649
|
+
if (onEmptyLastLine(state.editor)) return saveCompose(api);
|
|
650
|
+
return insertNewline(api);
|
|
589
651
|
}
|
|
590
652
|
if (spec && spec.enter === 'edit-next') {
|
|
591
653
|
return saveCompose(api, { editNext: true });
|
|
@@ -624,7 +686,11 @@ const COMPOSE_SPECIAL = {
|
|
|
624
686
|
};
|
|
625
687
|
|
|
626
688
|
const handleKey = (api, key) => {
|
|
627
|
-
if (key === 'enter')
|
|
689
|
+
if (key === 'enter') {
|
|
690
|
+
const result = enterCompose(api);
|
|
691
|
+
syncCodeScroll(api);
|
|
692
|
+
return result;
|
|
693
|
+
}
|
|
628
694
|
if (key === 'escape' || key === 'ctrl-s') return leaveCompose(api, key);
|
|
629
695
|
const special = COMPOSE_SPECIAL[key];
|
|
630
696
|
if (special) {
|
|
@@ -632,6 +698,7 @@ const handleKey = (api, key) => {
|
|
|
632
698
|
if (COMPOSE_EDITS.includes(key)) api.templates.clearTemplatePick();
|
|
633
699
|
resetBlink(api);
|
|
634
700
|
followFileEdit(api);
|
|
701
|
+
syncCodeScroll(api);
|
|
635
702
|
return result ?? null;
|
|
636
703
|
}
|
|
637
704
|
if (!key.length) return null;
|
|
@@ -641,6 +708,7 @@ const handleKey = (api, key) => {
|
|
|
641
708
|
api.state.editor.insert(key);
|
|
642
709
|
resetBlink(api);
|
|
643
710
|
followFileEdit(api);
|
|
711
|
+
syncCodeScroll(api);
|
|
644
712
|
}
|
|
645
713
|
return null;
|
|
646
714
|
};
|
|
@@ -653,6 +721,7 @@ const applyDiskText = (api, text) => {
|
|
|
653
721
|
api.state.editor.cursor = Math.min(cursor, text.length);
|
|
654
722
|
api.state.composeBaseline = text;
|
|
655
723
|
api.state.fileEditRows = unit.linesFor(api.ui, api.nav.reviewPath, null);
|
|
724
|
+
syncCodeScroll(api);
|
|
656
725
|
followFileEdit(api);
|
|
657
726
|
};
|
|
658
727
|
|
package/lib/session/dispatch.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const compose = require('./compose.js');
|
|
4
|
+
const commit = require('./commit.js');
|
|
5
|
+
const { hasStagedChanges, listedCommits } = commit;
|
|
4
6
|
const { COMPOSE_LEAVE } = compose;
|
|
5
7
|
const actions = require('./actions.js');
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const {
|
|
9
|
+
LIST_PANES,
|
|
10
|
+
CONFIRM_MODE,
|
|
11
|
+
disabledActions,
|
|
12
|
+
actionFromKey,
|
|
13
|
+
applyConfirm,
|
|
14
|
+
} = actions;
|
|
12
15
|
|
|
13
16
|
const currentTarget = (ui) => {
|
|
14
17
|
if (ui.pane === 'files') return ui.fileCursorEntry();
|
|
@@ -16,10 +19,10 @@ const currentTarget = (ui) => {
|
|
|
16
19
|
return ui.branches[ui.branchCursor];
|
|
17
20
|
}
|
|
18
21
|
if (ui.pane === 'commits') {
|
|
19
|
-
const entry = ui.commits.commits[ui.commitCursor];
|
|
20
|
-
const staged =
|
|
21
|
-
|
|
22
|
-
return { ...entry, canCommit: staged };
|
|
22
|
+
const entry = listedCommits(ui.commits.commits)[ui.commitCursor];
|
|
23
|
+
const staged = hasStagedChanges(ui);
|
|
24
|
+
const unstagedCurrent = !ui.rev && !ui.revShort;
|
|
25
|
+
return { ...entry, canCommit: staged, unstagedCurrent };
|
|
23
26
|
}
|
|
24
27
|
return ui.current();
|
|
25
28
|
};
|
|
@@ -43,6 +46,7 @@ const createDispatcher = (ui) => {
|
|
|
43
46
|
reword: ui.commits.onReword,
|
|
44
47
|
apply: ui.commits.onApply,
|
|
45
48
|
fixup: ui.commits.onFixup,
|
|
49
|
+
view: () => ui.commits.onView(),
|
|
46
50
|
branch: ui.gitBranches.onBranch,
|
|
47
51
|
pull: ui.gitBranches.onPull,
|
|
48
52
|
push: ui.gitBranches.onPush,
|
|
@@ -57,8 +61,18 @@ const createDispatcher = (ui) => {
|
|
|
57
61
|
open: ui.filesPane.onOpenFile,
|
|
58
62
|
file: ui.filesPane.onFileScope,
|
|
59
63
|
diff: ui.filesPane.onDiffScope,
|
|
64
|
+
npm: ui.npm.open,
|
|
65
|
+
npmEdit: ui.npm.edit,
|
|
66
|
+
npmNew: ui.npm.create,
|
|
67
|
+
npmDrop: () => ui.npm.askDrop(),
|
|
68
|
+
npmLogs: () => ui.npm.askLogs(),
|
|
69
|
+
npmStop: () => ui.npm.closeView(),
|
|
70
|
+
npmRerun: () => ui.npm.rerun(),
|
|
60
71
|
check: () => ui.composer.toggleFocusedTodo(),
|
|
61
|
-
removeTodo:
|
|
72
|
+
removeTodo: () => {
|
|
73
|
+
if (ui.pane === 'npm') return void ui.npm.askDrop();
|
|
74
|
+
ui.composer.removeFocusedTodo();
|
|
75
|
+
},
|
|
62
76
|
quit: () => ui.onQuit(),
|
|
63
77
|
scrollUp: () => ui.filesPane.onScroll(-1),
|
|
64
78
|
scrollDown: () => ui.filesPane.onScroll(1),
|
|
@@ -78,17 +92,9 @@ const createDispatcher = (ui) => {
|
|
|
78
92
|
if (result && result.kind === 'error') return;
|
|
79
93
|
}
|
|
80
94
|
const pane = ui.pane;
|
|
81
|
-
if (pane === '
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
if (pane === 'branches') {
|
|
86
|
-
if (action === 'next') return void ui.gitBranches.onBranchMove(1);
|
|
87
|
-
if (action === 'prev') return void ui.gitBranches.onBranchMove(-1);
|
|
88
|
-
}
|
|
89
|
-
if (pane === 'commits') {
|
|
90
|
-
if (action === 'next') return void ui.commits.onCommitMove(1);
|
|
91
|
-
if (action === 'prev') return void ui.commits.onCommitMove(-1);
|
|
95
|
+
if (LIST_PANES.includes(pane) && (action === 'next' || action === 'prev')) {
|
|
96
|
+
ui.filesPane.onScroll(action === 'next' ? 1 : -1);
|
|
97
|
+
return;
|
|
92
98
|
}
|
|
93
99
|
const hidden = disabledActions(pane, currentTarget(ui));
|
|
94
100
|
if (hidden.includes(action)) return;
|
|
@@ -113,12 +119,14 @@ const createInput = (ui) => {
|
|
|
113
119
|
},
|
|
114
120
|
confirmDrop: {
|
|
115
121
|
confirm: () => {
|
|
122
|
+
if (ui.npm.dropName) return void ui.npm.confirmDrop();
|
|
116
123
|
if (ui.commits.dropName) {
|
|
117
124
|
return void ui.commits.confirmDropCommit();
|
|
118
125
|
}
|
|
119
126
|
ui.gitBranches.confirmDropBranch();
|
|
120
127
|
},
|
|
121
128
|
cancel: () => {
|
|
129
|
+
if (ui.npm.dropName) return void ui.npm.cancelDrop();
|
|
122
130
|
if (ui.commits.dropName) {
|
|
123
131
|
return void ui.commits.cancelDropCommit();
|
|
124
132
|
}
|
|
@@ -145,6 +153,18 @@ const createInput = (ui) => {
|
|
|
145
153
|
const command = ui.composer.handleKey(key);
|
|
146
154
|
return void ui.runComposeCommand(command);
|
|
147
155
|
}
|
|
156
|
+
if (ui.pane === 'npm' && ui.npm.viewing) {
|
|
157
|
+
if (key === 'escape') return void ui.npm.closeView();
|
|
158
|
+
if (key === 'r') return void ui.npm.rerun();
|
|
159
|
+
if (key === 'e' || key === 'n') return;
|
|
160
|
+
}
|
|
161
|
+
if (ui.pane === 'npm' && key === 'ctrl-up') return void ui.npm.reorder(-1);
|
|
162
|
+
if (ui.pane === 'npm' && key === 'ctrl-down') {
|
|
163
|
+
return void ui.npm.reorder(1);
|
|
164
|
+
}
|
|
165
|
+
if (ui.pane === 'npm' && (key === 'up' || key === 'down')) {
|
|
166
|
+
return void ui.npm.move(key === 'up' ? -1 : 1);
|
|
167
|
+
}
|
|
148
168
|
if (key === 'escape') return void ui.filesPane.onEscape();
|
|
149
169
|
const toggle = key === 'x' || key === ' ';
|
|
150
170
|
if (toggle && ui.composer.toggleFocusedTodo()) return;
|