reslop 0.1.9 → 0.2.0

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 (94) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +2 -1
  3. package/bin/reslop.js +2 -2
  4. package/lib/ansi.js +4 -2
  5. package/lib/api.js +2 -2
  6. package/lib/capabilities.js +7 -14
  7. package/lib/cli.js +28 -47
  8. package/lib/clipboard.js +1 -1
  9. package/lib/{deps/changes.js → deps-diff.js} +309 -19
  10. package/lib/deps.js +498 -29
  11. package/lib/detect.js +1 -7
  12. package/lib/diff/align.js +7 -10
  13. package/lib/diff/diff.js +53 -0
  14. package/lib/diff/display.js +5 -4
  15. package/lib/diff/inline.js +26 -21
  16. package/lib/diff/items.js +6 -4
  17. package/lib/diff/patch.js +1 -3
  18. package/lib/diff/unit.js +392 -0
  19. package/lib/files.js +5 -8
  20. package/lib/{git/branches.js → git-branches.js} +6 -5
  21. package/lib/{git/dependencies.js → git-deps.js} +111 -38
  22. package/lib/git.js +589 -68
  23. package/lib/github.js +28 -197
  24. package/lib/gitlab.js +24 -195
  25. package/lib/highlight/bash.js +1 -3
  26. package/lib/highlight/css.js +1 -3
  27. package/lib/highlight/js.js +11 -14
  28. package/lib/highlight.js +6 -9
  29. package/lib/keys.js +14 -8
  30. package/lib/manifest.js +330 -0
  31. package/lib/remote.js +374 -0
  32. package/lib/render/branches.js +14 -68
  33. package/lib/render/chrome.js +24 -9
  34. package/lib/render/commits.js +6 -59
  35. package/lib/render/diff.js +16 -16
  36. package/lib/render/files.js +6 -34
  37. package/lib/render/frame.js +23 -12
  38. package/lib/render/notes.js +4 -3
  39. package/lib/render/primitives.js +45 -0
  40. package/lib/{render.js → render/render.js} +5 -5
  41. package/lib/render/unit.js +41 -0
  42. package/lib/review.js +750 -14
  43. package/lib/select.js +5 -10
  44. package/lib/session/accessors.js +9 -1
  45. package/lib/session/actions.js +32 -16
  46. package/lib/session/branches.js +116 -128
  47. package/lib/session/change-actions.js +202 -123
  48. package/lib/session/commit.js +105 -112
  49. package/lib/session/compose.js +158 -13
  50. package/lib/session/dispatch.js +104 -60
  51. package/lib/session/files-pane.js +142 -148
  52. package/lib/session/items.js +22 -30
  53. package/lib/session/lifecycle.js +44 -44
  54. package/lib/session/load.js +19 -33
  55. package/lib/session/navigation.js +12 -1
  56. package/lib/session/ops.js +28 -41
  57. package/lib/session/pointer.js +54 -57
  58. package/lib/session/review.js +23 -37
  59. package/lib/session/terminal.js +6 -12
  60. package/lib/session/todos.js +8 -12
  61. package/lib/session/unit.js +208 -0
  62. package/lib/session/update.js +33 -46
  63. package/lib/session/view.js +78 -9
  64. package/lib/session/watch.js +11 -19
  65. package/lib/session.js +21 -246
  66. package/lib/source.js +3 -3
  67. package/lib/update.js +40 -75
  68. package/lib/{git/proc.js → utilities.js} +75 -11
  69. package/lib/wrap.js +1 -3
  70. package/package.json +1 -1
  71. package/lib/deps/items.js +0 -134
  72. package/lib/deps/manifest.js +0 -152
  73. package/lib/deps/merge.js +0 -120
  74. package/lib/deps/proposals.js +0 -164
  75. package/lib/deps/reports.js +0 -180
  76. package/lib/deps/rows.js +0 -176
  77. package/lib/deps/scan.js +0 -138
  78. package/lib/deps/usage.js +0 -68
  79. package/lib/deps/versions.js +0 -119
  80. package/lib/diff.js +0 -33
  81. package/lib/git/changes.js +0 -164
  82. package/lib/git/read.js +0 -253
  83. package/lib/git/run.js +0 -100
  84. package/lib/npm/commands.js +0 -100
  85. package/lib/remote/changes.js +0 -37
  86. package/lib/remote/headers.js +0 -36
  87. package/lib/remote/http.js +0 -122
  88. package/lib/remote/notes.js +0 -94
  89. package/lib/review/format.js +0 -434
  90. package/lib/review/storage.js +0 -150
  91. package/lib/review/store.js +0 -178
  92. package/lib/review/templates.js +0 -49
  93. package/lib/session/origins.js +0 -7
  94. package/lib/sys.js +0 -84
package/lib/select.js CHANGED
@@ -145,8 +145,6 @@ const parseCells = (line) => {
145
145
 
146
146
  const rgbKey = (rgb) => (rgb ? `${rgb[0]},${rgb[1]},${rgb[2]}` : '');
147
147
 
148
- const styleKey = (fg, bg) => `${rgbKey(fg)}|${rgbKey(bg)}`;
149
-
150
148
  const styleSeq = (fg, bg) => {
151
149
  if (fg && bg) return RESET + seq(fg, bg);
152
150
  if (fg) return RESET + ansi.fg(fg);
@@ -169,7 +167,7 @@ const overlayRange = (line, fromCol, toCol) => {
169
167
  fg = cell.bg ?? THEME.ctxBg;
170
168
  bg = cell.fg ?? THEME.ctxFg;
171
169
  }
172
- const key = styleKey(fg, bg);
170
+ const key = `${rgbKey(fg)}|${rgbKey(bg)}`;
173
171
  if (key !== last) {
174
172
  out += styleSeq(fg, bg);
175
173
  last = key;
@@ -181,14 +179,11 @@ const overlayRange = (line, fromCol, toCol) => {
181
179
 
182
180
  const overlayRows = (rows, sel) => {
183
181
  if (!isRange(sel)) return rows;
184
- const next = [];
185
- for (let i = 0; i < rows.length; i++) {
182
+ const { length } = rows;
183
+ const next = new Array(length);
184
+ for (let i = 0; i < length; i++) {
186
185
  const range = lineRange(i, sel);
187
- if (!range) {
188
- next.push(rows[i]);
189
- continue;
190
- }
191
- next.push(overlayRange(rows[i], range.from, range.to));
186
+ next[i] = range ? overlayRange(rows[i], range.from, range.to) : rows[i];
192
187
  }
193
188
  return next;
194
189
  };
@@ -22,4 +22,12 @@ const bindGetters = (target, owner, names) => {
22
22
  }
23
23
  };
24
24
 
25
- module.exports = { bindAccessors, bindGetters, bindAlias };
25
+ const stateView = (state, methods, writable = [], readonly = []) => {
26
+ const descriptors = Object.getOwnPropertyDescriptors(methods);
27
+ const view = Object.defineProperties({}, descriptors);
28
+ bindAccessors(view, state, writable);
29
+ bindGetters(view, state, readonly);
30
+ return view;
31
+ };
32
+
33
+ module.exports = { bindAccessors, bindGetters, bindAlias, stateView };
@@ -12,6 +12,8 @@ const ACTIONS = {
12
12
  todo: ['t'],
13
13
  code: ['e'],
14
14
  branch: ['b'],
15
+ file: ['f'],
16
+ diff: ['d'],
15
17
  quit: ['q', 'ctrl-c'],
16
18
  };
17
19
  const ACTION_IDS = Object.keys(ACTIONS);
@@ -28,6 +30,8 @@ const COMMIT_ACTIONS = {
28
30
  amend: ['a'],
29
31
  fixup: ['f'],
30
32
  drop: ['d'],
33
+ pull: ['p'],
34
+ push: ['s'],
31
35
  };
32
36
 
33
37
  const ACTION_HOT = {
@@ -45,9 +49,17 @@ const ACTION_LABEL = {
45
49
  next: '→',
46
50
  };
47
51
 
48
- const DIFF_DISABLED = ['commit', 'branch', 'pull', 'push'];
52
+ const DIFF_DISABLED = ['commit', 'branch', 'pull', 'push', 'file', 'diff'];
53
+ const UNIT_DISABLED = [...DIFF_DISABLED, 'layout'];
49
54
  const FILES_DISABLED = ['layout', 'feedback', 'code'];
50
- const FILES_HIDDEN = [...FILES_DISABLED, 'prev', 'next', 'commit'];
55
+ const FILES_HIDDEN = [
56
+ ...FILES_DISABLED,
57
+ 'prev',
58
+ 'next',
59
+ 'commit',
60
+ 'file',
61
+ 'diff',
62
+ ];
51
63
  const FILES_GIT_DISABLED = ['add', 'unstage', 'revert'];
52
64
  const FILES_TODO_DISABLED = [...FILES_GIT_DISABLED, ...FILES_DISABLED];
53
65
  const TODO_DISABLED = [
@@ -60,6 +72,8 @@ const TODO_DISABLED = [
60
72
  'todo',
61
73
  'code',
62
74
  'branch',
75
+ 'file',
76
+ 'diff',
63
77
  'pull',
64
78
  'push',
65
79
  ];
@@ -73,6 +87,8 @@ const BRANCHES_DISABLED = [
73
87
  'todo',
74
88
  'code',
75
89
  'branch',
90
+ 'file',
91
+ 'diff',
76
92
  'prev',
77
93
  'next',
78
94
  ];
@@ -85,10 +101,10 @@ const COMMITS_DISABLED = [
85
101
  'todo',
86
102
  'code',
87
103
  'branch',
104
+ 'file',
105
+ 'diff',
88
106
  'prev',
89
107
  'next',
90
- 'pull',
91
- 'push',
92
108
  ];
93
109
 
94
110
  const isTodosTarget = (item) =>
@@ -122,6 +138,7 @@ const commitGitDisabled = (item) => {
122
138
  const disabledActions = (pane, item) => {
123
139
  const onTodos = isTodosTarget(item);
124
140
  if (pane === 'files') return onTodos ? FILES_TODO_DISABLED : FILES_DISABLED;
141
+ if (pane === 'unit') return [...UNIT_DISABLED, ...diffGitDisabled(item)];
125
142
  if (pane === 'branches') {
126
143
  return [...BRANCHES_DISABLED, ...branchGitDisabled(item)];
127
144
  }
@@ -151,11 +168,9 @@ const SCROLL = {
151
168
  };
152
169
 
153
170
  const KEY_TO_ACTION = {};
154
- const PANE_ONLY = ['branch'];
171
+ const PANE_ONLY = ['branch', 'file', 'diff'];
155
172
  const FILES_KEYS = {};
156
- for (const id of PANE_ONLY) {
157
- for (const key of ACTIONS[id]) FILES_KEYS[key] = id;
158
- }
173
+ for (const key of ACTIONS.branch) FILES_KEYS[key] = 'branch';
159
174
  for (const id of BRANCH_REMOTE) {
160
175
  for (const key of BRANCH_ACTIONS[id]) FILES_KEYS[key] = id;
161
176
  }
@@ -180,12 +195,16 @@ for (const id of ACTION_IDS) {
180
195
 
181
196
  for (const key of Object.keys(SCROLL)) KEY_TO_ACTION[key] = SCROLL[key];
182
197
 
183
- const actionFromKey = (key, pane) => {
198
+ const actionFromKey = (key, pane, fileScope) => {
184
199
  const listPane =
185
200
  pane === 'files' || pane === 'branches' || pane === 'commits';
186
201
  if (listPane && (key === 'left' || key === 'right')) return null;
187
202
  const paneKeys = PANE_KEYS[pane];
188
203
  if (paneKeys && paneKeys[key]) return paneKeys[key];
204
+ if (pane === 'files') {
205
+ if (key === 'f' && fileScope !== 'file') return 'file';
206
+ if (key === 'd' && fileScope === 'file') return 'diff';
207
+ }
189
208
  return KEY_TO_ACTION[key] ?? null;
190
209
  };
191
210
 
@@ -194,12 +213,10 @@ const actionKeys = (id) =>
194
213
 
195
214
  const actionHot = (id) => ACTION_HOT[id] ?? actionKeys(id)[0];
196
215
 
197
- const actionLabel = (id) => ACTION_LABEL[id] ?? ACTION_HOT[id] ?? id;
198
-
199
216
  const actionLetter = actionHot;
200
217
 
201
218
  const buttonWord = (id) => {
202
- const word = actionLabel(id);
219
+ const word = ACTION_LABEL[id] ?? ACTION_HOT[id] ?? id;
203
220
  const mark = actionLetter(id);
204
221
  if (word.includes(mark)) return word;
205
222
  return `${mark}${word}`;
@@ -257,13 +274,11 @@ const CONFIRM = {
257
274
 
258
275
  const CONFIRM_MODE = Object.keys(CONFIRM);
259
276
 
260
- const normalizeConfirmKey = (key) =>
261
- key.length === 1 ? key.toLowerCase() : key;
262
-
263
277
  const confirmKey = (mode, key) => {
264
278
  const spec = CONFIRM[mode];
265
279
  if (!spec) return null;
266
- return spec.keys[normalizeConfirmKey(key)] ?? null;
280
+ const norm = key.length === 1 ? key.toLowerCase() : key;
281
+ return spec.keys[norm] ?? null;
267
282
  };
268
283
 
269
284
  const applyConfirm = (mode, key, handlers) => {
@@ -289,6 +304,7 @@ module.exports = {
289
304
  ACTION_HOT,
290
305
  ACTION_LABEL,
291
306
  DIFF_DISABLED,
307
+ UNIT_DISABLED,
292
308
  FILES_DISABLED,
293
309
  FILES_HIDDEN,
294
310
  FILES_GIT_DISABLED,
@@ -1,261 +1,257 @@
1
1
  'use strict';
2
2
 
3
+ const { stateView } = require('./accessors.js');
4
+
3
5
  const { pickRepoWrite } = require('./ops.js');
4
6
 
5
7
  const selectedBranch = (api) => {
6
- const cursor = api.options.nav.branchCursor;
8
+ const cursor = api.ui.nav.branchCursor;
7
9
  return api.state.branches[cursor];
8
10
  };
9
11
 
10
12
  const refreshBranchList = (api) => {
11
- const repo = api.options.repo();
13
+ const repo = api.ui.repo;
12
14
  if (!repo.listBranches) return;
13
15
  try {
14
- api.state.branches = repo.listBranches(api.options.top());
16
+ api.state.branches = repo.listBranches(api.ui.top);
15
17
  } catch (error) {
16
- api.options.setStatus(error.message);
18
+ api.ui.status = error.message;
17
19
  return;
18
20
  }
19
21
  const last = api.state.branches.length - 1;
20
- const nav = api.options.nav;
22
+ const nav = api.ui.nav;
21
23
  if (nav.branchCursor > last) nav.branchCursor = Math.max(0, last);
22
24
  };
23
25
 
24
26
  const refreshAfterWrite = (api, extra = {}) => {
25
27
  refreshBranchList(api);
26
- api.options.refreshFromRepo({ keepEmpty: true, ...extra });
28
+ api.ui.commits.refresh();
29
+ api.ui.refreshFromRepo({ keepEmpty: true, ...extra });
27
30
  };
28
31
 
29
32
  const onBranch = (api) => {
30
- if (api.options.getMode() === 'compose') return;
31
- if (!api.options.canCommit()) return;
32
- const repo = api.options.repo();
33
- const caps = api.options.capabilities();
33
+ if (api.ui.mode === 'compose') return;
34
+ if (!api.ui.commits.canCommit()) return;
35
+ const repo = api.ui.repo;
36
+ const caps = api.ui.capabilities;
34
37
  if (!caps.branches || !repo.listBranches) {
35
- api.options.setStatus('read only');
38
+ api.ui.status = 'read only';
36
39
  return;
37
40
  }
38
41
  try {
39
- api.state.branches = repo.listBranches(api.options.top());
42
+ api.state.branches = repo.listBranches(api.ui.top);
40
43
  } catch (error) {
41
- api.options.setStatus(error.message);
44
+ api.ui.status = error.message;
42
45
  return;
43
46
  }
44
47
  const current = api.state.branches.findIndex((entry) => entry.current);
45
- api.options.nav.branchCursor = current < 0 ? 0 : current;
46
- api.options.nav.pane = 'branches';
47
- api.options.setStatus('');
48
- api.options.nav.clearSelection();
48
+ api.ui.nav.branchCursor = current < 0 ? 0 : current;
49
+ api.ui.nav.pane = 'branches';
50
+ api.ui.status = '';
51
+ api.ui.nav.clearSelection();
49
52
  };
50
53
 
51
54
  const onBranchMove = (api, delta) => {
52
55
  const branches = api.state.branches;
53
56
  if (!branches.length) {
54
- api.options.setStatus('nothing to review');
57
+ api.ui.status = 'nothing to review';
55
58
  return;
56
59
  }
57
60
  const next = Math.min(
58
61
  branches.length - 1,
59
- Math.max(0, api.options.nav.branchCursor + delta),
62
+ Math.max(0, api.ui.nav.branchCursor + delta),
60
63
  );
61
- if (next === api.options.nav.branchCursor) return;
62
- api.options.nav.branchCursor = next;
63
- api.options.setStatus('');
64
+ if (next === api.ui.nav.branchCursor) return;
65
+ api.ui.nav.branchCursor = next;
66
+ api.ui.status = '';
64
67
  };
65
68
 
66
69
  const checkoutAsync = (api, name, done, write) => {
67
- api.options.showFiles();
70
+ api.ui.showFiles();
68
71
  const run = (top) => write(top, name);
69
72
  const after = () =>
70
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
71
- return void api.options.runner.runBusy('checking out', done, run, after);
73
+ api.ui.refreshFromRepo({ keepEmpty: true, doneStatus: done });
74
+ return void api.ui.ops.runBusy('checking out', done, run, after);
72
75
  };
73
76
 
74
77
  const onCheckoutBranch = (api) => {
75
- if (!api.options.canCommit()) return;
78
+ if (!api.ui.commits.canCommit()) return;
76
79
  const entry = selectedBranch(api);
77
80
  if (!entry) return;
78
- if (entry.current) {
79
- api.options.showFiles();
80
- return;
81
- }
81
+ if (entry.current) return void api.ui.showFiles();
82
82
  const name = entry.name;
83
83
  const done = `checked out ${name}`;
84
- const uiOpen = api.options.uiOpen();
85
- const picked = pickRepoWrite(api.options.repo(), 'checkout', uiOpen);
84
+ const uiOpen = api.ui.uiOpen;
85
+ const picked = pickRepoWrite(api.ui.repo, 'checkout', uiOpen);
86
86
  if (picked.async) {
87
- checkoutAsync(api, name, done, picked.write);
88
- return;
87
+ return void checkoutAsync(api, name, done, picked.write);
89
88
  }
90
- const ok = api.options.runner.runRepo(done, (top) => {
91
- api.options.repo().checkout(top, name);
89
+ const ok = api.ui.ops.runRepo(done, (top) => {
90
+ api.ui.repo.checkout(top, name);
92
91
  });
93
92
  if (!ok) return;
94
- api.options.showFiles();
95
- api.options.refreshFromRepo({ keepEmpty: true });
96
- if (!api.options.getStatus()) api.options.setStatus(done);
93
+ api.ui.showFiles();
94
+ api.ui.refreshFromRepo({ keepEmpty: true });
95
+ if (!api.ui.status) api.ui.status = done;
97
96
  };
98
97
 
99
98
  const rebaseAsync = (api, onto, done, write) => {
100
99
  const run = (top) => write(top, onto);
101
100
  const after = () => refreshAfterWrite(api, { doneStatus: done });
102
- return void api.options.runner.runBusy('rebasing', done, run, after);
101
+ return void api.ui.ops.runBusy('rebasing', done, run, after);
103
102
  };
104
103
 
105
104
  const onRebaseBranch = (api) => {
106
- if (api.options.nav.pane !== 'branches') return;
107
- if (!api.options.canCommit()) return;
105
+ if (api.ui.nav.pane !== 'branches') return;
106
+ if (!api.ui.commits.canCommit()) return;
108
107
  const entry = selectedBranch(api);
109
108
  if (!entry || entry.current) return;
110
109
  const onto = entry.name;
111
110
  const done = `rebased onto ${onto}`;
112
- const uiOpen = api.options.uiOpen();
113
- const picked = pickRepoWrite(api.options.repo(), 'rebase', uiOpen);
111
+ const uiOpen = api.ui.uiOpen;
112
+ const picked = pickRepoWrite(api.ui.repo, 'rebase', uiOpen);
114
113
  if (picked.async) {
115
- rebaseAsync(api, onto, done, picked.write);
116
- return;
114
+ return void rebaseAsync(api, onto, done, picked.write);
117
115
  }
118
- const ok = api.options.runner.runRepo(done, (top) => {
119
- api.options.repo().rebase(top, onto);
116
+ const ok = api.ui.ops.runRepo(done, (top) => {
117
+ api.ui.repo.rebase(top, onto);
120
118
  });
121
119
  if (!ok) return;
122
120
  refreshAfterWrite(api);
123
- if (!api.options.getStatus()) api.options.setStatus(done);
121
+ if (!api.ui.status) api.ui.status = done;
124
122
  };
125
123
 
126
124
  const onDropBranch = (api) => {
127
- if (api.options.nav.pane !== 'branches') return;
128
- if (!api.options.canCommit()) return;
125
+ if (api.ui.nav.pane !== 'branches') return;
126
+ if (!api.ui.commits.canCommit()) return;
129
127
  const entry = selectedBranch(api);
130
128
  if (!entry || entry.current) return;
131
129
  api.state.dropName = entry.name;
132
- api.options.setMode('confirmDrop');
133
- api.options.setStatus('');
130
+ api.ui.mode = 'confirmDrop';
131
+ api.ui.status = '';
134
132
  };
135
133
 
136
134
  const cancelDropBranch = (api) => {
137
- api.options.setMode('review');
135
+ api.ui.mode = 'review';
138
136
  api.state.dropName = '';
139
- api.options.setStatus('');
137
+ api.ui.status = '';
140
138
  };
141
139
 
142
140
  const dropAsync = (api, name, done, write) => {
143
141
  const run = (top) => write(top, name);
144
142
  const after = () => refreshAfterWrite(api, { doneStatus: done });
145
- return void api.options.runner.runBusy('dropping', done, run, after);
143
+ return void api.ui.ops.runBusy('dropping', done, run, after);
146
144
  };
147
145
 
148
146
  const confirmDropBranch = (api) => {
149
147
  const name = api.state.dropName;
150
- api.options.setMode('review');
148
+ api.ui.mode = 'review';
151
149
  api.state.dropName = '';
152
150
  if (!name) return;
153
151
  const done = `dropped ${name}`;
154
- const uiOpen = api.options.uiOpen();
155
- const picked = pickRepoWrite(api.options.repo(), 'drop', uiOpen);
152
+ const uiOpen = api.ui.uiOpen;
153
+ const picked = pickRepoWrite(api.ui.repo, 'drop', uiOpen);
156
154
  if (picked.async) {
157
- dropAsync(api, name, done, picked.write);
158
- return;
155
+ return void dropAsync(api, name, done, picked.write);
159
156
  }
160
- const ok = api.options.runner.runRepo(done, (top) => {
161
- api.options.repo().drop(top, name);
157
+ const ok = api.ui.ops.runRepo(done, (top) => {
158
+ api.ui.repo.drop(top, name);
162
159
  });
163
160
  if (!ok) return;
164
161
  refreshAfterWrite(api);
165
- if (!api.options.getStatus()) api.options.setStatus(done);
162
+ if (!api.ui.status) api.ui.status = done;
166
163
  };
167
164
 
168
165
  const onNewBranch = (api) => {
169
- if (api.options.nav.pane !== 'branches') return;
170
- if (!api.options.canCommit()) return;
171
- api.options.composer.openCompose('branch', '');
166
+ if (api.ui.nav.pane !== 'branches') return;
167
+ if (!api.ui.commits.canCommit()) return;
168
+ api.ui.composer.openCompose('branch', '');
172
169
  };
173
170
 
174
171
  const createAsync = (api, name, done, write) => {
175
- api.options.composer.closeCompose();
176
- api.options.showFiles();
172
+ api.ui.composer.closeCompose();
173
+ api.ui.showFiles();
177
174
  const run = (top) => write(top, name);
178
175
  const after = () => refreshAfterWrite(api, { doneStatus: done });
179
- return void api.options.runner.runBusy('creating branch', done, run, after);
176
+ return void api.ui.ops.runBusy('creating branch', done, run, after);
180
177
  };
181
178
 
182
179
  const finishCreateBranch = (api) => {
183
- const editor = api.options.composer.state.editor;
180
+ const editor = api.ui.composer.state.editor;
184
181
  const name = editor ? editor.text.trim() : '';
185
182
  if (!name) {
186
- api.options.setStatus('empty branch name');
183
+ api.ui.status = 'empty branch name';
187
184
  return;
188
185
  }
189
186
  const done = `created ${name}`;
190
- const uiOpen = api.options.uiOpen();
191
- const picked = pickRepoWrite(api.options.repo(), 'createBranch', uiOpen);
187
+ const uiOpen = api.ui.uiOpen;
188
+ const picked = pickRepoWrite(api.ui.repo, 'createBranch', uiOpen);
192
189
  if (picked.async) {
193
- createAsync(api, name, done, picked.write);
194
- return;
190
+ return void createAsync(api, name, done, picked.write);
195
191
  }
196
- const ok = api.options.runner.runRepo(done, (top) => {
197
- api.options.repo().createBranch(top, name);
192
+ const ok = api.ui.ops.runRepo(done, (top) => {
193
+ api.ui.repo.createBranch(top, name);
198
194
  });
199
195
  if (!ok) return;
200
- api.options.composer.closeCompose();
201
- api.options.showFiles();
196
+ api.ui.composer.closeCompose();
197
+ api.ui.showFiles();
202
198
  refreshAfterWrite(api);
203
- if (!api.options.getStatus()) api.options.setStatus(done);
199
+ if (!api.ui.status) api.ui.status = done;
204
200
  };
205
201
 
206
202
  const onPull = (api) => {
207
- if (!api.options.canCommit()) return;
208
- const repo = api.options.repo();
209
- const picked = pickRepoWrite(repo, 'pull', api.options.uiOpen());
203
+ if (!api.ui.commits.canCommit()) return;
204
+ const repo = api.ui.repo;
205
+ const picked = pickRepoWrite(repo, 'pull', api.ui.uiOpen);
210
206
  if (picked.async) {
211
207
  const after = () => refreshAfterWrite(api);
212
208
  const write = (top) => picked.write(top);
213
- return void api.options.runner.runBusy('pulling', 'pulled', write, after);
209
+ return void api.ui.ops.runBusy('pulling', 'pulled', write, after);
214
210
  }
215
- const ok = api.options.runner.runRepo('pulled', (top) => {
211
+ const ok = api.ui.ops.runRepo('pulled', (top) => {
216
212
  repo.pull(top);
217
213
  });
218
214
  if (!ok) return;
219
215
  refreshAfterWrite(api);
220
- if (!api.options.getStatus()) api.options.setStatus('pulled');
216
+ if (!api.ui.status) api.ui.status = 'pulled';
221
217
  };
222
218
 
223
219
  const startPush = (api, force) => {
224
- if (!api.options.canCommit()) return;
220
+ if (!api.ui.commits.canCommit()) return;
225
221
  const done = force ? 'force pushed' : 'pushed';
226
222
  const kind = force ? 'force pushing' : 'pushing';
227
- const repo = api.options.repo();
228
- const picked = pickRepoWrite(repo, 'push', api.options.uiOpen());
223
+ const repo = api.ui.repo;
224
+ const picked = pickRepoWrite(repo, 'push', api.ui.uiOpen);
229
225
  if (picked.async) {
230
226
  const write = (top) => picked.write(top, force);
231
227
  const after = () => refreshAfterWrite(api);
232
- return void api.options.runner.runBusy(kind, done, write, after);
228
+ return void api.ui.ops.runBusy(kind, done, write, after);
233
229
  }
234
230
  try {
235
- repo.push(api.options.top(), force);
231
+ repo.push(api.ui.top, force);
236
232
  } catch (error) {
237
233
  if (error.rejected && !force) {
238
- api.options.setMode('confirmPush');
239
- api.options.setStatus('');
234
+ api.ui.mode = 'confirmPush';
235
+ api.ui.status = '';
240
236
  return;
241
237
  }
242
- api.options.setStatus(error.message);
238
+ api.ui.status = error.message;
243
239
  return;
244
240
  }
245
241
  refreshAfterWrite(api);
246
- api.options.setStatus(done);
242
+ api.ui.status = done;
247
243
  };
248
244
 
249
245
  const onPush = (api) => startPush(api, false);
250
246
 
251
247
  const onForcePush = (api) => {
252
- api.options.setMode('review');
248
+ api.ui.mode = 'review';
253
249
  startPush(api, true);
254
250
  };
255
251
 
256
252
  const cancelPush = (api) => {
257
- api.options.setMode('review');
258
- api.options.setStatus('');
253
+ api.ui.mode = 'review';
254
+ api.ui.status = '';
259
255
  };
260
256
 
261
257
  const reset = (state) => {
@@ -263,40 +259,32 @@ const reset = (state) => {
263
259
  state.dropName = '';
264
260
  };
265
261
 
266
- const createBranchController = (options) => {
262
+ const createBranchController = (ui) => {
267
263
  const state = {
268
264
  branches: [],
269
265
  dropName: '',
270
266
  };
271
- const api = { options, state };
272
- return {
273
- get branches() {
274
- return state.branches;
275
- },
276
- set branches(value) {
277
- state.branches = value;
278
- },
279
- get dropName() {
280
- return state.dropName;
267
+ const api = { ui, state };
268
+ return stateView(
269
+ state,
270
+ {
271
+ reset: () => reset(state),
272
+ onBranch: () => onBranch(api),
273
+ onBranchMove: (delta) => onBranchMove(api, delta),
274
+ onCheckoutBranch: () => onCheckoutBranch(api),
275
+ onRebaseBranch: () => onRebaseBranch(api),
276
+ onDropBranch: () => onDropBranch(api),
277
+ cancelDropBranch: () => cancelDropBranch(api),
278
+ confirmDropBranch: () => confirmDropBranch(api),
279
+ onNewBranch: () => onNewBranch(api),
280
+ finishCreateBranch: () => finishCreateBranch(api),
281
+ onPull: () => onPull(api),
282
+ onPush: () => onPush(api),
283
+ onForcePush: () => onForcePush(api),
284
+ cancelPush: () => cancelPush(api),
281
285
  },
282
- set dropName(value) {
283
- state.dropName = value;
284
- },
285
- reset: () => reset(state),
286
- onBranch: () => onBranch(api),
287
- onBranchMove: (delta) => onBranchMove(api, delta),
288
- onCheckoutBranch: () => onCheckoutBranch(api),
289
- onRebaseBranch: () => onRebaseBranch(api),
290
- onDropBranch: () => onDropBranch(api),
291
- cancelDropBranch: () => cancelDropBranch(api),
292
- confirmDropBranch: () => confirmDropBranch(api),
293
- onNewBranch: () => onNewBranch(api),
294
- finishCreateBranch: () => finishCreateBranch(api),
295
- onPull: () => onPull(api),
296
- onPush: () => onPush(api),
297
- onForcePush: () => onForcePush(api),
298
- cancelPush: () => cancelPush(api),
299
- };
286
+ ['branches', 'dropName'],
287
+ );
300
288
  };
301
289
 
302
290
  module.exports = { createBranchController };