reslop 0.2.4 → 0.2.6

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 (109) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/LICENSE +1 -1
  3. package/README.md +12 -13
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +32 -19
  6. package/lib/capabilities.js +8 -12
  7. package/lib/cli.js +40 -74
  8. package/lib/clipboard.js +48 -18
  9. package/lib/dashboard/git.js +128 -0
  10. package/lib/dashboard/model.js +332 -0
  11. package/lib/dashboard/npm.js +193 -0
  12. package/lib/dashboard/tree.js +278 -0
  13. package/lib/deps-diff.js +196 -404
  14. package/lib/deps.js +240 -399
  15. package/lib/detect.js +8 -18
  16. package/lib/diff/align.js +41 -113
  17. package/lib/diff/diff.js +12 -43
  18. package/lib/diff/display.js +25 -36
  19. package/lib/diff/edit.js +6 -20
  20. package/lib/diff/inline.js +138 -141
  21. package/lib/diff/items.js +33 -47
  22. package/lib/diff/parse.js +28 -56
  23. package/lib/diff/patch.js +12 -33
  24. package/lib/diff/unit.js +90 -206
  25. package/lib/editor.js +98 -55
  26. package/lib/files.js +86 -103
  27. package/lib/git-branches.js +254 -416
  28. package/lib/git-deps.js +182 -344
  29. package/lib/git-reword-todo.js +5 -13
  30. package/lib/git-worktree.js +141 -212
  31. package/lib/git.js +21 -49
  32. package/lib/github.js +67 -181
  33. package/lib/gitlab.js +40 -90
  34. package/lib/highlight/bash.js +55 -177
  35. package/lib/highlight/core.js +157 -132
  36. package/lib/highlight/css.js +25 -58
  37. package/lib/highlight/csv.js +19 -37
  38. package/lib/highlight/dart.js +72 -213
  39. package/lib/highlight/dot.js +16 -26
  40. package/lib/highlight/html.js +42 -63
  41. package/lib/highlight/js.js +177 -506
  42. package/lib/highlight/json.js +17 -37
  43. package/lib/highlight/log.js +22 -35
  44. package/lib/highlight/txt.js +9 -22
  45. package/lib/highlight.js +17 -46
  46. package/lib/keys.js +62 -85
  47. package/lib/manifest.js +67 -130
  48. package/lib/npm-commands.js +119 -189
  49. package/lib/remote.js +141 -197
  50. package/lib/render/branches.js +66 -73
  51. package/lib/render/chrome.js +264 -323
  52. package/lib/render/commits.js +187 -500
  53. package/lib/render/dash-activity.js +212 -0
  54. package/lib/render/dash-blocks.js +245 -0
  55. package/lib/render/dash-table.js +290 -0
  56. package/lib/render/dashboard.js +62 -0
  57. package/lib/render/diff.js +123 -228
  58. package/lib/render/files.js +45 -99
  59. package/lib/render/frame.js +129 -183
  60. package/lib/render/notes.js +144 -160
  61. package/lib/render/npm.js +234 -112
  62. package/lib/render/present.js +4 -11
  63. package/lib/render/primitives.js +131 -170
  64. package/lib/render/render.js +5 -14
  65. package/lib/render/report.js +43 -0
  66. package/lib/render/tiles.js +260 -0
  67. package/lib/render/unit.js +15 -28
  68. package/lib/report-model.js +110 -33
  69. package/lib/report-parse.js +56 -38
  70. package/lib/report-render.js +102 -59
  71. package/lib/report-run.js +87 -78
  72. package/lib/report-test.js +256 -141
  73. package/lib/report-tools.js +96 -161
  74. package/lib/review-merge.js +114 -152
  75. package/lib/review.js +115 -189
  76. package/lib/runs.js +225 -0
  77. package/lib/select.js +89 -75
  78. package/lib/session/accessors.js +14 -21
  79. package/lib/session/actions.js +82 -63
  80. package/lib/session/branches.js +193 -247
  81. package/lib/session/change-actions.js +171 -214
  82. package/lib/session/commit.js +280 -342
  83. package/lib/session/compose.js +559 -674
  84. package/lib/session/dashboard.js +385 -0
  85. package/lib/session/dispatch.js +164 -157
  86. package/lib/session/edit-click.js +57 -0
  87. package/lib/session/files-pane.js +85 -53
  88. package/lib/session/items.js +73 -104
  89. package/lib/session/lifecycle.js +403 -541
  90. package/lib/session/load.js +48 -68
  91. package/lib/session/navigation.js +96 -87
  92. package/lib/session/npm.js +409 -345
  93. package/lib/session/ops.js +196 -63
  94. package/lib/session/pointer.js +23 -15
  95. package/lib/session/progress.js +33 -21
  96. package/lib/session/review.js +33 -54
  97. package/lib/session/tasks.js +333 -0
  98. package/lib/session/templates.js +51 -59
  99. package/lib/session/terminal.js +85 -136
  100. package/lib/session/unit.js +3 -4
  101. package/lib/session/update.js +76 -97
  102. package/lib/session/view.js +52 -83
  103. package/lib/session/watch.js +208 -204
  104. package/lib/session.js +112 -237
  105. package/lib/update.js +45 -116
  106. package/lib/utilities.js +67 -89
  107. package/lib/wrap.js +33 -44
  108. package/package.json +1 -1
  109. package/lib/session/todos.js +0 -293
@@ -1,10 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const accessors = require('./accessors.js');
4
- const { stateView } = accessors;
5
-
6
3
  const files = require('../files.js');
7
- const { itemPath, TODO_FILE, isTodoItem } = files;
4
+ const { itemPath, TASKS_FILE, isTaskItem } = files;
8
5
  const review = require('../review.js');
9
6
  const { feedbackKey } = review;
10
7
  const diff = require('../diff/diff.js');
@@ -29,28 +26,24 @@ const npmBusyKind = (item) => {
29
26
  const blockKey = (item) => {
30
27
  if (!item || !item.file) return '';
31
28
  const rel = itemPath(item);
32
- if (isTodoItem(item)) return `todo:${TODO_FILE}`;
29
+ if (isTaskItem(item)) return `todo:${TASKS_FILE}`;
33
30
  const depId = depChangeKey(item);
34
31
  if (depId) return `${rel}:dep:${depId}`;
35
- if (!item.hunk) {
36
- const block = item.blockId ?? '-';
37
- return `${rel}:file:${block}`;
38
- }
39
- const oldStart = item.hunk.oldStart;
40
- const newStart = item.hunk.newStart;
41
32
  const block = item.blockId ?? '-';
33
+ if (!item.hunk) return `${rel}:file:${block}`;
34
+ const { oldStart, newStart } = item.hunk;
42
35
  return `${rel}:${oldStart}:${newStart}:${block}`;
43
36
  };
44
37
 
45
38
  const itemKey = (item) => {
46
39
  const key = blockKey(item);
47
- if (!key || isTodoItem(item)) return key;
40
+ if (!key || isTaskItem(item)) return key;
48
41
  const origin = item.origin ?? '';
49
42
  return `${origin}:${key}`;
50
43
  };
51
44
 
52
45
  const blockLinesKey = (item) => {
53
- if (!item || !item.file || isTodoItem(item)) return '';
46
+ if (!item || !item.file || isTaskItem(item)) return '';
54
47
  if (!item.hunk) return '';
55
48
  const parts = [itemPath(item)];
56
49
  for (const line of item.hunk.lines) {
@@ -122,37 +115,33 @@ const alignLoadedItems = (prev, next) => {
122
115
  const ordered = [];
123
116
  for (const [rel, list] of groupByPath(prev)) {
124
117
  seen.add(rel);
125
- const aligned = alignGroup(list, nextGroups.get(rel) ?? []);
126
- for (const item of aligned) ordered.push(item);
118
+ ordered.push(...alignGroup(list, nextGroups.get(rel) ?? []));
127
119
  }
128
120
  for (const [rel, list] of nextGroups) {
129
- if (seen.has(rel)) continue;
130
- for (const item of list) ordered.push(item);
121
+ if (!seen.has(rel)) ordered.push(...list);
131
122
  }
132
123
  return ordered;
133
124
  };
134
125
 
135
- const restoredIndex = (items, item) => {
136
- if (!item || !item.file) return -1;
137
- const origin = item.origin ?? '';
126
+ const originOf = (item) => item.origin ?? '';
127
+
128
+ const hunkStart = (item) => (item.hunk ? item.hunk.newStart : 0);
129
+
130
+ const sameLinesIndex = (items, item) => {
138
131
  const lines = blockLinesKey(item);
139
- if (lines) {
140
- let any = -1;
141
- for (let i = 0; i < items.length; i++) {
142
- if (blockLinesKey(items[i]) !== lines) continue;
143
- if (any < 0) any = i;
144
- if ((items[i].origin ?? '') === origin) return i;
145
- }
146
- if (any >= 0) return any;
147
- }
148
- const key = itemKey(item);
149
- if (key) {
150
- const exact = items.findIndex((entry) => itemKey(entry) === key);
151
- if (exact >= 0) return exact;
132
+ if (!lines) return -1;
133
+ let fallback = -1;
134
+ for (let i = 0; i < items.length; i++) {
135
+ if (blockLinesKey(items[i]) !== lines) continue;
136
+ if (originOf(items[i]) === originOf(item)) return i;
137
+ if (fallback < 0) fallback = i;
152
138
  }
139
+ return fallback;
140
+ };
141
+
142
+ const nearestHunkIndex = (items, item) => {
153
143
  const rel = itemPath(item);
154
144
  if (!rel) return -1;
155
- const start = item.hunk ? item.hunk.newStart : 0;
156
145
  let fileMatch = -1;
157
146
  let best = -1;
158
147
  let bestDist = Infinity;
@@ -160,19 +149,27 @@ const restoredIndex = (items, item) => {
160
149
  const entry = items[i];
161
150
  if (itemPath(entry) !== rel) continue;
162
151
  if (fileMatch < 0) fileMatch = i;
163
- if ((entry.origin ?? '') !== origin) continue;
164
- const at = entry.hunk ? entry.hunk.newStart : 0;
165
- const dist = Math.abs(at - start);
152
+ if (originOf(entry) !== originOf(item)) continue;
153
+ const dist = Math.abs(hunkStart(entry) - hunkStart(item));
166
154
  if (dist >= bestDist) continue;
167
155
  bestDist = dist;
168
156
  best = i;
169
157
  }
170
- if (best >= 0) return best;
171
- return fileMatch;
158
+ return best >= 0 ? best : fileMatch;
159
+ };
160
+
161
+ const restoredIndex = (items, item) => {
162
+ if (!item || !item.file) return -1;
163
+ const byLines = sameLinesIndex(items, item);
164
+ if (byLines >= 0) return byLines;
165
+ const key = itemKey(item);
166
+ const exact = key ? items.findIndex((entry) => itemKey(entry) === key) : -1;
167
+ if (exact >= 0) return exact;
168
+ return nearestHunkIndex(items, item);
172
169
  };
173
170
 
174
171
  const itemFeedKey = (item) => {
175
- if (!item || !item.file || isTodoItem(item)) return '';
172
+ if (!item || !item.file || isTaskItem(item)) return '';
176
173
  const hunk = item.hunk;
177
174
  const depId = depChangeKey(item);
178
175
  const file = depId ? `${itemPath(item)}#${depId}` : itemPath(item);
@@ -190,88 +187,60 @@ const sameBlock = (left, right) => {
190
187
  };
191
188
 
192
189
  const canEditCode = (item) => {
193
- if (!item || isTodoItem(item)) return false;
190
+ if (!item || isTaskItem(item)) return false;
194
191
  if (!item.hunk || !item.file) return false;
195
- if (item.file.isBinary) return false;
196
- return true;
192
+ return !item.file.isBinary;
197
193
  };
198
194
 
199
- const createItemCollection = () => {
200
- const state = {
201
- items: [],
202
- dismissed: new Set(),
203
- };
195
+ class ItemCollection {
196
+ constructor() {
197
+ this.items = [];
198
+ this.dismissed = new Set();
199
+ }
204
200
 
205
- const reset = () => {
206
- state.items = [];
207
- state.dismissed = new Set();
208
- };
201
+ reset() {
202
+ this.items = [];
203
+ this.dismissed = new Set();
204
+ }
209
205
 
210
- const isDismissed = (item) => state.dismissed.has(itemKey(item));
206
+ isDismissed(item) {
207
+ return this.dismissed.has(itemKey(item));
208
+ }
211
209
 
212
- const replace = (items) => {
213
- const aligned = alignLoadedItems(state.items, items);
214
- const next = [];
215
- for (const item of aligned) {
216
- if (isDismissed(item)) continue;
217
- next.push(item);
218
- }
219
- state.items = next;
220
- return next;
221
- };
210
+ replace(items) {
211
+ const aligned = alignLoadedItems(this.items, items);
212
+ this.items = aligned.filter((item) => !this.isDismissed(item));
213
+ return this.items;
214
+ }
222
215
 
223
- const dismiss = (item) => {
224
- state.dismissed.add(itemKey(item));
225
- };
216
+ dismiss(item) {
217
+ this.dismissed.add(itemKey(item));
218
+ }
226
219
 
227
- const clearDismissed = () => {
228
- state.dismissed.clear();
229
- };
220
+ clearDismissed() {
221
+ this.dismissed.clear();
222
+ }
230
223
 
231
- const findRestoredIndex = (item) => restoredIndex(state.items, item);
224
+ findRestoredIndex(item) {
225
+ return restoredIndex(this.items, item);
226
+ }
232
227
 
233
- const keepOrigin = (item, origin) => {
228
+ keepOrigin(item, origin) {
234
229
  const next = { ...item, origin };
235
- const { length } = state.items;
236
- const replaced = new Array(length);
237
- for (let i = 0; i < length; i++) {
238
- const entry = state.items[i];
239
- replaced[i] = sameBlock(entry, item) ? next : entry;
240
- }
241
- if (next.dep) {
242
- state.items = replaced;
243
- return;
244
- }
245
- state.items = refreshIndexPatches(replaced, next);
246
- };
247
-
248
- return stateView(
249
- state,
250
- {
251
- reset,
252
- replace,
253
- dismiss,
254
- clearDismissed,
255
- isDismissed,
256
- findRestoredIndex,
257
- keepOrigin,
258
- },
259
- ['items'],
260
- ['dismissed'],
261
- );
262
- };
230
+ const replaced = this.items.map((entry) =>
231
+ sameBlock(entry, item) ? next : entry,
232
+ );
233
+ this.items = next.dep ? replaced : refreshIndexPatches(replaced, next);
234
+ }
235
+ }
263
236
 
264
237
  module.exports = {
265
- depChangeKey,
266
238
  needsReload,
267
239
  npmBusyKind,
268
- blockKey,
269
- itemKey,
270
240
  itemFeedKey,
271
- blockLinesKey,
272
241
  alignLoadedItems,
273
242
  restoredIndex,
274
243
  sameBlock,
275
244
  canEditCode,
276
- createItemCollection,
245
+ ItemCollection,
277
246
  };