reslop 0.2.6 → 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 (42) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/lib/ansi.js +42 -2
  3. package/lib/api.js +1 -1
  4. package/lib/cli.js +21 -1
  5. package/lib/dashboard/model.js +28 -3
  6. package/lib/dashboard/npm.js +116 -19
  7. package/lib/files.js +13 -7
  8. package/lib/find.js +61 -0
  9. package/lib/git-deps.js +1 -0
  10. package/lib/git-worktree.js +22 -4
  11. package/lib/keys.js +26 -1
  12. package/lib/render/chrome.js +257 -79
  13. package/lib/render/dash-blocks.js +297 -46
  14. package/lib/render/dash-table.js +6 -1
  15. package/lib/render/files.js +23 -4
  16. package/lib/render/frame.js +4 -0
  17. package/lib/render/notes.js +13 -2
  18. package/lib/render/packages.js +93 -0
  19. package/lib/render/primitives.js +13 -6
  20. package/lib/render/repos.js +226 -0
  21. package/lib/render/search.js +25 -0
  22. package/lib/render/tiles.js +107 -12
  23. package/lib/review.js +5 -4
  24. package/lib/session/actions.js +136 -30
  25. package/lib/session/branches.js +3 -5
  26. package/lib/session/commit.js +31 -4
  27. package/lib/session/compose.js +19 -4
  28. package/lib/session/dashboard.js +160 -15
  29. package/lib/session/dispatch.js +38 -4
  30. package/lib/session/files-pane.js +17 -2
  31. package/lib/session/find.js +94 -0
  32. package/lib/session/lifecycle.js +27 -0
  33. package/lib/session/navigation.js +2 -0
  34. package/lib/session/packages.js +143 -0
  35. package/lib/session/pointer.js +14 -0
  36. package/lib/session/tasks.js +3 -3
  37. package/lib/session/view.js +15 -2
  38. package/lib/session/watch.js +5 -0
  39. package/lib/session/workspace.js +455 -0
  40. package/lib/session.js +14 -0
  41. package/lib/workspace.js +166 -0
  42. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const LIST_PANES = ['files', 'branches', 'commits', 'npm'];
3
+ const LIST_PANES = ['files', 'branches', 'commits', 'npm', 'packages'];
4
4
 
5
5
  const ACTIONS = {
6
6
  add: ['a'],
@@ -10,20 +10,20 @@ const ACTIONS = {
10
10
  commit: ['c'],
11
11
  prev: ['left', 'p', 'k'],
12
12
  next: ['right', 'n', 'j'],
13
- check: ['x', ' '],
13
+ check: [' '],
14
14
  layout: ['m'],
15
- feedback: ['f'],
15
+ feedback: [],
16
16
  tasks: ['t'],
17
17
  code: ['e'],
18
18
  branch: ['b'],
19
19
  file: ['f'],
20
20
  diff: ['d'],
21
- quit: ['q', 'ctrl-c'],
21
+ quit: ['ctrl-c'],
22
22
  };
23
23
  const ACTION_IDS = Object.keys(ACTIONS);
24
24
 
25
25
  const BRANCH_ACTIONS = {
26
- newBranch: ['n'],
26
+ newBranch: ['insert'],
27
27
  rebase: ['e'],
28
28
  drop: ['delete'],
29
29
  pull: ['p'],
@@ -31,18 +31,24 @@ const BRANCH_ACTIONS = {
31
31
  };
32
32
 
33
33
  const COMMIT_ACTIONS = {
34
- amend: ['a'],
34
+ newCommit: ['insert'],
35
35
  apply: ['p'],
36
36
  reword: ['e'],
37
- fixup: ['x'],
38
37
  drop: ['delete'],
39
38
  view: ['v'],
40
39
  };
41
40
 
41
+ const PACKAGE_ACTIONS = {
42
+ packageNew: ['insert'],
43
+ packageDrop: ['delete'],
44
+ packageWanted: ['w'],
45
+ packageLatest: ['l'],
46
+ };
47
+
42
48
  const NPM_ACTIONS = {
43
49
  npm: ['n'],
44
50
  npmEdit: ['e'],
45
- npmNew: ['i'],
51
+ npmNew: ['insert'],
46
52
  npmDrop: ['delete'],
47
53
  npmLogs: ['l'],
48
54
  npmStop: ['escape'],
@@ -69,32 +75,56 @@ const DASH_BLOCKS = {
69
75
  dashRun: 'run',
70
76
  dashTasks: 'tasks',
71
77
  };
72
- const DASH_ALLOWED = [...DASH_IDS, 'quit', 'theme'];
78
+ const DASH_ALLOWED = [...DASH_IDS, 'pull', 'push', 'quit', 'theme'];
79
+ const REPOS_ALLOWED = [
80
+ 'repoLeft',
81
+ 'repoRight',
82
+ 'repoUp',
83
+ 'repoDown',
84
+ 'open',
85
+ 'quit',
86
+ 'theme',
87
+ ];
73
88
  const DASH_HIDDEN = ACTION_IDS.filter((id) => id !== 'quit');
74
89
 
75
90
  const ACTION_HOT = {
76
91
  prev: '←',
77
92
  next: '→',
78
93
  drop: 'del',
94
+ newBranch: 'ins',
95
+ newCommit: 'ins',
96
+ feedback: 'q',
97
+ check: 'space',
98
+ theme: 'l',
99
+ npmNew: 'ins',
79
100
  npmDrop: 'del',
80
101
  npmStop: 'esc',
102
+ packageNew: 'ins',
103
+ packageDrop: 'del',
81
104
  };
82
105
 
83
106
  const ACTION_LABEL = {
84
107
  ...DASH_BLOCKS,
85
108
  revert: 'drop',
86
- check: 'x',
109
+ check: 'space',
110
+ theme: 'light',
87
111
  layout: 'mode',
88
112
  tasks: 'tasks',
89
113
  view: 'view',
90
114
  code: 'edit',
91
115
  reword: 'edit',
92
116
  drop: 'delete',
93
- newBranch: 'new',
117
+ newBranch: 'insert',
118
+ newCommit: 'insert',
119
+ feedback: 'quote',
94
120
  npmEdit: 'edit',
95
121
  npmNew: 'insert',
96
122
  npmDrop: 'delete',
97
123
  npmLogs: 'cleanup',
124
+ packageNew: 'insert',
125
+ packageDrop: 'delete',
126
+ packageWanted: 'wanted',
127
+ packageLatest: 'latest',
98
128
  npmStop: 'esc',
99
129
  npmVerbose: 'verbose',
100
130
  npmRerun: 're-run',
@@ -113,7 +143,7 @@ const DIFF_DISABLED = [
113
143
  'diff',
114
144
  ];
115
145
  const UNIT_DISABLED = [...DIFF_DISABLED, 'layout', 'ignore'];
116
- const FILES_DISABLED = ['layout', 'feedback', 'code'];
146
+ const FILES_DISABLED = ['layout', 'feedback'];
117
147
  const FILES_HIDDEN = [
118
148
  ...FILES_DISABLED,
119
149
  'check',
@@ -126,7 +156,7 @@ const FILES_HIDDEN = [
126
156
  'branch',
127
157
  ];
128
158
  const FILES_GIT_DISABLED = ['add', 'unstage', 'revert', 'ignore'];
129
- const FILES_TASKS_DISABLED = [...FILES_GIT_DISABLED, ...FILES_DISABLED];
159
+ const FILES_TASKS_DISABLED = [...FILES_GIT_DISABLED, ...FILES_DISABLED, 'code'];
130
160
  const TASKS_DISABLED = [
131
161
  'add',
132
162
  'unstage',
@@ -166,19 +196,44 @@ const NPM_DISABLED = [...BRANCHES_DISABLED, 'pull', 'push'];
166
196
  const isTasksTarget = (item) =>
167
197
  !!(item && (item.kind === 'tasks' || item.origin === 'task'));
168
198
 
199
+ const DIFF_MOVE_IDS = ['add', 'unstage', 'revert'];
200
+
201
+ const entryHasDiff = (entry) => {
202
+ if (!entry || entry.kind === 'tasks') return false;
203
+ const keys = [
204
+ 'added',
205
+ 'removed',
206
+ 'stagedAdded',
207
+ 'stagedRemoved',
208
+ 'unstagedAdded',
209
+ 'unstagedRemoved',
210
+ 'remaining',
211
+ ];
212
+ let total = 0;
213
+ for (const key of keys) total += entry[key] ?? 0;
214
+ return total > 0;
215
+ };
216
+
217
+ const lineHasDiff = (line) =>
218
+ !!line && (line.type === 'add' || line.type === 'del');
219
+
220
+ const withoutMoves = (off, hasDiff) => {
221
+ if (hasDiff) return off;
222
+ const next = off.slice();
223
+ for (const id of DIFF_MOVE_IDS) {
224
+ if (!next.includes(id)) next.push(id);
225
+ }
226
+ return next;
227
+ };
228
+
169
229
  const diffGitDisabled = (item) => {
170
230
  if (!item || isTasksTarget(item)) return [];
171
231
  if (item.origin === 'staged') return ['add'];
172
232
  return ['unstage'];
173
233
  };
174
234
 
175
- const BRANCH_REMOTE = ['pull', 'push'];
176
-
177
- const branchGitDisabled = (item) => {
178
- const off = item && !item.current ? [] : ['rebase', 'drop'];
179
- if (!item || !item.current) return [...off, ...BRANCH_REMOTE];
180
- return off;
181
- };
235
+ const branchGitDisabled = (item) =>
236
+ item && !item.current ? [] : ['rebase', 'drop'];
182
237
 
183
238
  const isFixupCommit = (item) =>
184
239
  `${item && item.subject ? item.subject : ''}`.startsWith('fixup!');
@@ -196,24 +251,42 @@ const commitWriteDisabled = (item) => {
196
251
  return ['amend', 'apply'];
197
252
  };
198
253
 
254
+ const commitChord = (item) => {
255
+ if (!item || item.pending || !item.sha) return 'commit';
256
+ if (item.head) return 'amend';
257
+ return 'fixup';
258
+ };
259
+
199
260
  const commitGitDisabled = (item) => {
200
261
  const off = [...commitWriteDisabled(item)];
201
262
  if (!isFixupCommit(item)) off.push('apply');
202
- if (item && item.canCommit === true) return off;
203
- return [...off, 'commit', 'fixup'];
263
+ const chord = commitChord(item);
264
+ const ready = item && item.canCommit === true;
265
+ if (chord === 'amend') return off;
266
+ if (!ready) off.push('commit');
267
+ return off;
204
268
  };
205
269
 
206
270
  const disabledActions = (pane, item) => {
207
271
  const onTodos = isTasksTarget(item);
208
- if (pane === 'files') return onTodos ? FILES_TASKS_DISABLED : FILES_DISABLED;
209
- if (pane === 'unit') return [...UNIT_DISABLED, ...diffGitDisabled(item)];
272
+ if (pane === 'dashboard' || pane === 'repos') return [];
273
+ if (pane === 'files') {
274
+ const base = onTodos ? FILES_TASKS_DISABLED : FILES_DISABLED;
275
+ if (onTodos) return base;
276
+ return withoutMoves(base, entryHasDiff(item));
277
+ }
278
+ if (pane === 'unit') {
279
+ const off = [...UNIT_DISABLED, ...diffGitDisabled(item)];
280
+ const onDiff = !item || item.lineDiff !== false;
281
+ return withoutMoves(off, onDiff);
282
+ }
210
283
  if (pane === 'branches') {
211
284
  return [...BRANCHES_DISABLED, ...branchGitDisabled(item)];
212
285
  }
213
286
  if (pane === 'commits') {
214
287
  return [...COMMITS_DISABLED, ...commitWriteDisabled(item)];
215
288
  }
216
- if (pane === 'npm') return NPM_DISABLED;
289
+ if (pane === 'npm' || pane === 'packages') return NPM_DISABLED;
217
290
  if (pane === 'tasks' || onTodos) return TASKS_DISABLED;
218
291
  return [...DIFF_DISABLED, ...diffGitDisabled(item)];
219
292
  };
@@ -250,25 +323,37 @@ const keysForActions = (actions) => {
250
323
 
251
324
  const PANE_ONLY = ['branch', 'file', 'diff'];
252
325
  const REVIEW_DROP = { d: 'revert' };
326
+ const DIFF_KEYS = { ...REVIEW_DROP, q: 'feedback' };
253
327
  const BRANCH_KEYS = keysForActions(BRANCH_ACTIONS);
254
- const COMMIT_KEYS = { ...keysForActions(COMMIT_ACTIONS), c: 'commit' };
328
+ const COMMIT_KEYS = { ...keysForActions(COMMIT_ACTIONS), s: 'push' };
255
329
  const NPM_KEYS = {
256
330
  e: 'npmEdit',
257
- i: 'npmNew',
331
+ insert: 'npmNew',
258
332
  delete: 'npmDrop',
259
333
  l: 'npmLogs',
260
334
  };
261
335
  const DASH_KEYS = keysForActions(DASH_ACTIONS);
262
336
  const SCREEN_KEYS = DASH_KEYS;
263
337
  const PANE_KEYS = {
264
- dashboard: DASH_KEYS,
338
+ dashboard: { ...DASH_KEYS, p: 'pull', s: 'push' },
265
339
  files: REVIEW_DROP,
266
- diff: REVIEW_DROP,
267
- unit: REVIEW_DROP,
340
+ diff: DIFF_KEYS,
341
+ unit: DIFF_KEYS,
268
342
  branches: BRANCH_KEYS,
269
343
  commits: COMMIT_KEYS,
270
344
  npm: NPM_KEYS,
345
+ packages: keysForActions(PACKAGE_ACTIONS),
271
346
  tasks: { delete: 'drop' },
347
+ repos: {
348
+ left: 'repoLeft',
349
+ right: 'repoRight',
350
+ up: 'repoUp',
351
+ down: 'repoDown',
352
+ k: 'repoUp',
353
+ j: 'repoDown',
354
+ p: 'repoLeft',
355
+ n: 'repoRight',
356
+ },
272
357
  };
273
358
 
274
359
  const KEY_TO_ACTION = {
@@ -296,6 +381,7 @@ const actionKeys = (id) =>
296
381
  BRANCH_ACTIONS[id] ??
297
382
  COMMIT_ACTIONS[id] ??
298
383
  NPM_ACTIONS[id] ??
384
+ PACKAGE_ACTIONS[id] ??
299
385
  DASH_ACTIONS[id] ??
300
386
  [];
301
387
 
@@ -356,6 +442,22 @@ const CONFIRM = {
356
442
  escape: 'cancel',
357
443
  },
358
444
  },
445
+ confirmCommit: {
446
+ choices: [
447
+ { letter: 'esc', label: 'esc cancel', lead: ' ' },
448
+ { letter: 'c', label: 'commit', lead: ' ' },
449
+ { letter: 'a', label: 'amend', lead: ' ' },
450
+ { letter: 'f', label: 'fixup', lead: ' ' },
451
+ ],
452
+ prefix: ' what do you want to do?',
453
+ keys: {
454
+ esc: 'cancel',
455
+ escape: 'cancel',
456
+ c: 'commit',
457
+ a: 'amend',
458
+ f: 'fixup',
459
+ },
460
+ },
359
461
  };
360
462
 
361
463
  const CONFIRM_MODE = Object.keys(CONFIRM);
@@ -381,6 +483,7 @@ module.exports = {
381
483
  DASH_BLOCKS,
382
484
  DASH_ALLOWED,
383
485
  DASH_HIDDEN,
486
+ REPOS_ALLOWED,
384
487
  ACTIONS,
385
488
  ACTION_IDS,
386
489
  BRANCH_ACTIONS,
@@ -396,6 +499,9 @@ module.exports = {
396
499
  COMMITS_DISABLED,
397
500
  NPM_DISABLED,
398
501
  disabledActions,
502
+ entryHasDiff,
503
+ lineHasDiff,
504
+ withoutMoves,
399
505
  diffGitDisabled,
400
506
  branchGitDisabled,
401
507
  commitGitDisabled,
@@ -83,13 +83,11 @@ class BranchController {
83
83
  const ui = this.ui;
84
84
  if (!ui.commits.canCommit()) return;
85
85
  const entry = this.selected();
86
- if (!entry) return;
87
- if (entry.current) return void ui.showFiles();
86
+ if (!entry || entry.current) return;
88
87
  const name = entry.name;
89
- const after = (extra) => ui.refreshFromRepo({ keepEmpty: true, ...extra });
90
- const leave = () => ui.showFiles();
88
+ const after = (extra) => this.refreshAfterWrite(extra);
91
89
  const done = `checked out ${name}`;
92
- ui.ops.runWrite('checkout', [name], 'checking out', done, after, leave);
90
+ ui.ops.runWrite('checkout', [name], 'checking out', done, after);
93
91
  }
94
92
 
95
93
  finishCreateBranch() {
@@ -200,19 +200,46 @@ class CommitController {
200
200
  editor.cursor = lineEnd < 0 ? editor.text.length : lineEnd;
201
201
  }
202
202
 
203
- onCommit() {
204
- if (this.ui.nav.pane !== 'commits') return void this.show();
205
- if (!this.canCommit()) return;
203
+ onInsert() {
204
+ const entry = this.selected();
205
+ if (!entry || entry.pending || !entry.sha) {
206
+ if (this.canCommit()) this.start('commit');
207
+ return;
208
+ }
209
+ if (!this.canWrite()) return;
210
+ this.ui.status = '';
211
+ this.ui.mode = 'confirmCommit';
212
+ }
213
+
214
+ chooseCommit(kind) {
215
+ this.ui.mode = 'review';
216
+ if (kind === 'amend') {
217
+ this.onAmend();
218
+ return;
219
+ }
220
+ if (kind === 'fixup') {
221
+ this.onFixup();
222
+ return;
223
+ }
206
224
  this.start('commit');
207
225
  }
208
226
 
227
+ cancelCommitChoice() {
228
+ this.ui.mode = 'review';
229
+ }
230
+
231
+ onCommit() {
232
+ if (this.ui.nav.pane === 'commits') return;
233
+ this.show();
234
+ }
235
+
209
236
  onShowDiff() {
210
237
  const ui = this.ui;
211
238
  if (ui.mode === 'compose') return;
212
239
  const entry = this.selected();
213
240
  if (!entry) return;
214
241
  const viewingCommit = Boolean(ui.rev || ui.revShort);
215
- if (entry.pending && !viewingCommit) return void this.onCommit();
242
+ if (entry.pending && !viewingCommit) return void this.onInsert();
216
243
  const sha = entry.pending ? '' : entry.sha || '';
217
244
  ui.rev = sha;
218
245
  ui.revShort = sha ? entry.shortSha || '' : '';
@@ -11,7 +11,8 @@ const { listedCommits } = commit;
11
11
  const editor = require('../editor.js');
12
12
  const { Editor } = editor;
13
13
  const files = require('../files.js');
14
- const { itemPath, isTaskItem, listPath, isReadOnlyOrigin } = files;
14
+ const { itemPath, isTaskItem, isTasksEntry, listPath } = files;
15
+ const { isReadOnlyOrigin } = files;
15
16
  const diff = require('../diff/diff.js');
16
17
  const { blockAddText } = diff;
17
18
  const items = require('./items.js');
@@ -37,10 +38,11 @@ const KIND = {
37
38
  commit: { enter: 'save', tab: 'template', escape: 'cancel', move: 'note' },
38
39
  branch: { enter: 'save', tab: 'template', escape: 'cancel', move: 'note' },
39
40
  npm: { enter: 'save', tab: 'insert-tab', escape: 'cancel', move: 'note' },
41
+ package: { enter: 'save', tab: 'insert-tab', escape: 'cancel', move: 'note' },
40
42
  };
41
43
 
42
- const COMMAND_KINDS = ['commit', 'branch', 'npm'];
43
- const NOTE_VIEWS = ['feedback', 'commit', 'branch', 'npm'];
44
+ const COMMAND_KINDS = ['commit', 'branch', 'npm', 'package'];
45
+ const NOTE_VIEWS = ['feedback', 'commit', 'branch', 'npm', 'package'];
44
46
 
45
47
  const itemNote = (item, text) => {
46
48
  const hunk = item.hunk;
@@ -544,8 +546,21 @@ class Composer {
544
546
  this.followFileEdit();
545
547
  }
546
548
 
549
+ onFileEdit() {
550
+ const ui = this.ui;
551
+ const list = ui.fileList();
552
+ const entry = list[ui.nav.fileCursor];
553
+ if (!entry || isTasksEntry(entry)) {
554
+ ui.status = 'not a diff block';
555
+ return;
556
+ }
557
+ unit.openUnitFile(ui, entry);
558
+ this.onUnitEdit();
559
+ }
560
+
547
561
  onCode() {
548
562
  const ui = this.ui;
563
+ if (ui.nav.pane === 'files') return void this.onFileEdit();
549
564
  if (ui.nav.pane === 'unit') return void this.onUnitEdit();
550
565
  const item = ui.current();
551
566
  if (ui.nav.pane === 'files' || !canEditCode(item)) {
@@ -634,7 +649,7 @@ class Composer {
634
649
  if (!key.length || key.startsWith('ctrl-') || key.startsWith('alt-')) {
635
650
  return null;
636
651
  }
637
- if (key.charCodeAt(0) >= 32) {
652
+ if (key.length === 1 && key.charCodeAt(0) >= 32) {
638
653
  this.templates.clearTemplatePick();
639
654
  this.editor.insert(key);
640
655
  this.afterEdit();