reslop 0.1.8 → 0.1.9

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.
@@ -11,10 +11,7 @@ const ACTIONS = {
11
11
  feedback: ['f'],
12
12
  todo: ['t'],
13
13
  code: ['e'],
14
- reload: ['r'],
15
14
  branch: ['b'],
16
- pull: ['p'],
17
- push: ['s'],
18
15
  quit: ['q', 'ctrl-c'],
19
16
  };
20
17
  const ACTION_IDS = Object.keys(ACTIONS);
@@ -23,6 +20,14 @@ const BRANCH_ACTIONS = {
23
20
  newBranch: ['n'],
24
21
  rebase: ['r'],
25
22
  drop: ['d'],
23
+ pull: ['p'],
24
+ push: ['s'],
25
+ };
26
+
27
+ const COMMIT_ACTIONS = {
28
+ amend: ['a'],
29
+ fixup: ['f'],
30
+ drop: ['d'],
26
31
  };
27
32
 
28
33
  const ACTION_HOT = {
@@ -40,8 +45,9 @@ const ACTION_LABEL = {
40
45
  next: '→',
41
46
  };
42
47
 
43
- const DIFF_DISABLED = ['commit', 'reload', 'branch', 'pull', 'push'];
48
+ const DIFF_DISABLED = ['commit', 'branch', 'pull', 'push'];
44
49
  const FILES_DISABLED = ['layout', 'feedback', 'code'];
50
+ const FILES_HIDDEN = [...FILES_DISABLED, 'prev', 'next', 'commit'];
45
51
  const FILES_GIT_DISABLED = ['add', 'unstage', 'revert'];
46
52
  const FILES_TODO_DISABLED = [...FILES_GIT_DISABLED, ...FILES_DISABLED];
47
53
  const TODO_DISABLED = [
@@ -53,7 +59,6 @@ const TODO_DISABLED = [
53
59
  'feedback',
54
60
  'todo',
55
61
  'code',
56
- 'reload',
57
62
  'branch',
58
63
  'pull',
59
64
  'push',
@@ -67,8 +72,21 @@ const BRANCHES_DISABLED = [
67
72
  'feedback',
68
73
  'todo',
69
74
  'code',
70
- 'reload',
71
75
  'branch',
76
+ 'prev',
77
+ 'next',
78
+ ];
79
+ const COMMITS_DISABLED = [
80
+ 'add',
81
+ 'unstage',
82
+ 'revert',
83
+ 'layout',
84
+ 'feedback',
85
+ 'todo',
86
+ 'code',
87
+ 'branch',
88
+ 'prev',
89
+ 'next',
72
90
  'pull',
73
91
  'push',
74
92
  ];
@@ -82,9 +100,23 @@ const diffGitDisabled = (item) => {
82
100
  return ['unstage'];
83
101
  };
84
102
 
103
+ const BRANCH_REMOTE = ['pull', 'push'];
104
+
85
105
  const branchGitDisabled = (item) => {
86
- if (item && !item.current) return [];
87
- return ['rebase', 'drop'];
106
+ const off = item && !item.current ? [] : ['rebase', 'drop'];
107
+ if (!item || !item.current) return [...off, ...BRANCH_REMOTE];
108
+ return off;
109
+ };
110
+
111
+ const commitWriteDisabled = (item) => {
112
+ if (!item || !item.sha) return ['amend', 'fixup', 'drop'];
113
+ return [];
114
+ };
115
+
116
+ const commitGitDisabled = (item) => {
117
+ const off = commitWriteDisabled(item);
118
+ if (item && item.canCommit === true) return off;
119
+ return [...off, 'commit', 'fixup'];
88
120
  };
89
121
 
90
122
  const disabledActions = (pane, item) => {
@@ -93,6 +125,9 @@ const disabledActions = (pane, item) => {
93
125
  if (pane === 'branches') {
94
126
  return [...BRANCHES_DISABLED, ...branchGitDisabled(item)];
95
127
  }
128
+ if (pane === 'commits') {
129
+ return [...COMMITS_DISABLED, ...commitWriteDisabled(item)];
130
+ }
96
131
  if (onTodos) return TODO_DISABLED;
97
132
  return [...DIFF_DISABLED, ...diffGitDisabled(item)];
98
133
  };
@@ -116,16 +151,27 @@ const SCROLL = {
116
151
  };
117
152
 
118
153
  const KEY_TO_ACTION = {};
119
- const PANE_ONLY = ['branch', 'pull', 'push'];
154
+ const PANE_ONLY = ['branch'];
120
155
  const FILES_KEYS = {};
121
156
  for (const id of PANE_ONLY) {
122
157
  for (const key of ACTIONS[id]) FILES_KEYS[key] = id;
123
158
  }
159
+ for (const id of BRANCH_REMOTE) {
160
+ for (const key of BRANCH_ACTIONS[id]) FILES_KEYS[key] = id;
161
+ }
124
162
  const BRANCH_KEYS = {};
125
163
  for (const id of Object.keys(BRANCH_ACTIONS)) {
126
164
  for (const key of BRANCH_ACTIONS[id]) BRANCH_KEYS[key] = id;
127
165
  }
128
- const PANE_KEYS = { files: FILES_KEYS, branches: BRANCH_KEYS };
166
+ const COMMIT_KEYS = {};
167
+ for (const id of Object.keys(COMMIT_ACTIONS)) {
168
+ for (const key of COMMIT_ACTIONS[id]) COMMIT_KEYS[key] = id;
169
+ }
170
+ const PANE_KEYS = {
171
+ files: FILES_KEYS,
172
+ branches: BRANCH_KEYS,
173
+ commits: COMMIT_KEYS,
174
+ };
129
175
 
130
176
  for (const id of ACTION_IDS) {
131
177
  if (PANE_ONLY.includes(id)) continue;
@@ -135,12 +181,16 @@ for (const id of ACTION_IDS) {
135
181
  for (const key of Object.keys(SCROLL)) KEY_TO_ACTION[key] = SCROLL[key];
136
182
 
137
183
  const actionFromKey = (key, pane) => {
184
+ const listPane =
185
+ pane === 'files' || pane === 'branches' || pane === 'commits';
186
+ if (listPane && (key === 'left' || key === 'right')) return null;
138
187
  const paneKeys = PANE_KEYS[pane];
139
188
  if (paneKeys && paneKeys[key]) return paneKeys[key];
140
189
  return KEY_TO_ACTION[key] ?? null;
141
190
  };
142
191
 
143
- const actionKeys = (id) => ACTIONS[id] ?? BRANCH_ACTIONS[id] ?? [];
192
+ const actionKeys = (id) =>
193
+ ACTIONS[id] ?? BRANCH_ACTIONS[id] ?? COMMIT_ACTIONS[id] ?? [];
144
194
 
145
195
  const actionHot = (id) => ACTION_HOT[id] ?? actionKeys(id)[0];
146
196
 
@@ -173,19 +223,6 @@ const CONFIRM = {
173
223
  escape: 'cancel',
174
224
  },
175
225
  },
176
- confirmCommit: {
177
- choices: [
178
- { letter: 'c', label: 'commit', lead: ' ' },
179
- { letter: 'a', label: 'amend', lead: ' ' },
180
- { letter: 'f', label: 'fixup', lead: ' ' },
181
- ],
182
- keys: {
183
- c: 'commit',
184
- a: 'amend',
185
- f: 'fixup',
186
- escape: 'cancel',
187
- },
188
- },
189
226
  confirmUpdate: {
190
227
  choices: YES_NO,
191
228
  prefix: (view) => {
@@ -248,19 +285,23 @@ module.exports = {
248
285
  ACTIONS,
249
286
  ACTION_IDS,
250
287
  BRANCH_ACTIONS,
288
+ COMMIT_ACTIONS,
251
289
  ACTION_HOT,
252
290
  ACTION_LABEL,
253
291
  DIFF_DISABLED,
254
292
  FILES_DISABLED,
293
+ FILES_HIDDEN,
255
294
  FILES_GIT_DISABLED,
256
295
  FILES_TODO_DISABLED,
257
296
  TODO_DISABLED,
258
297
  BRANCHES_DISABLED,
298
+ COMMITS_DISABLED,
259
299
  SCROLL,
260
300
  PANE_ONLY,
261
301
  disabledActions,
262
302
  diffGitDisabled,
263
303
  branchGitDisabled,
304
+ commitGitDisabled,
264
305
  actionFromKey,
265
306
  actionKeys,
266
307
  actionHot,
@@ -21,6 +21,11 @@ const refreshBranchList = (api) => {
21
21
  if (nav.branchCursor > last) nav.branchCursor = Math.max(0, last);
22
22
  };
23
23
 
24
+ const refreshAfterWrite = (api, extra = {}) => {
25
+ refreshBranchList(api);
26
+ api.options.refreshFromRepo({ keepEmpty: true, ...extra });
27
+ };
28
+
24
29
  const onBranch = (api) => {
25
30
  if (api.options.getMode() === 'compose') return;
26
31
  if (!api.options.canCommit()) return;
@@ -93,10 +98,7 @@ const onCheckoutBranch = (api) => {
93
98
 
94
99
  const rebaseAsync = (api, onto, done, write) => {
95
100
  const run = (top) => write(top, onto);
96
- const after = () => {
97
- refreshBranchList(api);
98
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
99
- };
101
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
100
102
  return void api.options.runner.runBusy('rebasing', done, run, after);
101
103
  };
102
104
 
@@ -117,8 +119,7 @@ const onRebaseBranch = (api) => {
117
119
  api.options.repo().rebase(top, onto);
118
120
  });
119
121
  if (!ok) return;
120
- refreshBranchList(api);
121
- api.options.refreshFromRepo({ keepEmpty: true });
122
+ refreshAfterWrite(api);
122
123
  if (!api.options.getStatus()) api.options.setStatus(done);
123
124
  };
124
125
 
@@ -140,10 +141,7 @@ const cancelDropBranch = (api) => {
140
141
 
141
142
  const dropAsync = (api, name, done, write) => {
142
143
  const run = (top) => write(top, name);
143
- const after = () => {
144
- refreshBranchList(api);
145
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
146
- };
144
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
147
145
  return void api.options.runner.runBusy('dropping', done, run, after);
148
146
  };
149
147
 
@@ -163,8 +161,7 @@ const confirmDropBranch = (api) => {
163
161
  api.options.repo().drop(top, name);
164
162
  });
165
163
  if (!ok) return;
166
- refreshBranchList(api);
167
- api.options.refreshFromRepo({ keepEmpty: true });
164
+ refreshAfterWrite(api);
168
165
  if (!api.options.getStatus()) api.options.setStatus(done);
169
166
  };
170
167
 
@@ -178,8 +175,7 @@ const createAsync = (api, name, done, write) => {
178
175
  api.options.composer.closeCompose();
179
176
  api.options.showFiles();
180
177
  const run = (top) => write(top, name);
181
- const after = () =>
182
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
178
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
183
179
  return void api.options.runner.runBusy('creating branch', done, run, after);
184
180
  };
185
181
 
@@ -203,7 +199,7 @@ const finishCreateBranch = (api) => {
203
199
  if (!ok) return;
204
200
  api.options.composer.closeCompose();
205
201
  api.options.showFiles();
206
- api.options.refreshFromRepo({ keepEmpty: true });
202
+ refreshAfterWrite(api);
207
203
  if (!api.options.getStatus()) api.options.setStatus(done);
208
204
  };
209
205
 
@@ -212,7 +208,7 @@ const onPull = (api) => {
212
208
  const repo = api.options.repo();
213
209
  const picked = pickRepoWrite(repo, 'pull', api.options.uiOpen());
214
210
  if (picked.async) {
215
- const after = () => api.options.refreshFromRepo({ keepEmpty: true });
211
+ const after = () => refreshAfterWrite(api);
216
212
  const write = (top) => picked.write(top);
217
213
  return void api.options.runner.runBusy('pulling', 'pulled', write, after);
218
214
  }
@@ -220,7 +216,7 @@ const onPull = (api) => {
220
216
  repo.pull(top);
221
217
  });
222
218
  if (!ok) return;
223
- api.options.refreshFromRepo({ keepEmpty: true });
219
+ refreshAfterWrite(api);
224
220
  if (!api.options.getStatus()) api.options.setStatus('pulled');
225
221
  };
226
222
 
@@ -232,7 +228,8 @@ const startPush = (api, force) => {
232
228
  const picked = pickRepoWrite(repo, 'push', api.options.uiOpen());
233
229
  if (picked.async) {
234
230
  const write = (top) => picked.write(top, force);
235
- return void api.options.runner.runBusy(kind, done, write);
231
+ const after = () => refreshAfterWrite(api);
232
+ return void api.options.runner.runBusy(kind, done, write, after);
236
233
  }
237
234
  try {
238
235
  repo.push(api.options.top(), force);
@@ -245,6 +242,7 @@ const startPush = (api, force) => {
245
242
  api.options.setStatus(error.message);
246
243
  return;
247
244
  }
245
+ refreshAfterWrite(api);
248
246
  api.options.setStatus(done);
249
247
  };
250
248
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const files = require('../files.js');
4
- const { itemPath, isTodoItem, isTodosEntry } = files;
4
+ const { listPath, isTodoItem, isTodosEntry } = files;
5
5
  const items = require('./items.js');
6
6
  const { needsReload, npmBusyKind, sameBlock } = items;
7
7
  const { isReadOnlyOrigin } = require('./origins.js');
@@ -27,6 +27,9 @@ const COMMANDS = {
27
27
 
28
28
  const keepOrigin = (options, item, origin) => {
29
29
  options.collection.keepOrigin(item, origin);
30
+ const idx = options.collection.findRestoredIndex({ ...item, origin });
31
+ if (idx >= 0) options.nav.index = idx;
32
+ if (options.ignoreWatch) options.ignoreWatch();
30
33
  options.nav.clearSelection();
31
34
  options.syncReviewPath();
32
35
  options.syncFileCursor();
@@ -44,7 +47,7 @@ const fileActionItems = (options) => {
44
47
  const selected = [];
45
48
  for (const item of options.getItems()) {
46
49
  if (isTodoItem(item)) continue;
47
- if (itemPath(item) !== rel) continue;
50
+ if (listPath(item) !== rel) continue;
48
51
  selected.push(item);
49
52
  }
50
53
  return selected;
@@ -222,7 +225,7 @@ const onFileAdd = (options) => {
222
225
  return;
223
226
  }
224
227
  if (!guardWritable(options, selected[0])) return;
225
- const rel = itemPath(selected[0]);
228
+ const rel = listPath(selected[0]);
226
229
  const targets = selected.filter(COMMANDS.add.match);
227
230
  if (!targets.length) {
228
231
  options.setStatus('already staged');
@@ -257,7 +260,7 @@ const onFileUnstage = (options) => {
257
260
  return;
258
261
  }
259
262
  if (!guardWritable(options, selected[0])) return;
260
- const rel = itemPath(selected[0]);
263
+ const rel = listPath(selected[0]);
261
264
  const targets = selected.filter(COMMANDS.unstage.match);
262
265
  if (!targets.length) {
263
266
  options.setStatus('not staged');
@@ -283,7 +286,7 @@ const onFileRevert = (options) => {
283
286
  return;
284
287
  }
285
288
  if (!guardWritable(options, selected[0])) return;
286
- const rel = itemPath(selected[0]);
289
+ const rel = listPath(selected[0]);
287
290
  for (const item of selected) {
288
291
  if (needsReload(item)) options.collection.dismiss(item);
289
292
  }
@@ -33,19 +33,71 @@ const hasStagedChanges = (options) => {
33
33
  return false;
34
34
  };
35
35
 
36
- const onCommit = (options) => {
37
- if (!canCommit(options)) return;
38
- options.setMode('confirmCommit');
39
- options.setStatus('');
36
+ const selectedCommit = (api) => {
37
+ const cursor = api.options.nav.commitCursor;
38
+ return api.state.commits[cursor] ?? null;
40
39
  };
41
40
 
42
- const cancelCommit = (options) => {
43
- options.setMode('review');
44
- options.composer.state.commitKind = null;
45
- options.setStatus('');
41
+ const clampCommitCursor = (api) => {
42
+ const last = api.state.commits.length - 1;
43
+ const nav = api.options.nav;
44
+ if (nav.commitCursor > last) nav.commitCursor = Math.max(0, last);
46
45
  };
47
46
 
48
- const startGitCommit = (options, kind) => {
47
+ const refreshCommitList = (api) => {
48
+ const repo = api.options.repo();
49
+ if (!repo.listCommits) return;
50
+ try {
51
+ api.state.commits = repo.listCommits(api.options.top());
52
+ } catch (error) {
53
+ api.options.setStatus(error.message);
54
+ return;
55
+ }
56
+ clampCommitCursor(api);
57
+ };
58
+
59
+ const refreshAfterWrite = (api, extra = {}) => {
60
+ refreshCommitList(api);
61
+ api.options.refreshFromRepo({ keepEmpty: true, ...extra });
62
+ };
63
+
64
+ const showCommits = (api) => {
65
+ if (api.options.getMode() === 'compose') return;
66
+ if (!canCommit(api.options)) return;
67
+ const repo = api.options.repo();
68
+ if (!repo.listCommits) {
69
+ api.options.setStatus('read only');
70
+ return;
71
+ }
72
+ try {
73
+ api.state.commits = repo.listCommits(api.options.top());
74
+ } catch (error) {
75
+ api.options.setStatus(error.message);
76
+ return;
77
+ }
78
+ api.options.nav.commitCursor = 0;
79
+ api.options.nav.pane = 'commits';
80
+ api.options.setStatus('');
81
+ api.options.nav.clearSelection();
82
+ };
83
+
84
+ const onCommitMove = (api, delta) => {
85
+ const commits = api.state.commits;
86
+ if (!commits.length) {
87
+ api.options.setStatus('nothing to review');
88
+ return;
89
+ }
90
+ const next = Math.min(
91
+ commits.length - 1,
92
+ Math.max(0, api.options.nav.commitCursor + delta),
93
+ );
94
+ if (next === api.options.nav.commitCursor) return;
95
+ api.options.nav.commitCursor = next;
96
+ api.options.setStatus('');
97
+ };
98
+
99
+ const startGitCommit = (api, kind) => {
100
+ const options = api.options;
49
101
  if (kind !== 'amend' && !hasStagedChanges(options)) {
50
102
  options.setMode('review');
51
103
  options.composer.state.commitKind = null;
@@ -54,25 +106,50 @@ const startGitCommit = (options, kind) => {
54
106
  }
55
107
  options.composer.state.commitKind = kind;
56
108
  let text = '';
57
- if (kind === 'fixup') text = 'HEAD';
109
+ if (kind === 'fixup') {
110
+ const entry = selectedCommit(api);
111
+ text = entry ? entry.shortSha || entry.sha : 'HEAD';
112
+ }
58
113
  if (kind === 'amend' && options.repo().lastMessage) {
59
114
  text = options.repo().lastMessage(options.top()) ?? '';
60
115
  }
61
116
  options.composer.openCompose('commit', text);
62
117
  };
63
118
 
64
- const finishAsyncCommit = (options, kind, message, done, write) => {
65
- const composer = options.composer;
66
- composer.closeCompose();
119
+ const onCommit = (api) => {
120
+ if (api.options.nav.pane !== 'commits') return void showCommits(api);
121
+ if (!canCommit(api.options)) return;
122
+ startGitCommit(api, 'commit');
123
+ };
124
+
125
+ const onAmend = (api) => {
126
+ if (api.options.nav.pane !== 'commits') return;
127
+ if (!canCommit(api.options)) return;
128
+ startGitCommit(api, 'amend');
129
+ };
130
+
131
+ const onFixup = (api) => {
132
+ if (api.options.nav.pane !== 'commits') return;
133
+ if (!canCommit(api.options)) return;
134
+ startGitCommit(api, 'fixup');
135
+ };
136
+
137
+ const cancelCommit = (api) => {
138
+ api.options.setMode('review');
139
+ api.options.composer.state.commitKind = null;
140
+ api.options.setStatus('');
141
+ };
142
+
143
+ const finishAsyncCommit = (api, kind, message, done, write) => {
144
+ const options = api.options;
145
+ options.composer.closeCompose();
67
146
  const run = (top) => write(top, kind, message);
68
- const after = () => {
69
- options.collection.clearDismissed();
70
- options.refreshFromRepo({ doneStatus: done });
71
- };
147
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
72
148
  return void options.runner.runBusy('committing', done, run, after);
73
149
  };
74
150
 
75
- const finishSyncCommit = (options, kind, message, done) => {
151
+ const finishSyncCommit = (api, kind, message, done) => {
152
+ const options = api.options;
76
153
  try {
77
154
  options.repo().commit(options.top(), kind, message);
78
155
  } catch (error) {
@@ -81,13 +158,14 @@ const finishSyncCommit = (options, kind, message, done) => {
81
158
  }
82
159
  options.composer.closeCompose();
83
160
  options.collection.clearDismissed();
84
- options.refreshFromRepo();
161
+ refreshAfterWrite(api);
85
162
  if (!options.isDone() && !options.pendingExtras()) {
86
163
  options.setStatus(done);
87
164
  }
88
165
  };
89
166
 
90
- const finishGitCommit = (options) => {
167
+ const finishGitCommit = (api) => {
168
+ const options = api.options;
91
169
  const kind = options.composer.state.commitKind;
92
170
  const editor = options.composer.state.editor;
93
171
  const message = editor ? editor.text : '';
@@ -104,19 +182,103 @@ const finishGitCommit = (options) => {
104
182
  const uiOpen = options.uiOpen();
105
183
  const picked = pickRepoWrite(options.repo(), 'commit', uiOpen);
106
184
  if (picked.async) {
107
- finishAsyncCommit(options, kind, message, done, picked.write);
185
+ finishAsyncCommit(api, kind, message, done, picked.write);
186
+ return;
187
+ }
188
+ finishSyncCommit(api, kind, message, done);
189
+ };
190
+
191
+ const onDropCommit = (api) => {
192
+ if (api.options.nav.pane !== 'commits') return;
193
+ if (!canCommit(api.options)) return;
194
+ const entry = selectedCommit(api);
195
+ if (!entry) return;
196
+ api.state.dropName = entry.shortSha || entry.sha;
197
+ api.state.dropSha = entry.sha;
198
+ api.options.setMode('confirmDrop');
199
+ api.options.setStatus('');
200
+ };
201
+
202
+ const cancelDropCommit = (api) => {
203
+ api.options.setMode('review');
204
+ api.state.dropName = '';
205
+ api.state.dropSha = '';
206
+ api.options.setStatus('');
207
+ };
208
+
209
+ const dropAsync = (api, sha, done, write) => {
210
+ const run = (top) => write(top, sha);
211
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
212
+ return void api.options.runner.runBusy('dropping', done, run, after);
213
+ };
214
+
215
+ const confirmDropCommit = (api) => {
216
+ const sha = api.state.dropSha;
217
+ const name = api.state.dropName;
218
+ api.options.setMode('review');
219
+ api.state.dropName = '';
220
+ api.state.dropSha = '';
221
+ if (!sha) return;
222
+ const done = `dropped ${name}`;
223
+ const repo = api.options.repo();
224
+ if (!repo.dropCommit) {
225
+ api.options.setStatus('read only');
226
+ return;
227
+ }
228
+ const uiOpen = api.options.uiOpen();
229
+ const picked = pickRepoWrite(repo, 'dropCommit', uiOpen);
230
+ if (picked.async) {
231
+ dropAsync(api, sha, done, picked.write);
108
232
  return;
109
233
  }
110
- finishSyncCommit(options, kind, message, done);
234
+ const ok = api.options.runner.runRepo(done, (top) => {
235
+ repo.dropCommit(top, sha);
236
+ });
237
+ if (!ok) return;
238
+ refreshAfterWrite(api);
239
+ if (!api.options.getStatus()) api.options.setStatus(done);
240
+ };
241
+
242
+ const reset = (state) => {
243
+ state.commits = [];
244
+ state.dropName = '';
245
+ state.dropSha = '';
111
246
  };
112
247
 
113
- const createCommitController = (options) => ({
114
- canCommit: () => canCommit(options),
115
- onCommit: () => onCommit(options),
116
- cancelCommit: () => cancelCommit(options),
117
- startGitCommit: (kind) => startGitCommit(options, kind),
118
- finishGitCommit: () => finishGitCommit(options),
119
- });
248
+ const createCommitController = (options) => {
249
+ const state = {
250
+ commits: [],
251
+ dropName: '',
252
+ dropSha: '',
253
+ };
254
+ const api = { options, state };
255
+ return {
256
+ get commits() {
257
+ return state.commits;
258
+ },
259
+ set commits(value) {
260
+ state.commits = value;
261
+ },
262
+ get dropName() {
263
+ return state.dropName;
264
+ },
265
+ set dropName(value) {
266
+ state.dropName = value;
267
+ },
268
+ reset: () => reset(state),
269
+ canCommit: () => canCommit(options),
270
+ onCommit: () => onCommit(api),
271
+ onAmend: () => onAmend(api),
272
+ onFixup: () => onFixup(api),
273
+ onCommitMove: (delta) => onCommitMove(api, delta),
274
+ cancelCommit: () => cancelCommit(api),
275
+ startGitCommit: (kind) => startGitCommit(api, kind),
276
+ finishGitCommit: () => finishGitCommit(api),
277
+ onDropCommit: () => onDropCommit(api),
278
+ cancelDropCommit: () => cancelDropCommit(api),
279
+ confirmDropCommit: () => confirmDropCommit(api),
280
+ };
281
+ };
120
282
 
121
283
  module.exports = {
122
284
  COMMIT_STATUS,
@@ -19,12 +19,19 @@ const createDispatcher = (options) => {
19
19
  code: options.composer.onCode,
20
20
  reload: options.onReload,
21
21
  commit: options.commits.onCommit,
22
+ amend: options.commits.onAmend,
23
+ fixup: options.commits.onFixup,
22
24
  branch: options.gitBranches.onBranch,
23
25
  pull: options.gitBranches.onPull,
24
26
  push: options.gitBranches.onPush,
25
27
  newBranch: options.gitBranches.onNewBranch,
26
28
  rebase: options.gitBranches.onRebaseBranch,
27
- drop: options.gitBranches.onDropBranch,
29
+ drop: () => {
30
+ if (options.getPane() === 'commits') {
31
+ return void options.commits.onDropCommit();
32
+ }
33
+ options.gitBranches.onDropBranch();
34
+ },
28
35
  open: options.onOpenFile,
29
36
  removeTodo: options.composer.removeFocusedTodo,
30
37
  quit: options.onQuit,
@@ -54,6 +61,10 @@ const createDispatcher = (options) => {
54
61
  if (action === 'next') return void options.onBranchMove(1);
55
62
  if (action === 'prev') return void options.onBranchMove(-1);
56
63
  }
64
+ if (pane === 'commits') {
65
+ if (action === 'next') return void options.onCommitMove(1);
66
+ if (action === 'prev') return void options.onCommitMove(-1);
67
+ }
57
68
  const hidden = disabledActions(pane, options.currentTarget());
58
69
  if (hidden.includes(action)) return;
59
70
  const handler = handlers[action];
@@ -67,7 +78,6 @@ const createDispatcher = (options) => {
67
78
  const createInput = (options) => {
68
79
  const confirmations = {
69
80
  confirmQuit: options.quit,
70
- confirmCommit: options.commit,
71
81
  confirmUpdate: options.update,
72
82
  confirmDrop: options.drop,
73
83
  confirmPush: options.push,
@@ -35,7 +35,7 @@ const showFiles = (options) => {
35
35
  };
36
36
 
37
37
  const onEscape = (options) => {
38
- if (options.nav.pane === 'branches') {
38
+ if (options.nav.pane === 'branches' || options.nav.pane === 'commits') {
39
39
  showFiles(options);
40
40
  return;
41
41
  }
@@ -61,6 +61,7 @@ const onOpenFile = (options) => {
61
61
  if (options.nav.pane === 'branches') {
62
62
  return void options.onCheckoutBranch();
63
63
  }
64
+ if (options.nav.pane === 'commits') return;
64
65
  if (options.nav.pane !== 'files') {
65
66
  if (options.nav.todoOpen) options.composer.editFocusedTodo();
66
67
  return;
@@ -157,6 +158,9 @@ const onScroll = (options, delta) => {
157
158
  if (options.nav.pane === 'branches') {
158
159
  return void options.onBranchMove(delta);
159
160
  }
161
+ if (options.nav.pane === 'commits') {
162
+ return void options.onCommitMove(delta);
163
+ }
160
164
  if (options.nav.todoOpen && options.composer.todoRowCount() > 1) {
161
165
  return void options.composer.moveTodoFocus(delta);
162
166
  }
@@ -186,6 +190,11 @@ const onJump = (options, toEnd) => {
186
190
  options.onBranchMove(delta);
187
191
  return;
188
192
  }
193
+ if (options.nav.pane === 'commits') {
194
+ const delta = toEnd ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER;
195
+ options.onCommitMove(delta);
196
+ return;
197
+ }
189
198
  if (options.nav.todoOpen && options.composer.todoRowCount() > 0) {
190
199
  const last = options.composer.todoRowCount() - 1;
191
200
  const target = toEnd ? last : 0;