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
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 };
@@ -11,10 +11,9 @@ 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'],
15
+ file: ['f'],
16
+ diff: ['d'],
18
17
  quit: ['q', 'ctrl-c'],
19
18
  };
20
19
  const ACTION_IDS = Object.keys(ACTIONS);
@@ -23,6 +22,16 @@ const BRANCH_ACTIONS = {
23
22
  newBranch: ['n'],
24
23
  rebase: ['r'],
25
24
  drop: ['d'],
25
+ pull: ['p'],
26
+ push: ['s'],
27
+ };
28
+
29
+ const COMMIT_ACTIONS = {
30
+ amend: ['a'],
31
+ fixup: ['f'],
32
+ drop: ['d'],
33
+ pull: ['p'],
34
+ push: ['s'],
26
35
  };
27
36
 
28
37
  const ACTION_HOT = {
@@ -40,8 +49,17 @@ const ACTION_LABEL = {
40
49
  next: '→',
41
50
  };
42
51
 
43
- const DIFF_DISABLED = ['commit', 'reload', 'branch', 'pull', 'push'];
52
+ const DIFF_DISABLED = ['commit', 'branch', 'pull', 'push', 'file', 'diff'];
53
+ const UNIT_DISABLED = [...DIFF_DISABLED, 'layout'];
44
54
  const FILES_DISABLED = ['layout', 'feedback', 'code'];
55
+ const FILES_HIDDEN = [
56
+ ...FILES_DISABLED,
57
+ 'prev',
58
+ 'next',
59
+ 'commit',
60
+ 'file',
61
+ 'diff',
62
+ ];
45
63
  const FILES_GIT_DISABLED = ['add', 'unstage', 'revert'];
46
64
  const FILES_TODO_DISABLED = [...FILES_GIT_DISABLED, ...FILES_DISABLED];
47
65
  const TODO_DISABLED = [
@@ -53,8 +71,9 @@ const TODO_DISABLED = [
53
71
  'feedback',
54
72
  'todo',
55
73
  'code',
56
- 'reload',
57
74
  'branch',
75
+ 'file',
76
+ 'diff',
58
77
  'pull',
59
78
  'push',
60
79
  ];
@@ -67,10 +86,25 @@ const BRANCHES_DISABLED = [
67
86
  'feedback',
68
87
  'todo',
69
88
  'code',
70
- 'reload',
71
89
  'branch',
72
- 'pull',
73
- 'push',
90
+ 'file',
91
+ 'diff',
92
+ 'prev',
93
+ 'next',
94
+ ];
95
+ const COMMITS_DISABLED = [
96
+ 'add',
97
+ 'unstage',
98
+ 'revert',
99
+ 'layout',
100
+ 'feedback',
101
+ 'todo',
102
+ 'code',
103
+ 'branch',
104
+ 'file',
105
+ 'diff',
106
+ 'prev',
107
+ 'next',
74
108
  ];
75
109
 
76
110
  const isTodosTarget = (item) =>
@@ -82,17 +116,35 @@ const diffGitDisabled = (item) => {
82
116
  return ['unstage'];
83
117
  };
84
118
 
119
+ const BRANCH_REMOTE = ['pull', 'push'];
120
+
85
121
  const branchGitDisabled = (item) => {
86
- if (item && !item.current) return [];
87
- return ['rebase', 'drop'];
122
+ const off = item && !item.current ? [] : ['rebase', 'drop'];
123
+ if (!item || !item.current) return [...off, ...BRANCH_REMOTE];
124
+ return off;
125
+ };
126
+
127
+ const commitWriteDisabled = (item) => {
128
+ if (!item || !item.sha) return ['amend', 'fixup', 'drop'];
129
+ return [];
130
+ };
131
+
132
+ const commitGitDisabled = (item) => {
133
+ const off = commitWriteDisabled(item);
134
+ if (item && item.canCommit === true) return off;
135
+ return [...off, 'commit', 'fixup'];
88
136
  };
89
137
 
90
138
  const disabledActions = (pane, item) => {
91
139
  const onTodos = isTodosTarget(item);
92
140
  if (pane === 'files') return onTodos ? FILES_TODO_DISABLED : FILES_DISABLED;
141
+ if (pane === 'unit') return [...UNIT_DISABLED, ...diffGitDisabled(item)];
93
142
  if (pane === 'branches') {
94
143
  return [...BRANCHES_DISABLED, ...branchGitDisabled(item)];
95
144
  }
145
+ if (pane === 'commits') {
146
+ return [...COMMITS_DISABLED, ...commitWriteDisabled(item)];
147
+ }
96
148
  if (onTodos) return TODO_DISABLED;
97
149
  return [...DIFF_DISABLED, ...diffGitDisabled(item)];
98
150
  };
@@ -116,16 +168,25 @@ const SCROLL = {
116
168
  };
117
169
 
118
170
  const KEY_TO_ACTION = {};
119
- const PANE_ONLY = ['branch', 'pull', 'push'];
171
+ const PANE_ONLY = ['branch', 'file', 'diff'];
120
172
  const FILES_KEYS = {};
121
- for (const id of PANE_ONLY) {
122
- for (const key of ACTIONS[id]) FILES_KEYS[key] = id;
173
+ for (const key of ACTIONS.branch) FILES_KEYS[key] = 'branch';
174
+ for (const id of BRANCH_REMOTE) {
175
+ for (const key of BRANCH_ACTIONS[id]) FILES_KEYS[key] = id;
123
176
  }
124
177
  const BRANCH_KEYS = {};
125
178
  for (const id of Object.keys(BRANCH_ACTIONS)) {
126
179
  for (const key of BRANCH_ACTIONS[id]) BRANCH_KEYS[key] = id;
127
180
  }
128
- const PANE_KEYS = { files: FILES_KEYS, branches: BRANCH_KEYS };
181
+ const COMMIT_KEYS = {};
182
+ for (const id of Object.keys(COMMIT_ACTIONS)) {
183
+ for (const key of COMMIT_ACTIONS[id]) COMMIT_KEYS[key] = id;
184
+ }
185
+ const PANE_KEYS = {
186
+ files: FILES_KEYS,
187
+ branches: BRANCH_KEYS,
188
+ commits: COMMIT_KEYS,
189
+ };
129
190
 
130
191
  for (const id of ACTION_IDS) {
131
192
  if (PANE_ONLY.includes(id)) continue;
@@ -134,22 +195,28 @@ for (const id of ACTION_IDS) {
134
195
 
135
196
  for (const key of Object.keys(SCROLL)) KEY_TO_ACTION[key] = SCROLL[key];
136
197
 
137
- const actionFromKey = (key, pane) => {
198
+ const actionFromKey = (key, pane, fileScope) => {
199
+ const listPane =
200
+ pane === 'files' || pane === 'branches' || pane === 'commits';
201
+ if (listPane && (key === 'left' || key === 'right')) return null;
138
202
  const paneKeys = PANE_KEYS[pane];
139
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
+ }
140
208
  return KEY_TO_ACTION[key] ?? null;
141
209
  };
142
210
 
143
- const actionKeys = (id) => ACTIONS[id] ?? BRANCH_ACTIONS[id] ?? [];
211
+ const actionKeys = (id) =>
212
+ ACTIONS[id] ?? BRANCH_ACTIONS[id] ?? COMMIT_ACTIONS[id] ?? [];
144
213
 
145
214
  const actionHot = (id) => ACTION_HOT[id] ?? actionKeys(id)[0];
146
215
 
147
- const actionLabel = (id) => ACTION_LABEL[id] ?? ACTION_HOT[id] ?? id;
148
-
149
216
  const actionLetter = actionHot;
150
217
 
151
218
  const buttonWord = (id) => {
152
- const word = actionLabel(id);
219
+ const word = ACTION_LABEL[id] ?? ACTION_HOT[id] ?? id;
153
220
  const mark = actionLetter(id);
154
221
  if (word.includes(mark)) return word;
155
222
  return `${mark}${word}`;
@@ -173,19 +240,6 @@ const CONFIRM = {
173
240
  escape: 'cancel',
174
241
  },
175
242
  },
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
243
  confirmUpdate: {
190
244
  choices: YES_NO,
191
245
  prefix: (view) => {
@@ -220,13 +274,11 @@ const CONFIRM = {
220
274
 
221
275
  const CONFIRM_MODE = Object.keys(CONFIRM);
222
276
 
223
- const normalizeConfirmKey = (key) =>
224
- key.length === 1 ? key.toLowerCase() : key;
225
-
226
277
  const confirmKey = (mode, key) => {
227
278
  const spec = CONFIRM[mode];
228
279
  if (!spec) return null;
229
- return spec.keys[normalizeConfirmKey(key)] ?? null;
280
+ const norm = key.length === 1 ? key.toLowerCase() : key;
281
+ return spec.keys[norm] ?? null;
230
282
  };
231
283
 
232
284
  const applyConfirm = (mode, key, handlers) => {
@@ -248,19 +300,24 @@ module.exports = {
248
300
  ACTIONS,
249
301
  ACTION_IDS,
250
302
  BRANCH_ACTIONS,
303
+ COMMIT_ACTIONS,
251
304
  ACTION_HOT,
252
305
  ACTION_LABEL,
253
306
  DIFF_DISABLED,
307
+ UNIT_DISABLED,
254
308
  FILES_DISABLED,
309
+ FILES_HIDDEN,
255
310
  FILES_GIT_DISABLED,
256
311
  FILES_TODO_DISABLED,
257
312
  TODO_DISABLED,
258
313
  BRANCHES_DISABLED,
314
+ COMMITS_DISABLED,
259
315
  SCROLL,
260
316
  PANE_ONLY,
261
317
  disabledActions,
262
318
  diffGitDisabled,
263
319
  branchGitDisabled,
320
+ commitGitDisabled,
264
321
  actionFromKey,
265
322
  actionKeys,
266
323
  actionHot,