reslop 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/LICENSE +1 -1
  3. package/README.md +12 -13
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +32 -19
  6. package/lib/capabilities.js +8 -12
  7. package/lib/cli.js +40 -74
  8. package/lib/clipboard.js +48 -18
  9. package/lib/dashboard/git.js +128 -0
  10. package/lib/dashboard/model.js +332 -0
  11. package/lib/dashboard/npm.js +193 -0
  12. package/lib/dashboard/tree.js +278 -0
  13. package/lib/deps-diff.js +196 -404
  14. package/lib/deps.js +240 -399
  15. package/lib/detect.js +8 -18
  16. package/lib/diff/align.js +41 -113
  17. package/lib/diff/diff.js +12 -43
  18. package/lib/diff/display.js +25 -36
  19. package/lib/diff/edit.js +6 -20
  20. package/lib/diff/inline.js +138 -141
  21. package/lib/diff/items.js +33 -47
  22. package/lib/diff/parse.js +28 -56
  23. package/lib/diff/patch.js +12 -33
  24. package/lib/diff/unit.js +90 -206
  25. package/lib/editor.js +98 -55
  26. package/lib/files.js +86 -103
  27. package/lib/git-branches.js +254 -416
  28. package/lib/git-deps.js +182 -344
  29. package/lib/git-reword-todo.js +5 -13
  30. package/lib/git-worktree.js +141 -212
  31. package/lib/git.js +21 -49
  32. package/lib/github.js +67 -181
  33. package/lib/gitlab.js +40 -90
  34. package/lib/highlight/bash.js +55 -177
  35. package/lib/highlight/core.js +157 -132
  36. package/lib/highlight/css.js +25 -58
  37. package/lib/highlight/csv.js +19 -37
  38. package/lib/highlight/dart.js +72 -213
  39. package/lib/highlight/dot.js +16 -26
  40. package/lib/highlight/html.js +42 -63
  41. package/lib/highlight/js.js +177 -506
  42. package/lib/highlight/json.js +17 -37
  43. package/lib/highlight/log.js +22 -35
  44. package/lib/highlight/txt.js +9 -22
  45. package/lib/highlight.js +17 -46
  46. package/lib/keys.js +62 -85
  47. package/lib/manifest.js +67 -130
  48. package/lib/npm-commands.js +119 -189
  49. package/lib/remote.js +141 -197
  50. package/lib/render/branches.js +66 -73
  51. package/lib/render/chrome.js +264 -323
  52. package/lib/render/commits.js +187 -500
  53. package/lib/render/dash-activity.js +212 -0
  54. package/lib/render/dash-blocks.js +245 -0
  55. package/lib/render/dash-table.js +290 -0
  56. package/lib/render/dashboard.js +62 -0
  57. package/lib/render/diff.js +123 -228
  58. package/lib/render/files.js +45 -99
  59. package/lib/render/frame.js +129 -183
  60. package/lib/render/notes.js +144 -160
  61. package/lib/render/npm.js +234 -112
  62. package/lib/render/present.js +4 -11
  63. package/lib/render/primitives.js +131 -170
  64. package/lib/render/render.js +5 -14
  65. package/lib/render/report.js +43 -0
  66. package/lib/render/tiles.js +260 -0
  67. package/lib/render/unit.js +15 -28
  68. package/lib/report-model.js +110 -33
  69. package/lib/report-parse.js +56 -38
  70. package/lib/report-render.js +102 -59
  71. package/lib/report-run.js +87 -78
  72. package/lib/report-test.js +256 -141
  73. package/lib/report-tools.js +96 -161
  74. package/lib/review-merge.js +114 -152
  75. package/lib/review.js +115 -189
  76. package/lib/runs.js +225 -0
  77. package/lib/select.js +89 -75
  78. package/lib/session/accessors.js +14 -21
  79. package/lib/session/actions.js +82 -63
  80. package/lib/session/branches.js +193 -247
  81. package/lib/session/change-actions.js +171 -214
  82. package/lib/session/commit.js +280 -342
  83. package/lib/session/compose.js +559 -674
  84. package/lib/session/dashboard.js +385 -0
  85. package/lib/session/dispatch.js +164 -157
  86. package/lib/session/edit-click.js +57 -0
  87. package/lib/session/files-pane.js +85 -53
  88. package/lib/session/items.js +73 -104
  89. package/lib/session/lifecycle.js +403 -541
  90. package/lib/session/load.js +48 -68
  91. package/lib/session/navigation.js +96 -87
  92. package/lib/session/npm.js +409 -345
  93. package/lib/session/ops.js +196 -63
  94. package/lib/session/pointer.js +23 -15
  95. package/lib/session/progress.js +33 -21
  96. package/lib/session/review.js +33 -54
  97. package/lib/session/tasks.js +333 -0
  98. package/lib/session/templates.js +51 -59
  99. package/lib/session/terminal.js +85 -136
  100. package/lib/session/unit.js +3 -4
  101. package/lib/session/update.js +76 -97
  102. package/lib/session/view.js +52 -83
  103. package/lib/session/watch.js +208 -204
  104. package/lib/session.js +112 -237
  105. package/lib/update.js +45 -116
  106. package/lib/utilities.js +67 -89
  107. package/lib/wrap.js +33 -44
  108. package/package.json +1 -1
  109. package/lib/session/todos.js +0 -293
@@ -1,8 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const accessors = require('./accessors.js');
4
- const { stateView } = accessors;
5
-
6
3
  const files = require('../files.js');
7
4
  const { isReadOnlyOrigin } = files;
8
5
  const actions = require('./actions.js');
@@ -37,17 +34,13 @@ const PENDING_COMMIT = {
37
34
 
38
35
  const listedCommits = (commits) => [PENDING_COMMIT].concat(commits ?? []);
39
36
 
40
- const isPending = (entry) => Boolean(entry && entry.pending);
41
-
42
- const briefCommit = (ui) => ui.commits.commitView !== 'full';
43
-
44
37
  const joinMessage = (line, rest) => (rest ? `${line}\n${rest}` : line);
45
38
 
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;
39
+ const tidyCommitMessage = (message) => {
40
+ const lines = `${message ?? ''}`.split('\n').map((line) => line.trim());
41
+ while (lines.length && lines[0] === '') lines.shift();
42
+ while (lines.length && lines[lines.length - 1] === '') lines.pop();
43
+ return lines.join('\n');
51
44
  };
52
45
 
53
46
  const fixupMessage = (entry) => {
@@ -56,377 +49,322 @@ const fixupMessage = (entry) => {
56
49
  return `fixup! ${subject}`;
57
50
  };
58
51
 
59
- const canCommit = (ui) => {
60
- const caps = ui.capabilities;
61
- if (!caps.branches) {
62
- ui.status = 'read only';
63
- return false;
64
- }
65
- for (const item of ui.items) {
66
- if (isReadOnlyOrigin(item.origin)) {
67
- ui.status = 'read only';
68
- return false;
69
- }
70
- }
71
- return true;
72
- };
73
-
74
52
  const hasStagedChanges = (ui) => {
75
53
  const repo = ui.repo;
76
54
  if (repo.hasStaged) return repo.hasStaged(ui.top);
77
- for (const item of ui.items) {
78
- if (item.origin === 'staged') return true;
79
- }
80
- return false;
55
+ return ui.items.some((item) => item.origin === 'staged');
81
56
  };
82
57
 
83
- const selectedCommit = (api) => {
84
- const cursor = api.ui.nav.commitCursor;
85
- return listedCommits(api.state.commits)[cursor] ?? null;
86
- };
87
-
88
- const clampCommitCursor = (api) => {
89
- const last = listedCommits(api.state.commits).length - 1;
90
- const nav = api.ui.nav;
91
- if (nav.commitCursor > last) nav.commitCursor = Math.max(0, last);
92
- };
93
-
94
- const refreshCommitList = (api) => {
95
- const repo = api.ui.repo;
96
- if (!repo.listCommits) return;
97
- try {
98
- api.state.commits = repo.listCommits(api.ui.top);
99
- } catch (error) {
100
- api.ui.status = error.message;
101
- return;
58
+ class CommitController {
59
+ constructor(ui) {
60
+ this.ui = ui;
61
+ this.reset();
102
62
  }
103
- clampCommitCursor(api);
104
- };
105
63
 
106
- const refreshAfterWrite = (api, extra = {}) => {
107
- refreshCommitList(api);
108
- api.ui.refreshFromRepo({ keepEmpty: true, ...extra });
109
- };
110
-
111
- const showCommits = (api) => {
112
- if (api.ui.mode === 'compose') return;
113
- const repo = api.ui.repo;
114
- if (!repo.listCommits) {
115
- api.ui.status = 'read only';
116
- return;
64
+ reset() {
65
+ this.commits = [];
66
+ this.dropName = '';
67
+ this.dropSha = '';
68
+ this.commitView = 'brief';
117
69
  }
118
- try {
119
- api.state.commits = repo.listCommits(api.ui.top);
120
- } catch (error) {
121
- api.ui.status = error.message;
122
- return;
70
+
71
+ get brief() {
72
+ return this.commitView !== 'full';
123
73
  }
124
- api.ui.nav.commitCursor = 0;
125
- api.ui.nav.pane = 'commits';
126
- api.ui.status = '';
127
- api.ui.nav.clearSelection();
128
- };
129
74
 
130
- const onCommitMove = (api, delta) => {
131
- if (api.ui.mode === 'compose') return;
132
- const commits = listedCommits(api.state.commits);
133
- const next = Math.min(
134
- commits.length - 1,
135
- Math.max(0, api.ui.nav.commitCursor + delta),
136
- );
137
- if (next === api.ui.nav.commitCursor) return;
138
- api.ui.nav.commitCursor = next;
139
- api.ui.status = '';
140
- };
75
+ canCommit() {
76
+ const ui = this.ui;
77
+ const readOnly =
78
+ !ui.capabilities.branches ||
79
+ ui.items.some((item) => isReadOnlyOrigin(item.origin));
80
+ if (readOnly) ui.status = 'read only';
81
+ return !readOnly;
82
+ }
141
83
 
142
- const startGitCommit = (api, kind) => {
143
- const ui = api.ui;
144
- if (!isInPlaceCommit(kind) && !hasStagedChanges(ui)) {
145
- ui.mode = 'review';
146
- ui.composer.state.commitKind = null;
147
- ui.status = 'nothing to commit';
148
- return;
84
+ canWrite() {
85
+ return this.ui.nav.pane === 'commits' && this.canCommit();
149
86
  }
150
- let text = '';
151
- if (kind === 'fixup') text = fixupMessage(selectedCommit(api));
152
- if (kind === 'commit') api.ui.nav.commitCursor = 0;
153
- if (kind === 'amend') {
154
- const headAt = api.state.commits.findIndex((entry) => entry.head);
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) ?? '';
87
+
88
+ selected() {
89
+ return listedCommits(this.commits)[this.ui.nav.commitCursor] ?? null;
158
90
  }
159
- if (kind === 'reword') {
160
- const entry = selectedCommit(api);
161
- if (!entry || !entry.sha) return;
162
- if (typeof ui.repo.commitMessage === 'function') {
163
- text = ui.repo.commitMessage(ui.top, entry.sha) ?? '';
164
- } else {
165
- text = commitText(entry);
91
+
92
+ loadCommits() {
93
+ const ui = this.ui;
94
+ try {
95
+ this.commits = ui.repo.listCommits(ui.top);
96
+ return true;
97
+ } catch (error) {
98
+ ui.status = error.message;
99
+ return false;
166
100
  }
167
101
  }
168
- ui.composer.state.commitBody = '';
169
- if (isInPlaceCommit(kind)) text = keepBriefBody(ui, text);
170
- ui.composer.state.commitKind = kind;
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;
176
- };
177
102
 
178
- const onCommit = (api) => {
179
- if (api.ui.nav.pane !== 'commits') return void showCommits(api);
180
- if (!canCommit(api.ui)) return;
181
- api.ui.nav.commitCursor = 0;
182
- startGitCommit(api, 'commit');
183
- };
103
+ refresh() {
104
+ if (!this.ui.repo.listCommits || !this.loadCommits()) return;
105
+ const last = listedCommits(this.commits).length - 1;
106
+ const nav = this.ui.nav;
107
+ if (nav.commitCursor > last) nav.commitCursor = Math.max(0, last);
108
+ }
184
109
 
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
- };
110
+ refreshAfterWrite(extra = {}) {
111
+ this.refresh();
112
+ this.ui.refreshFromRepo({ keepEmpty: true, ...extra });
113
+ }
194
114
 
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 || '';
115
+ indexForView() {
116
+ const ui = this.ui;
117
+ if (hasStagedChanges(ui)) return 0;
118
+ const list = listedCommits(this.commits);
119
+ const want = `${ui.rev ?? ''}`;
120
+ const short = `${ui.revShort ?? ''}`;
121
+ if (!want && !short) return 0;
122
+ for (let i = 0; i < list.length; i++) {
123
+ const entry = list[i];
124
+ if (entry.pending) continue;
125
+ const sha = `${entry.sha ?? ''}`;
126
+ const brief = `${entry.shortSha ?? ''}`;
127
+ if (want && sha === want) return i;
128
+ if (short && (brief === short || sha.startsWith(short))) return i;
129
+ }
130
+ return 0;
208
131
  }
209
- ui.refreshFromRepo({
210
- keepEmpty: true,
211
- afterLoad: () => openLoadedDiff(ui),
212
- });
213
- };
214
132
 
215
- const onAmend = (api) => {
216
- if (api.ui.nav.pane !== 'commits') return;
217
- if (!canCommit(api.ui)) return;
218
- startGitCommit(api, 'amend');
219
- };
133
+ show() {
134
+ const ui = this.ui;
135
+ if (ui.mode === 'compose') return;
136
+ if (!ui.repo.listCommits) {
137
+ ui.status = 'read only';
138
+ return;
139
+ }
140
+ if (!this.loadCommits()) return;
141
+ const nav = ui.nav;
142
+ nav.commitCursor = this.indexForView();
143
+ nav.pane = 'commits';
144
+ nav.resetListScroll('commits');
145
+ ui.status = '';
146
+ nav.clearSelection();
147
+ }
220
148
 
221
- const onReword = (api) => {
222
- if (api.ui.nav.pane !== 'commits') return;
223
- if (!canCommit(api.ui)) return;
224
- startGitCommit(api, 'reword');
225
- };
149
+ onCommitMove(delta) {
150
+ const nav = this.ui.nav;
151
+ if (this.ui.mode === 'compose') return;
152
+ const last = listedCommits(this.commits).length - 1;
153
+ const next = Math.min(last, Math.max(0, nav.commitCursor + delta));
154
+ if (next === nav.commitCursor) return;
155
+ nav.commitCursor = next;
156
+ this.ui.status = '';
157
+ }
226
158
 
227
- const applyFixupNow = (api) => {
228
- const entry = selectedCommit(api);
229
- if (!entry || !entry.sha) return;
230
- const done = 'applied';
231
- const repo = api.ui.repo;
232
- if (!repo.applyFixup) {
233
- api.ui.status = 'read only';
234
- return;
159
+ messageFor(kind) {
160
+ const ui = this.ui;
161
+ if (kind === 'fixup') return fixupMessage(this.selected());
162
+ if (kind === 'amend') {
163
+ const headAt = this.commits.findIndex((entry) => entry.head);
164
+ const at = headAt < 0 ? 0 : headAt;
165
+ ui.nav.commitCursor = this.commits.length ? at + 1 : 0;
166
+ if (ui.repo.lastMessage) return ui.repo.lastMessage(ui.top) ?? '';
167
+ return '';
168
+ }
169
+ if (kind === 'reword') {
170
+ const entry = this.selected();
171
+ if (!entry || !entry.sha) return null;
172
+ if (!ui.repo.commitMessage) return commitText(entry);
173
+ return ui.repo.commitMessage(ui.top, entry.sha) ?? '';
174
+ }
175
+ ui.nav.commitCursor = 0;
176
+ return '';
235
177
  }
236
- api.ui.ops.runWrite('applyFixup', [entry.sha], 'applying', done, (extra) =>
237
- refreshAfterWrite(api, extra),
238
- );
239
- };
240
178
 
241
- const onApply = (api) => {
242
- if (api.ui.nav.pane !== 'commits') return;
243
- if (!canCommit(api.ui)) return;
244
- const entry = selectedCommit(api);
245
- if (isFixupCommit(entry)) return void applyFixupNow(api);
246
- startGitCommit(api, 'amend');
247
- };
179
+ start(kind) {
180
+ const ui = this.ui;
181
+ const composer = ui.composer;
182
+ if (!isInPlaceCommit(kind) && !hasStagedChanges(ui)) {
183
+ ui.mode = 'review';
184
+ composer.commitKind = null;
185
+ ui.status = 'nothing to commit';
186
+ return;
187
+ }
188
+ let text = this.messageFor(kind);
189
+ if (text === null) return;
190
+ composer.commitBody = '';
191
+ if (isInPlaceCommit(kind) && this.brief) {
192
+ const parts = splitMessage(text);
193
+ composer.commitBody = parts.rest;
194
+ text = parts.line;
195
+ }
196
+ composer.commitKind = kind;
197
+ ui.composer.openCompose('commit', text);
198
+ const editor = composer.editor;
199
+ const lineEnd = editor.text.indexOf('\n');
200
+ editor.cursor = lineEnd < 0 ? editor.text.length : lineEnd;
201
+ }
248
202
 
249
- const onFixup = (api) => {
250
- if (api.ui.nav.pane !== 'commits') return;
251
- if (!canCommit(api.ui)) return;
252
- startGitCommit(api, 'fixup');
253
- };
203
+ onCommit() {
204
+ if (this.ui.nav.pane !== 'commits') return void this.show();
205
+ if (!this.canCommit()) return;
206
+ this.start('commit');
207
+ }
254
208
 
255
- const cancelCommit = (api) => {
256
- api.ui.mode = 'review';
257
- api.ui.composer.state.commitKind = null;
258
- api.ui.status = '';
259
- };
209
+ onShowDiff() {
210
+ const ui = this.ui;
211
+ if (ui.mode === 'compose') return;
212
+ const entry = this.selected();
213
+ if (!entry) return;
214
+ const viewingCommit = Boolean(ui.rev || ui.revShort);
215
+ if (entry.pending && !viewingCommit) return void this.onCommit();
216
+ const sha = entry.pending ? '' : entry.sha || '';
217
+ ui.rev = sha;
218
+ ui.revShort = sha ? entry.shortSha || '' : '';
219
+ const afterLoad = () => {
220
+ const nav = ui.nav;
221
+ nav.tasksOpen = false;
222
+ nav.scroll = 0;
223
+ nav.index = 0;
224
+ nav.pane = ui.items.length ? 'diff' : 'files';
225
+ ui.syncReviewPath();
226
+ ui.syncFileCursor();
227
+ ui.status = '';
228
+ };
229
+ ui.refreshFromRepo({ keepEmpty: true, afterLoad });
230
+ }
260
231
 
261
- const finishAsyncCommit = (api, kind, message, done, write) => {
262
- const ui = api.ui;
263
- ui.composer.closeCompose();
264
- const run = (top) => write(top, kind, message);
265
- const after = () => refreshAfterWrite(api, { doneStatus: done });
266
- return void ui.ops.runBusy('committing', done, run, after);
267
- };
232
+ onAmend() {
233
+ if (this.canWrite()) this.start('amend');
234
+ }
268
235
 
269
- const finishSyncCommit = (api, kind, message, done) => {
270
- const ui = api.ui;
271
- try {
272
- ui.repo.commit(ui.top, kind, message);
273
- } catch (error) {
274
- ui.status = error.message;
275
- return;
236
+ onReword() {
237
+ if (this.canWrite()) this.start('reword');
276
238
  }
277
- ui.composer.closeCompose();
278
- ui.collection.clearDismissed();
279
- refreshAfterWrite(api);
280
- if (!ui.done && !ui.pendingExtras) {
281
- ui.status = done;
239
+
240
+ onFixup() {
241
+ if (this.canWrite()) this.start('fixup');
282
242
  }
283
- };
284
243
 
285
- const finishReword = (api, message) => {
286
- const ui = api.ui;
287
- const entry = selectedCommit(api);
288
- if (!entry || !entry.sha) {
289
- ui.status = 'read only';
290
- return;
244
+ onApply() {
245
+ if (!this.canWrite()) return;
246
+ const entry = this.selected();
247
+ if (!isFixupCommit(entry)) return void this.start('amend');
248
+ if (!entry.sha) return;
249
+ if (!this.ui.repo.applyFixup) {
250
+ this.ui.status = 'read only';
251
+ return;
252
+ }
253
+ const after = (extra) => this.refreshAfterWrite(extra);
254
+ this.ui.ops.runWrite(
255
+ 'applyFixup',
256
+ [entry.sha],
257
+ 'applying',
258
+ 'applied',
259
+ after,
260
+ );
291
261
  }
292
- const done = COMMIT_STATUS.reword;
293
- const repo = ui.repo;
294
- if (!repo.reword) {
295
- ui.status = 'read only';
296
- return;
262
+
263
+ runAsync(kind, done, run) {
264
+ this.ui.composer.closeCompose();
265
+ const after = () => this.refreshAfterWrite({ doneStatus: done });
266
+ this.ui.ops.runBusy(kind, done, run, after);
297
267
  }
298
- const picked = pickRepoWrite(repo, 'reword', ui.uiOpen);
299
- if (picked.async) {
268
+
269
+ finishReword(message) {
270
+ const ui = this.ui;
271
+ const entry = this.selected();
272
+ if (!entry || !entry.sha || !ui.repo.reword) {
273
+ ui.status = 'read only';
274
+ return;
275
+ }
276
+ const done = COMMIT_STATUS.reword;
277
+ const picked = pickRepoWrite(ui.repo, 'reword', ui.uiOpen);
278
+ if (picked.async) {
279
+ const run = (top) => picked.write(top, entry.sha, message);
280
+ return void this.runAsync('rewording', done, run);
281
+ }
282
+ try {
283
+ ui.repo.reword(ui.top, entry.sha, message);
284
+ } catch (error) {
285
+ ui.status = error.message;
286
+ return;
287
+ }
300
288
  ui.composer.closeCompose();
301
- const run = (top) => picked.write(top, entry.sha, message);
302
- const after = () => refreshAfterWrite(api, { doneStatus: done });
303
- return void ui.ops.runBusy('rewording', done, run, after);
304
- }
305
- try {
306
- repo.reword(ui.top, entry.sha, message);
307
- } catch (error) {
308
- ui.status = error.message;
309
- return;
289
+ this.refreshAfterWrite();
290
+ if (!ui.status) ui.status = done;
310
291
  }
311
- ui.composer.closeCompose();
312
- refreshAfterWrite(api);
313
- if (!ui.status) ui.status = done;
314
- };
315
292
 
316
- const finishGitCommit = (api) => {
317
- const ui = api.ui;
318
- const kind = ui.composer.state.commitKind;
319
- const editor = ui.composer.state.editor;
320
- let message = editor ? editor.text : '';
321
- if (isInPlaceCommit(kind) && briefCommit(ui)) {
322
- message = joinMessage(message, ui.composer.state.commitBody);
323
- }
324
- if (!message.trim()) {
325
- ui.status = 'empty commit message';
326
- return;
327
- }
328
- if (!isInPlaceCommit(kind) && !hasStagedChanges(ui)) {
293
+ finishGitCommit() {
294
+ const ui = this.ui;
295
+ const composer = ui.composer;
296
+ const kind = composer.commitKind;
297
+ let message = composer.editor ? composer.editor.text : '';
298
+ if (isInPlaceCommit(kind) && this.brief) {
299
+ message = joinMessage(message, composer.commitBody);
300
+ }
301
+ message = tidyCommitMessage(message);
302
+ if (!message.trim()) {
303
+ ui.status = 'empty commit message';
304
+ return;
305
+ }
306
+ if (!isInPlaceCommit(kind) && !hasStagedChanges(ui)) {
307
+ ui.composer.closeCompose();
308
+ ui.status = 'nothing to commit';
309
+ return;
310
+ }
311
+ if (kind === 'reword') return void this.finishReword(message);
312
+ const done = COMMIT_STATUS[kind] ?? 'committed';
313
+ const picked = pickRepoWrite(ui.repo, 'commit', ui.uiOpen);
314
+ if (picked.async) {
315
+ const run = (top) => picked.write(top, kind, message);
316
+ return void this.runAsync('committing', done, run);
317
+ }
318
+ try {
319
+ ui.repo.commit(ui.top, kind, message);
320
+ } catch (error) {
321
+ ui.status = error.message;
322
+ return;
323
+ }
329
324
  ui.composer.closeCompose();
330
- ui.status = 'nothing to commit';
331
- return;
325
+ ui.collection.clearDismissed();
326
+ this.refreshAfterWrite();
327
+ if (!ui.done && !ui.pendingExtras) ui.status = done;
332
328
  }
333
- if (kind === 'reword') return void finishReword(api, message);
334
- const done = COMMIT_STATUS[kind] ?? 'committed';
335
- const uiOpen = ui.uiOpen;
336
- const picked = pickRepoWrite(ui.repo, 'commit', uiOpen);
337
- if (picked.async) {
338
- return void finishAsyncCommit(api, kind, message, done, picked.write);
339
- }
340
- finishSyncCommit(api, kind, message, done);
341
- };
342
329
 
343
- const onDropCommit = (api) => {
344
- if (api.ui.nav.pane !== 'commits') return;
345
- if (!canCommit(api.ui)) return;
346
- const entry = selectedCommit(api);
347
- if (!entry) return;
348
- api.state.dropName = entry.shortSha || entry.sha;
349
- api.state.dropSha = entry.sha;
350
- api.ui.mode = 'confirmDrop';
351
- api.ui.status = '';
352
- };
353
-
354
- const cancelDropCommit = (api) => {
355
- api.ui.mode = 'review';
356
- api.state.dropName = '';
357
- api.state.dropSha = '';
358
- api.ui.status = '';
359
- };
360
-
361
- const confirmDropCommit = (api) => {
362
- const sha = api.state.dropSha;
363
- const name = api.state.dropName;
364
- api.ui.mode = 'review';
365
- api.state.dropName = '';
366
- api.state.dropSha = '';
367
- if (!sha) return;
368
- const done = `dropped ${name}`;
369
- const repo = api.ui.repo;
370
- if (!repo.dropCommit) {
371
- api.ui.status = 'read only';
372
- return;
330
+ onDropCommit() {
331
+ if (!this.canWrite()) return;
332
+ const entry = this.selected();
333
+ if (!entry) return;
334
+ this.dropName = entry.shortSha || entry.sha;
335
+ this.dropSha = entry.sha;
336
+ this.ui.mode = 'confirmDrop';
337
+ this.ui.status = '';
373
338
  }
374
- api.ui.ops.runWrite('dropCommit', [sha], 'dropping', done, (extra) =>
375
- refreshAfterWrite(api, extra),
376
- );
377
- };
378
339
 
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;
385
- };
340
+ cancelDropCommit() {
341
+ this.ui.mode = 'review';
342
+ this.dropName = '';
343
+ this.dropSha = '';
344
+ this.ui.status = '';
345
+ }
386
346
 
387
- const reset = (state) => {
388
- state.commits = [];
389
- state.dropName = '';
390
- state.dropSha = '';
391
- state.commitView = 'brief';
392
- };
347
+ confirmDropCommit() {
348
+ const sha = this.dropSha;
349
+ const done = `dropped ${this.dropName}`;
350
+ this.ui.mode = 'review';
351
+ this.dropName = '';
352
+ this.dropSha = '';
353
+ if (!sha) return;
354
+ if (!this.ui.repo.dropCommit) {
355
+ this.ui.status = 'read only';
356
+ return;
357
+ }
358
+ const after = (extra) => this.refreshAfterWrite(extra);
359
+ this.ui.ops.runWrite('dropCommit', [sha], 'dropping', done, after);
360
+ }
393
361
 
394
- const createCommitController = (ui) => {
395
- const state = {
396
- commits: [],
397
- dropName: '',
398
- dropSha: '',
399
- commitView: 'brief',
400
- };
401
- const api = { ui, state };
402
- return stateView(
403
- state,
404
- {
405
- reset: () => reset(state),
406
- canCommit: () => canCommit(ui),
407
- onCommit: () => onCommit(api),
408
- onAmend: () => onAmend(api),
409
- onReword: () => onReword(api),
410
- onApply: () => onApply(api),
411
- onFixup: () => onFixup(api),
412
- onCommitMove: (delta) => onCommitMove(api, delta),
413
- onShowDiff: () => showSelectedDiff(api),
414
- onView: () => onView(api),
415
- cancelCommit: () => cancelCommit(api),
416
- startGitCommit: (kind) => startGitCommit(api, kind),
417
- finishGitCommit: () => finishGitCommit(api),
418
- refresh: () => refreshCommitList(api),
419
- onDropCommit: () => onDropCommit(api),
420
- cancelDropCommit: () => cancelDropCommit(api),
421
- confirmDropCommit: () => confirmDropCommit(api),
422
- },
423
- ['commits', 'dropName', 'commitView'],
424
- );
425
- };
362
+ onView() {
363
+ if (this.ui.nav.pane !== 'commits') return;
364
+ this.commitView = this.brief ? 'full' : 'brief';
365
+ this.ui.nav.listScroll = 0;
366
+ this.ui.status = this.commitView;
367
+ }
368
+ }
426
369
 
427
- module.exports = {
428
- COMMIT_STATUS,
429
- hasStagedChanges,
430
- createCommitController,
431
- listedCommits,
432
- };
370
+ module.exports = { hasStagedChanges, listedCommits, CommitController };