reslop 0.2.5 → 0.2.7

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 (114) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/LICENSE +1 -1
  3. package/README.md +11 -11
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +72 -19
  6. package/lib/api.js +1 -1
  7. package/lib/capabilities.js +8 -8
  8. package/lib/cli.js +61 -75
  9. package/lib/clipboard.js +39 -47
  10. package/lib/dashboard/git.js +128 -0
  11. package/lib/dashboard/model.js +357 -0
  12. package/lib/dashboard/npm.js +290 -0
  13. package/lib/dashboard/tree.js +278 -0
  14. package/lib/deps-diff.js +197 -402
  15. package/lib/deps.js +113 -240
  16. package/lib/detect.js +8 -18
  17. package/lib/diff/align.js +41 -113
  18. package/lib/diff/diff.js +12 -43
  19. package/lib/diff/display.js +25 -36
  20. package/lib/diff/edit.js +6 -20
  21. package/lib/diff/inline.js +76 -144
  22. package/lib/diff/items.js +33 -47
  23. package/lib/diff/parse.js +28 -56
  24. package/lib/diff/patch.js +12 -33
  25. package/lib/diff/unit.js +79 -178
  26. package/lib/editor.js +52 -69
  27. package/lib/files.js +79 -91
  28. package/lib/find.js +61 -0
  29. package/lib/git-branches.js +254 -416
  30. package/lib/git-deps.js +148 -272
  31. package/lib/git-reword-todo.js +5 -13
  32. package/lib/git-worktree.js +161 -214
  33. package/lib/git.js +21 -49
  34. package/lib/github.js +67 -181
  35. package/lib/gitlab.js +40 -90
  36. package/lib/highlight/bash.js +55 -177
  37. package/lib/highlight/core.js +155 -141
  38. package/lib/highlight/css.js +25 -58
  39. package/lib/highlight/csv.js +19 -37
  40. package/lib/highlight/dart.js +72 -213
  41. package/lib/highlight/dot.js +14 -14
  42. package/lib/highlight/html.js +42 -63
  43. package/lib/highlight/js.js +177 -506
  44. package/lib/highlight/json.js +17 -37
  45. package/lib/highlight/log.js +19 -25
  46. package/lib/highlight/txt.js +7 -10
  47. package/lib/highlight.js +17 -46
  48. package/lib/keys.js +75 -83
  49. package/lib/manifest.js +67 -126
  50. package/lib/npm-commands.js +120 -169
  51. package/lib/remote.js +140 -190
  52. package/lib/render/branches.js +63 -61
  53. package/lib/render/chrome.js +412 -347
  54. package/lib/render/commits.js +160 -361
  55. package/lib/render/dash-activity.js +212 -0
  56. package/lib/render/dash-blocks.js +496 -0
  57. package/lib/render/dash-table.js +295 -0
  58. package/lib/render/dashboard.js +62 -0
  59. package/lib/render/diff.js +123 -258
  60. package/lib/render/files.js +60 -86
  61. package/lib/render/frame.js +82 -117
  62. package/lib/render/notes.js +150 -210
  63. package/lib/render/npm.js +213 -177
  64. package/lib/render/packages.js +93 -0
  65. package/lib/render/present.js +4 -11
  66. package/lib/render/primitives.js +77 -172
  67. package/lib/render/render.js +5 -14
  68. package/lib/render/report.js +43 -0
  69. package/lib/render/repos.js +226 -0
  70. package/lib/render/search.js +25 -0
  71. package/lib/render/tiles.js +355 -0
  72. package/lib/render/unit.js +15 -31
  73. package/lib/report-model.js +110 -33
  74. package/lib/report-parse.js +56 -37
  75. package/lib/report-render.js +102 -59
  76. package/lib/report-run.js +87 -77
  77. package/lib/report-test.js +221 -99
  78. package/lib/report-tools.js +96 -154
  79. package/lib/review-merge.js +33 -41
  80. package/lib/review.js +69 -129
  81. package/lib/runs.js +225 -0
  82. package/lib/select.js +53 -91
  83. package/lib/session/accessors.js +14 -21
  84. package/lib/session/actions.js +189 -65
  85. package/lib/session/branches.js +164 -222
  86. package/lib/session/change-actions.js +49 -119
  87. package/lib/session/commit.js +298 -352
  88. package/lib/session/compose.js +572 -715
  89. package/lib/session/dashboard.js +530 -0
  90. package/lib/session/dispatch.js +197 -171
  91. package/lib/session/files-pane.js +92 -45
  92. package/lib/session/find.js +94 -0
  93. package/lib/session/items.js +6 -17
  94. package/lib/session/lifecycle.js +420 -466
  95. package/lib/session/load.js +1 -14
  96. package/lib/session/navigation.js +4 -2
  97. package/lib/session/npm.js +403 -420
  98. package/lib/session/ops.js +5 -13
  99. package/lib/session/packages.js +143 -0
  100. package/lib/session/pointer.js +30 -14
  101. package/lib/session/progress.js +39 -30
  102. package/lib/session/review.js +1 -3
  103. package/lib/session/tasks.js +277 -236
  104. package/lib/session/templates.js +51 -59
  105. package/lib/session/terminal.js +85 -132
  106. package/lib/session/view.js +59 -80
  107. package/lib/session/watch.js +201 -212
  108. package/lib/session/workspace.js +455 -0
  109. package/lib/session.js +95 -161
  110. package/lib/update.js +44 -111
  111. package/lib/utilities.js +46 -88
  112. package/lib/workspace.js +166 -0
  113. package/lib/wrap.js +29 -55
  114. package/package.json +1 -1
@@ -6,17 +6,8 @@ const QUIET_KIND = new Set(['staged', 'unstaged']);
6
6
  const pickRepoWrite = (repo, name, uiOpen) => {
7
7
  const asyncFn = repo[`${name}Async`];
8
8
  const allowAsync = uiOpen === true || ASYNC_WITHOUT_UI.includes(name);
9
- if (allowAsync && typeof asyncFn === 'function') {
10
- return {
11
- async: true,
12
- write: (top, ...args) => asyncFn(top, ...args),
13
- };
14
- }
15
- const syncFn = repo[name];
16
- return {
17
- async: false,
18
- write: (top, ...args) => syncFn(top, ...args),
19
- };
9
+ const isAsync = allowAsync && typeof asyncFn === 'function';
10
+ return { async: isAsync, write: isAsync ? asyncFn : repo[name] };
20
11
  };
21
12
 
22
13
  const showsBusy = (kind) => Boolean(kind) && !QUIET_KIND.has(kind);
@@ -86,7 +77,6 @@ class ChangeQueue {
86
77
 
87
78
  startReload() {
88
79
  const { ui } = this;
89
- if (typeof ui.reloadAfterChange !== 'function') return void ui.paint();
90
80
  this.reloading = true;
91
81
  ui.reloadAfterChange(() => {
92
82
  this.reloading = false;
@@ -231,15 +221,17 @@ class OpsRunner {
231
221
  this.finishBusy(done, after);
232
222
  }
233
223
 
234
- runWrite(name, args, kind, done, after) {
224
+ runWrite(name, args, kind, done, after, leave = null) {
235
225
  const { ui } = this;
236
226
  const picked = pickRepoWrite(ui.repo, name, ui.uiOpen);
237
227
  const write = (top) => picked.write(top, ...args);
238
228
  if (picked.async) {
229
+ if (leave) leave();
239
230
  const refresh = () => after({ doneStatus: done });
240
231
  return void this.runBusy(kind, done, write, refresh);
241
232
  }
242
233
  if (!this.runRepo(done, write)) return;
234
+ if (leave) leave();
243
235
  after({});
244
236
  if (!ui.status) ui.status = done;
245
237
  }
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+
3
+ const utilities = require('../utilities.js');
4
+ const { IS_WIN, npmBin, oneLine, runProc } = utilities;
5
+
6
+ const INSTALL_MS = 120000;
7
+
8
+ class PackageController {
9
+ constructor(ui) {
10
+ this.ui = ui;
11
+ this.dropName = '';
12
+ this.addDev = false;
13
+ this.running = false;
14
+ this.job = null;
15
+ }
16
+
17
+ rows() {
18
+ const data = this.ui.dashboard.packagesView();
19
+ const modules = data.modules;
20
+ return modules && modules.packages ? modules.packages : [];
21
+ }
22
+
23
+ selected() {
24
+ return this.rows()[this.ui.nav.packagesCursor] ?? null;
25
+ }
26
+
27
+ canWrite() {
28
+ if (this.running) return false;
29
+ const ui = this.ui;
30
+ const caps = ui.capabilities;
31
+ if (!ui.readOnly && (!caps || caps.changes !== false)) return true;
32
+ ui.status = 'read only';
33
+ return false;
34
+ }
35
+
36
+ need() {
37
+ if (!this.canWrite()) return null;
38
+ const pkg = this.selected();
39
+ if (pkg) return pkg;
40
+ this.ui.status = 'not a package';
41
+ return null;
42
+ }
43
+
44
+ create() {
45
+ if (!this.canWrite()) return;
46
+ const pkg = this.selected();
47
+ if (pkg && pkg.transitive) {
48
+ this.ui.status = 'transitive';
49
+ return;
50
+ }
51
+ this.addDev = Boolean(pkg && pkg.dev);
52
+ this.ui.composer.openCompose('package', '');
53
+ }
54
+
55
+ finishAdd() {
56
+ const editor = this.ui.composer.editor;
57
+ if (!editor) return;
58
+ const name = editor.text.trim();
59
+ if (!name || /\s/.test(name) || name.startsWith('-')) {
60
+ this.ui.status = 'name';
61
+ return;
62
+ }
63
+ const args = ['install', name];
64
+ if (this.addDev) args.push('--save-dev');
65
+ this.ui.composer.closeCompose();
66
+ this.job = this.exec(args, 'npm i', `installed ${name}`);
67
+ }
68
+
69
+ askDrop() {
70
+ const pkg = this.need();
71
+ if (!pkg) return;
72
+ if (pkg.transitive) {
73
+ this.ui.status = 'transitive';
74
+ return;
75
+ }
76
+ this.dropName = pkg.name;
77
+ this.ui.mode = 'confirmDrop';
78
+ this.ui.status = '';
79
+ }
80
+
81
+ cancelDrop() {
82
+ this.dropName = '';
83
+ this.ui.mode = 'review';
84
+ this.ui.status = '';
85
+ }
86
+
87
+ confirmDrop() {
88
+ const name = this.dropName;
89
+ this.dropName = '';
90
+ this.ui.mode = 'review';
91
+ if (!name) return;
92
+ const done = `dropped ${name}`;
93
+ this.job = this.exec(['uninstall', name], 'npm uninstall', done);
94
+ }
95
+
96
+ updateWanted() {
97
+ const pkg = this.need();
98
+ if (!pkg) return;
99
+ const done = `updated ${pkg.name}`;
100
+ this.job = this.exec(['update', pkg.name], 'npm i', done);
101
+ }
102
+
103
+ updateLatest() {
104
+ const pkg = this.need();
105
+ if (!pkg) return;
106
+ const args = ['install', `${pkg.name}@latest`];
107
+ if (pkg.dev) args.push('--save-dev');
108
+ this.job = this.exec(args, 'npm i', `updated ${pkg.name}`);
109
+ }
110
+
111
+ async exec(args, busy, done) {
112
+ const ui = this.ui;
113
+ this.running = true;
114
+ ui.status = '';
115
+ ui.ops.setBusy(busy);
116
+ ui.ignoreWatch(INSTALL_MS);
117
+ ui.paint();
118
+ let result;
119
+ try {
120
+ const hook = ui.repo && ui.repo.runPackage;
121
+ const options = { cwd: ui.top, shell: IS_WIN };
122
+ result = hook
123
+ ? await hook(ui.top, args)
124
+ : await runProc(npmBin(), args, options);
125
+ } catch (error) {
126
+ result = { error, status: 1, stderr: '' };
127
+ }
128
+ this.running = false;
129
+ ui.ops.clearBusy();
130
+ const failed = !result || result.error || result.status;
131
+ if (failed) {
132
+ const message = result && result.error ? result.error.message : '';
133
+ const stderr = result ? result.stderr : '';
134
+ ui.status = oneLine(stderr, message || 'npm failed');
135
+ } else {
136
+ ui.status = done;
137
+ ui.dashboard.tasks.npm.request();
138
+ }
139
+ ui.paint();
140
+ }
141
+ }
142
+
143
+ module.exports = { PackageController };
@@ -2,6 +2,7 @@
2
2
 
3
3
  const select = require('../select.js');
4
4
  const editClick = require('./edit-click.js');
5
+ const filesPane = require('./files-pane.js');
5
6
  const { extractText, isRange } = select;
6
7
  const keys = require('../keys.js');
7
8
  const { hitAction } = keys;
@@ -94,7 +95,19 @@ const RELEASE_TARGETS = [
94
95
  hits: 'statusHits',
95
96
  onHit: (ui, hit) => {
96
97
  if (hit.id === 'branch') return void ui.gitBranches.onBranch();
97
- ui.input.confirmChoice(hit.id);
98
+ ui.confirmChoice(hit.id);
99
+ },
100
+ },
101
+ {
102
+ match: (ui) => ui.pane === 'dashboard',
103
+ hits: 'fileHits',
104
+ onHit: (ui, hit) => ui.dashboard.open(hit.cursor),
105
+ },
106
+ {
107
+ match: (ui) => ui.pane === 'repos',
108
+ hits: 'fileHits',
109
+ onHit: (ui, hit) => {
110
+ void ui.workspace.openAt(hit.cursor);
98
111
  },
99
112
  },
100
113
  {
@@ -103,7 +116,7 @@ const RELEASE_TARGETS = [
103
116
  onHit: (ui, hit) => {
104
117
  const again = armDoubleClick(ui.nav, 'files', hit.cursor);
105
118
  ui.nav.fileCursor = hit.cursor;
106
- if (again) ui.filesPane.onOpenFile();
119
+ if (again) filesPane.onOpenFile(ui);
107
120
  },
108
121
  },
109
122
  {
@@ -122,7 +135,14 @@ const RELEASE_TARGETS = [
122
135
  if (ui.mode === 'compose') return;
123
136
  const again = armDoubleClick(ui.nav, 'commits', hit.cursor);
124
137
  ui.nav.commitCursor = hit.cursor;
125
- if (again) ui.filesPane.onOpenFile();
138
+ if (again) filesPane.onOpenFile(ui);
139
+ },
140
+ },
141
+ {
142
+ match: (ui) => ui.pane === 'packages',
143
+ hits: 'fileHits',
144
+ onHit: (ui, hit) => {
145
+ ui.nav.packagesCursor = hit.cursor;
126
146
  },
127
147
  },
128
148
  {
@@ -135,11 +155,11 @@ const RELEASE_TARGETS = [
135
155
  },
136
156
  },
137
157
  {
138
- match: (ui) => ui.pane === 'diff',
158
+ match: (ui) => ui.pane === 'tasks',
139
159
  hits: 'taskHits',
140
160
  onHit: (ui, hit) => {
141
- if (hit.check) return void ui.composer.onTaskCheck(hit.cursor);
142
- ui.composer.onTaskHit(hit.cursor);
161
+ if (hit.check) return void ui.composer.tasks.onTaskCheck(hit.cursor);
162
+ ui.composer.tasks.onTaskHit(hit.cursor);
143
163
  },
144
164
  },
145
165
  {
@@ -171,14 +191,14 @@ const onRelease = (ui, event) => {
171
191
  };
172
192
 
173
193
  const POINTER_HANDLERS = {
174
- wheelUp: (ui) => ui.filesPane.onScroll(-1),
175
- wheelDown: (ui) => ui.filesPane.onScroll(1),
194
+ wheelUp: (ui) => filesPane.onScroll(ui, -1),
195
+ wheelDown: (ui) => filesPane.onScroll(ui, 1),
176
196
  press: onPress,
177
197
  drag: onDrag,
178
198
  release: onRelease,
179
199
  };
180
200
 
181
- const handle = (ui, event) => {
201
+ const handlePointer = (ui, event) => {
182
202
  const kind = event.kind;
183
203
  const handler = POINTER_HANDLERS[kind];
184
204
  if (!handler) return;
@@ -187,8 +207,4 @@ const handle = (ui, event) => {
187
207
  handler(ui, event);
188
208
  };
189
209
 
190
- const createPointer = (ui) => ({
191
- handle: (event) => handle(ui, event),
192
- });
193
-
194
- module.exports = { createPointer };
210
+ module.exports = { handlePointer };
@@ -1,32 +1,41 @@
1
1
  'use strict';
2
2
 
3
- const createProgress = (term, onTick, intervalMs) => {
4
- const active = new Set();
5
-
6
- const tick = () => {
7
- if (!active.size) return;
8
- onTick();
9
- term.later('progress', tick, intervalMs);
10
- };
11
-
12
- const start = (id) => {
13
- active.add(id);
14
- term.later('progress', tick, intervalMs);
15
- };
16
-
17
- const stop = (id) => {
18
- active.delete(id);
19
- if (active.size === 0) term.cancel('progress');
20
- };
21
-
22
- const clear = () => {
23
- active.clear();
24
- term.cancel('progress');
25
- };
26
-
27
- const size = () => active.size;
28
-
29
- return { start, stop, clear, size };
30
- };
31
-
32
- module.exports = { createProgress };
3
+ class Progress {
4
+ constructor(term, onTick, intervalMs) {
5
+ this.term = term;
6
+ this.onTick = onTick;
7
+ this.intervalMs = intervalMs;
8
+ this.active = new Set();
9
+ }
10
+
11
+ tick() {
12
+ if (!this.active.size) return;
13
+ this.onTick();
14
+ this.schedule();
15
+ }
16
+
17
+ schedule() {
18
+ this.term.later('progress', () => this.tick(), this.intervalMs);
19
+ }
20
+
21
+ start(id) {
22
+ this.active.add(id);
23
+ this.schedule();
24
+ }
25
+
26
+ stop(id) {
27
+ this.active.delete(id);
28
+ if (!this.active.size) this.term.cancel('progress');
29
+ }
30
+
31
+ clear() {
32
+ this.active.clear();
33
+ this.term.cancel('progress');
34
+ }
35
+
36
+ size() {
37
+ return this.active.size;
38
+ }
39
+ }
40
+
41
+ module.exports = { Progress };
@@ -7,9 +7,7 @@ const { loadReview, flushReview } = review;
7
7
 
8
8
  class ReviewController {
9
9
  constructor() {
10
- this.store = null;
11
- this.didResume = false;
12
- this.importedRemote = false;
10
+ this.reset();
13
11
  }
14
12
 
15
13
  reset() {