reslop 0.1.8 → 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 (95) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +27 -38
  3. package/bin/reslop.js +2 -2
  4. package/lib/ansi.js +6 -2
  5. package/lib/api.js +2 -2
  6. package/lib/capabilities.js +10 -14
  7. package/lib/cli.js +28 -47
  8. package/lib/clipboard.js +1 -1
  9. package/lib/deps-diff.js +712 -0
  10. package/lib/deps.js +556 -32
  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 +34 -8
  20. package/lib/{git/branches.js → git-branches.js} +103 -10
  21. package/lib/{git/dependencies.js → git-deps.js} +111 -38
  22. package/lib/git.js +592 -65
  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 +22 -9
  30. package/lib/manifest.js +330 -0
  31. package/lib/remote.js +374 -0
  32. package/lib/render/branches.js +34 -66
  33. package/lib/render/chrome.js +57 -22
  34. package/lib/render/commits.js +85 -0
  35. package/lib/render/diff.js +16 -16
  36. package/lib/render/files.js +29 -37
  37. package/lib/render/frame.js +29 -13
  38. package/lib/render/notes.js +4 -3
  39. package/lib/render/primitives.js +46 -1
  40. package/lib/{render.js → render/render.js} +6 -7
  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 +93 -36
  46. package/lib/session/branches.js +130 -144
  47. package/lib/session/change-actions.js +206 -124
  48. package/lib/session/commit.js +217 -62
  49. package/lib/session/compose.js +158 -13
  50. package/lib/session/dispatch.js +109 -55
  51. package/lib/session/files-pane.js +145 -142
  52. package/lib/session/items.js +131 -34
  53. package/lib/session/lifecycle.js +82 -42
  54. package/lib/session/load.js +19 -33
  55. package/lib/session/navigation.js +15 -3
  56. package/lib/session/ops.js +28 -41
  57. package/lib/session/pointer.js +58 -54
  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 +82 -11
  64. package/lib/session/watch.js +11 -19
  65. package/lib/session.js +29 -226
  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 +2 -2
  71. package/lib/deps/changes.js +0 -331
  72. package/lib/deps/items.js +0 -131
  73. package/lib/deps/manifest.js +0 -145
  74. package/lib/deps/merge.js +0 -120
  75. package/lib/deps/proposals.js +0 -164
  76. package/lib/deps/reports.js +0 -180
  77. package/lib/deps/rows.js +0 -177
  78. package/lib/deps/scan.js +0 -138
  79. package/lib/deps/usage.js +0 -68
  80. package/lib/deps/versions.js +0 -119
  81. package/lib/diff.js +0 -33
  82. package/lib/git/changes.js +0 -164
  83. package/lib/git/read.js +0 -253
  84. package/lib/git/run.js +0 -100
  85. package/lib/npm/commands.js +0 -100
  86. package/lib/remote/changes.js +0 -37
  87. package/lib/remote/headers.js +0 -36
  88. package/lib/remote/http.js +0 -122
  89. package/lib/remote/notes.js +0 -94
  90. package/lib/review/format.js +0 -434
  91. package/lib/review/storage.js +0 -150
  92. package/lib/review/store.js +0 -178
  93. package/lib/review/templates.js +0 -49
  94. package/lib/session/origins.js +0 -7
  95. package/lib/sys.js +0 -84
@@ -1,263 +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
 
26
+ const refreshAfterWrite = (api, extra = {}) => {
27
+ refreshBranchList(api);
28
+ api.ui.commits.refresh();
29
+ api.ui.refreshFromRepo({ keepEmpty: true, ...extra });
30
+ };
31
+
24
32
  const onBranch = (api) => {
25
- if (api.options.getMode() === 'compose') return;
26
- if (!api.options.canCommit()) return;
27
- const repo = api.options.repo();
28
- 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;
29
37
  if (!caps.branches || !repo.listBranches) {
30
- api.options.setStatus('read only');
38
+ api.ui.status = 'read only';
31
39
  return;
32
40
  }
33
41
  try {
34
- api.state.branches = repo.listBranches(api.options.top());
42
+ api.state.branches = repo.listBranches(api.ui.top);
35
43
  } catch (error) {
36
- api.options.setStatus(error.message);
44
+ api.ui.status = error.message;
37
45
  return;
38
46
  }
39
47
  const current = api.state.branches.findIndex((entry) => entry.current);
40
- api.options.nav.branchCursor = current < 0 ? 0 : current;
41
- api.options.nav.pane = 'branches';
42
- api.options.setStatus('');
43
- 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();
44
52
  };
45
53
 
46
54
  const onBranchMove = (api, delta) => {
47
55
  const branches = api.state.branches;
48
56
  if (!branches.length) {
49
- api.options.setStatus('nothing to review');
57
+ api.ui.status = 'nothing to review';
50
58
  return;
51
59
  }
52
60
  const next = Math.min(
53
61
  branches.length - 1,
54
- Math.max(0, api.options.nav.branchCursor + delta),
62
+ Math.max(0, api.ui.nav.branchCursor + delta),
55
63
  );
56
- if (next === api.options.nav.branchCursor) return;
57
- api.options.nav.branchCursor = next;
58
- api.options.setStatus('');
64
+ if (next === api.ui.nav.branchCursor) return;
65
+ api.ui.nav.branchCursor = next;
66
+ api.ui.status = '';
59
67
  };
60
68
 
61
69
  const checkoutAsync = (api, name, done, write) => {
62
- api.options.showFiles();
70
+ api.ui.showFiles();
63
71
  const run = (top) => write(top, name);
64
72
  const after = () =>
65
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
66
- 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);
67
75
  };
68
76
 
69
77
  const onCheckoutBranch = (api) => {
70
- if (!api.options.canCommit()) return;
78
+ if (!api.ui.commits.canCommit()) return;
71
79
  const entry = selectedBranch(api);
72
80
  if (!entry) return;
73
- if (entry.current) {
74
- api.options.showFiles();
75
- return;
76
- }
81
+ if (entry.current) return void api.ui.showFiles();
77
82
  const name = entry.name;
78
83
  const done = `checked out ${name}`;
79
- const uiOpen = api.options.uiOpen();
80
- const picked = pickRepoWrite(api.options.repo(), 'checkout', uiOpen);
84
+ const uiOpen = api.ui.uiOpen;
85
+ const picked = pickRepoWrite(api.ui.repo, 'checkout', uiOpen);
81
86
  if (picked.async) {
82
- checkoutAsync(api, name, done, picked.write);
83
- return;
87
+ return void checkoutAsync(api, name, done, picked.write);
84
88
  }
85
- const ok = api.options.runner.runRepo(done, (top) => {
86
- api.options.repo().checkout(top, name);
89
+ const ok = api.ui.ops.runRepo(done, (top) => {
90
+ api.ui.repo.checkout(top, name);
87
91
  });
88
92
  if (!ok) return;
89
- api.options.showFiles();
90
- api.options.refreshFromRepo({ keepEmpty: true });
91
- 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;
92
96
  };
93
97
 
94
98
  const rebaseAsync = (api, onto, done, write) => {
95
99
  const run = (top) => write(top, onto);
96
- const after = () => {
97
- refreshBranchList(api);
98
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
99
- };
100
- return void api.options.runner.runBusy('rebasing', done, run, after);
100
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
101
+ return void api.ui.ops.runBusy('rebasing', done, run, after);
101
102
  };
102
103
 
103
104
  const onRebaseBranch = (api) => {
104
- if (api.options.nav.pane !== 'branches') return;
105
- if (!api.options.canCommit()) return;
105
+ if (api.ui.nav.pane !== 'branches') return;
106
+ if (!api.ui.commits.canCommit()) return;
106
107
  const entry = selectedBranch(api);
107
108
  if (!entry || entry.current) return;
108
109
  const onto = entry.name;
109
110
  const done = `rebased onto ${onto}`;
110
- const uiOpen = api.options.uiOpen();
111
- const picked = pickRepoWrite(api.options.repo(), 'rebase', uiOpen);
111
+ const uiOpen = api.ui.uiOpen;
112
+ const picked = pickRepoWrite(api.ui.repo, 'rebase', uiOpen);
112
113
  if (picked.async) {
113
- rebaseAsync(api, onto, done, picked.write);
114
- return;
114
+ return void rebaseAsync(api, onto, done, picked.write);
115
115
  }
116
- const ok = api.options.runner.runRepo(done, (top) => {
117
- api.options.repo().rebase(top, onto);
116
+ const ok = api.ui.ops.runRepo(done, (top) => {
117
+ api.ui.repo.rebase(top, onto);
118
118
  });
119
119
  if (!ok) return;
120
- refreshBranchList(api);
121
- api.options.refreshFromRepo({ keepEmpty: true });
122
- if (!api.options.getStatus()) api.options.setStatus(done);
120
+ refreshAfterWrite(api);
121
+ if (!api.ui.status) api.ui.status = done;
123
122
  };
124
123
 
125
124
  const onDropBranch = (api) => {
126
- if (api.options.nav.pane !== 'branches') return;
127
- if (!api.options.canCommit()) return;
125
+ if (api.ui.nav.pane !== 'branches') return;
126
+ if (!api.ui.commits.canCommit()) return;
128
127
  const entry = selectedBranch(api);
129
128
  if (!entry || entry.current) return;
130
129
  api.state.dropName = entry.name;
131
- api.options.setMode('confirmDrop');
132
- api.options.setStatus('');
130
+ api.ui.mode = 'confirmDrop';
131
+ api.ui.status = '';
133
132
  };
134
133
 
135
134
  const cancelDropBranch = (api) => {
136
- api.options.setMode('review');
135
+ api.ui.mode = 'review';
137
136
  api.state.dropName = '';
138
- api.options.setStatus('');
137
+ api.ui.status = '';
139
138
  };
140
139
 
141
140
  const dropAsync = (api, name, done, write) => {
142
141
  const run = (top) => write(top, name);
143
- const after = () => {
144
- refreshBranchList(api);
145
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
146
- };
147
- return void api.options.runner.runBusy('dropping', done, run, after);
142
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
143
+ return void api.ui.ops.runBusy('dropping', done, run, after);
148
144
  };
149
145
 
150
146
  const confirmDropBranch = (api) => {
151
147
  const name = api.state.dropName;
152
- api.options.setMode('review');
148
+ api.ui.mode = 'review';
153
149
  api.state.dropName = '';
154
150
  if (!name) return;
155
151
  const done = `dropped ${name}`;
156
- const uiOpen = api.options.uiOpen();
157
- const picked = pickRepoWrite(api.options.repo(), 'drop', uiOpen);
152
+ const uiOpen = api.ui.uiOpen;
153
+ const picked = pickRepoWrite(api.ui.repo, 'drop', uiOpen);
158
154
  if (picked.async) {
159
- dropAsync(api, name, done, picked.write);
160
- return;
155
+ return void dropAsync(api, name, done, picked.write);
161
156
  }
162
- const ok = api.options.runner.runRepo(done, (top) => {
163
- api.options.repo().drop(top, name);
157
+ const ok = api.ui.ops.runRepo(done, (top) => {
158
+ api.ui.repo.drop(top, name);
164
159
  });
165
160
  if (!ok) return;
166
- refreshBranchList(api);
167
- api.options.refreshFromRepo({ keepEmpty: true });
168
- if (!api.options.getStatus()) api.options.setStatus(done);
161
+ refreshAfterWrite(api);
162
+ if (!api.ui.status) api.ui.status = done;
169
163
  };
170
164
 
171
165
  const onNewBranch = (api) => {
172
- if (api.options.nav.pane !== 'branches') return;
173
- if (!api.options.canCommit()) return;
174
- 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', '');
175
169
  };
176
170
 
177
171
  const createAsync = (api, name, done, write) => {
178
- api.options.composer.closeCompose();
179
- api.options.showFiles();
172
+ api.ui.composer.closeCompose();
173
+ api.ui.showFiles();
180
174
  const run = (top) => write(top, name);
181
- const after = () =>
182
- api.options.refreshFromRepo({ keepEmpty: true, doneStatus: done });
183
- return void api.options.runner.runBusy('creating branch', done, run, after);
175
+ const after = () => refreshAfterWrite(api, { doneStatus: done });
176
+ return void api.ui.ops.runBusy('creating branch', done, run, after);
184
177
  };
185
178
 
186
179
  const finishCreateBranch = (api) => {
187
- const editor = api.options.composer.state.editor;
180
+ const editor = api.ui.composer.state.editor;
188
181
  const name = editor ? editor.text.trim() : '';
189
182
  if (!name) {
190
- api.options.setStatus('empty branch name');
183
+ api.ui.status = 'empty branch name';
191
184
  return;
192
185
  }
193
186
  const done = `created ${name}`;
194
- const uiOpen = api.options.uiOpen();
195
- const picked = pickRepoWrite(api.options.repo(), 'createBranch', uiOpen);
187
+ const uiOpen = api.ui.uiOpen;
188
+ const picked = pickRepoWrite(api.ui.repo, 'createBranch', uiOpen);
196
189
  if (picked.async) {
197
- createAsync(api, name, done, picked.write);
198
- return;
190
+ return void createAsync(api, name, done, picked.write);
199
191
  }
200
- const ok = api.options.runner.runRepo(done, (top) => {
201
- api.options.repo().createBranch(top, name);
192
+ const ok = api.ui.ops.runRepo(done, (top) => {
193
+ api.ui.repo.createBranch(top, name);
202
194
  });
203
195
  if (!ok) return;
204
- api.options.composer.closeCompose();
205
- api.options.showFiles();
206
- api.options.refreshFromRepo({ keepEmpty: true });
207
- if (!api.options.getStatus()) api.options.setStatus(done);
196
+ api.ui.composer.closeCompose();
197
+ api.ui.showFiles();
198
+ refreshAfterWrite(api);
199
+ if (!api.ui.status) api.ui.status = done;
208
200
  };
209
201
 
210
202
  const onPull = (api) => {
211
- if (!api.options.canCommit()) return;
212
- const repo = api.options.repo();
213
- 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);
214
206
  if (picked.async) {
215
- const after = () => api.options.refreshFromRepo({ keepEmpty: true });
207
+ const after = () => refreshAfterWrite(api);
216
208
  const write = (top) => picked.write(top);
217
- return void api.options.runner.runBusy('pulling', 'pulled', write, after);
209
+ return void api.ui.ops.runBusy('pulling', 'pulled', write, after);
218
210
  }
219
- const ok = api.options.runner.runRepo('pulled', (top) => {
211
+ const ok = api.ui.ops.runRepo('pulled', (top) => {
220
212
  repo.pull(top);
221
213
  });
222
214
  if (!ok) return;
223
- api.options.refreshFromRepo({ keepEmpty: true });
224
- if (!api.options.getStatus()) api.options.setStatus('pulled');
215
+ refreshAfterWrite(api);
216
+ if (!api.ui.status) api.ui.status = 'pulled';
225
217
  };
226
218
 
227
219
  const startPush = (api, force) => {
228
- if (!api.options.canCommit()) return;
220
+ if (!api.ui.commits.canCommit()) return;
229
221
  const done = force ? 'force pushed' : 'pushed';
230
222
  const kind = force ? 'force pushing' : 'pushing';
231
- const repo = api.options.repo();
232
- const picked = pickRepoWrite(repo, 'push', api.options.uiOpen());
223
+ const repo = api.ui.repo;
224
+ const picked = pickRepoWrite(repo, 'push', api.ui.uiOpen);
233
225
  if (picked.async) {
234
226
  const write = (top) => picked.write(top, force);
235
- return void api.options.runner.runBusy(kind, done, write);
227
+ const after = () => refreshAfterWrite(api);
228
+ return void api.ui.ops.runBusy(kind, done, write, after);
236
229
  }
237
230
  try {
238
- repo.push(api.options.top(), force);
231
+ repo.push(api.ui.top, force);
239
232
  } catch (error) {
240
233
  if (error.rejected && !force) {
241
- api.options.setMode('confirmPush');
242
- api.options.setStatus('');
234
+ api.ui.mode = 'confirmPush';
235
+ api.ui.status = '';
243
236
  return;
244
237
  }
245
- api.options.setStatus(error.message);
238
+ api.ui.status = error.message;
246
239
  return;
247
240
  }
248
- api.options.setStatus(done);
241
+ refreshAfterWrite(api);
242
+ api.ui.status = done;
249
243
  };
250
244
 
251
245
  const onPush = (api) => startPush(api, false);
252
246
 
253
247
  const onForcePush = (api) => {
254
- api.options.setMode('review');
248
+ api.ui.mode = 'review';
255
249
  startPush(api, true);
256
250
  };
257
251
 
258
252
  const cancelPush = (api) => {
259
- api.options.setMode('review');
260
- api.options.setStatus('');
253
+ api.ui.mode = 'review';
254
+ api.ui.status = '';
261
255
  };
262
256
 
263
257
  const reset = (state) => {
@@ -265,40 +259,32 @@ const reset = (state) => {
265
259
  state.dropName = '';
266
260
  };
267
261
 
268
- const createBranchController = (options) => {
262
+ const createBranchController = (ui) => {
269
263
  const state = {
270
264
  branches: [],
271
265
  dropName: '',
272
266
  };
273
- const api = { options, state };
274
- return {
275
- get branches() {
276
- return state.branches;
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),
277
285
  },
278
- set branches(value) {
279
- state.branches = value;
280
- },
281
- get dropName() {
282
- return state.dropName;
283
- },
284
- set dropName(value) {
285
- state.dropName = value;
286
- },
287
- reset: () => reset(state),
288
- onBranch: () => onBranch(api),
289
- onBranchMove: (delta) => onBranchMove(api, delta),
290
- onCheckoutBranch: () => onCheckoutBranch(api),
291
- onRebaseBranch: () => onRebaseBranch(api),
292
- onDropBranch: () => onDropBranch(api),
293
- cancelDropBranch: () => cancelDropBranch(api),
294
- confirmDropBranch: () => confirmDropBranch(api),
295
- onNewBranch: () => onNewBranch(api),
296
- finishCreateBranch: () => finishCreateBranch(api),
297
- onPull: () => onPull(api),
298
- onPush: () => onPush(api),
299
- onForcePush: () => onForcePush(api),
300
- cancelPush: () => cancelPush(api),
301
- };
286
+ ['branches', 'dropName'],
287
+ );
302
288
  };
303
289
 
304
290
  module.exports = { createBranchController };