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,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const files = require('./files.js');
4
- const { TODO_FILE } = files;
4
+ const { TASKS_FILE, taskKind } = files;
5
5
 
6
6
  const flatText = (text) => `${text ?? ''}`.trim().replace(/\n/g, ' ');
7
7
 
@@ -9,28 +9,20 @@ const snapTodo = (todo) => ({
9
9
  file: todo.file ?? '',
10
10
  text: flatText(todo.text),
11
11
  done: todo.done === true,
12
+ kind: taskKind(todo),
12
13
  });
13
14
 
14
- const snapList = (todos) => {
15
- const list = [];
16
- for (const todo of todos ?? []) {
17
- const snap = snapTodo(todo);
18
- if (!snap.text) continue;
19
- list.push(snap);
20
- }
21
- return list;
22
- };
15
+ const snapList = (todos) => todos.map(snapTodo).filter((snap) => snap.text);
23
16
 
24
17
  const copyMap = (map) => {
25
18
  const next = new Map();
26
- if (!map) return next;
27
19
  for (const [key, note] of map) next.set(key, { ...note });
28
20
  return next;
29
21
  };
30
22
 
31
23
  const snapshotSide = (store) => ({
32
24
  status: store.status,
33
- todos: snapList(store.todos),
25
+ tasks: snapList(store.tasks),
34
26
  feedback: copyMap(store.feedback),
35
27
  code: copyMap(store.code),
36
28
  });
@@ -58,162 +50,137 @@ const pickDone = (baseDone, ourDone, theirDone) => {
58
50
 
59
51
  const withDone = (todo, done) => {
60
52
  if (todo.done === done) return todo;
61
- return { id: todo.id, file: todo.file, text: todo.text, done };
53
+ return { ...todo, done };
62
54
  };
63
55
 
64
56
  const liveText = (todo) => flatText(todo.text);
65
57
 
66
58
  const snapText = (snap) => snap.text;
67
59
 
60
+ const liveKey = (todo) => `${taskKind(todo)}\0${liveText(todo)}`;
61
+
62
+ const snapKey = (snap) => `${taskKind(snap)}\0${snapText(snap)}`;
63
+
68
64
  const flags = (n) => new Array(n).fill(false);
69
65
 
70
66
  const adoptTodo = (store, snap) => {
71
- const id = store.nextTodoId;
72
- store.nextTodoId += 1;
73
- const file = snap.file || TODO_FILE;
74
- return { id, file, text: snap.text, done: snap.done };
67
+ const id = store.nextTaskId;
68
+ store.nextTaskId += 1;
69
+ const file = snap.file || TASKS_FILE;
70
+ return { id, file, text: snap.text, done: snap.done, kind: taskKind(snap) };
75
71
  };
76
72
 
77
- const findMerged = (merged, alias, text) => {
78
- const linked = alias.get(text);
79
- if (linked) {
80
- const at = merged.indexOf(linked);
81
- if (at >= 0) return at;
82
- }
83
- for (let i = 0; i < merged.length; i++) {
84
- if (liveText(merged[i]) === text) return i;
85
- }
86
- return -1;
87
- };
73
+ const replaceTodo = (todo, snap) => ({
74
+ ...todo,
75
+ text: snap.text,
76
+ done: snap.done,
77
+ kind: taskKind(snap),
78
+ });
88
79
 
89
- const insertTheir = (store, merged, theirs, theirKeep, alias) => {
90
- for (let i = 0; i < theirs.length; i++) {
91
- if (!theirKeep[i]) continue;
92
- let at = merged.length;
93
- let placed = false;
94
- for (let j = i - 1; j >= 0 && !placed; j--) {
95
- const prev = findMerged(merged, alias, theirs[j].text);
96
- if (prev < 0) continue;
97
- at = prev + 1;
98
- placed = true;
80
+ class TodoMerge {
81
+ constructor(store, theirs) {
82
+ this.store = store;
83
+ this.ours = store.tasks.filter((todo) => liveText(todo));
84
+ this.theirs = theirs;
85
+ this.usedOurs = flags(this.ours.length);
86
+ this.usedTheirs = flags(theirs.length);
87
+ this.kept = flags(this.ours.length);
88
+ this.dropped = flags(this.ours.length);
89
+ this.theirKeep = flags(theirs.length);
90
+ this.alias = new Map();
91
+ }
92
+
93
+ keepOurs(index) {
94
+ this.kept[index] = true;
95
+ this.alias.set(liveKey(this.ours[index]), this.ours[index]);
96
+ }
97
+
98
+ mergeBase(base) {
99
+ const { ours, theirs } = this;
100
+ const key = snapKey(base);
101
+ const oi = claim(ours, this.usedOurs, key, liveKey);
102
+ const ti = claim(theirs, this.usedTheirs, key, snapKey);
103
+ if (oi >= 0 && ti >= 0) {
104
+ const done = pickDone(base.done, ours[oi].done === true, theirs[ti].done);
105
+ ours[oi] = withDone(ours[oi], done);
106
+ this.keepOurs(oi);
107
+ } else if (oi >= 0) {
108
+ if (ours[oi].done === base.done) this.dropped[oi] = true;
109
+ else this.keepOurs(oi);
110
+ } else if (ti >= 0 && theirs[ti].done !== base.done) {
111
+ this.theirKeep[ti] = true;
99
112
  }
100
- for (let j = i + 1; j < theirs.length && !placed; j++) {
101
- const next = findMerged(merged, alias, theirs[j].text);
102
- if (next < 0) continue;
103
- at = next;
104
- placed = true;
105
- }
106
- const item = adoptTodo(store, theirs[i]);
107
- merged.splice(at, 0, item);
108
- alias.set(theirs[i].text, item);
109
113
  }
110
- return merged;
111
- };
112
-
113
- const keepOurs = (ours, kept, alias, index, text) => {
114
- kept[index] = true;
115
- alias.set(text, ours[index]);
116
- };
117
114
 
118
- const mergeBaseTodo = (
119
- base,
120
- ours,
121
- theirs,
122
- used,
123
- kept,
124
- dropped,
125
- theirKeep,
126
- alias,
127
- ) => {
128
- const text = base.text;
129
- const oi = claim(ours, used.ours, text, liveText);
130
- const ti = claim(theirs, used.theirs, text, snapText);
131
- if (oi >= 0 && ti >= 0) {
132
- const done = pickDone(base.done, ours[oi].done === true, theirs[ti].done);
133
- ours[oi] = withDone(ours[oi], done);
134
- keepOurs(ours, kept, alias, oi, text);
135
- return;
136
- }
137
- if (oi >= 0) {
138
- if (ours[oi].done === base.done) {
139
- dropped[oi] = true;
115
+ mergeFresh(index) {
116
+ const { ours, theirs } = this;
117
+ const key = liveKey(ours[index]);
118
+ const ti = claim(theirs, this.usedTheirs, key, snapKey);
119
+ if (ti < 0) {
120
+ this.kept[index] = true;
140
121
  return;
141
122
  }
142
- keepOurs(ours, kept, alias, oi, text);
143
- return;
123
+ const done = ours[index].done === true || theirs[ti].done === true;
124
+ ours[index] = withDone(ours[index], done);
125
+ this.keepOurs(index);
144
126
  }
145
- if (ti >= 0 && theirs[ti].done !== base.done) theirKeep[ti] = true;
146
- };
147
127
 
148
- const replaceTodo = (todo, snap) => ({
149
- id: todo.id,
150
- file: todo.file,
151
- text: snap.text,
152
- done: snap.done,
153
- });
154
-
155
- const fillGaps = (merged, gaps, theirs, theirKeep, alias) => {
156
- let filled = 0;
157
- for (let i = 0; i < theirs.length && filled < gaps.length; i++) {
158
- if (!theirKeep[i]) continue;
159
- const gap = gaps[filled];
160
- const item = replaceTodo(gap.todo, theirs[i]);
161
- merged.splice(gap.at, 0, item);
162
- alias.set(theirs[i].text, item);
163
- theirKeep[i] = false;
164
- filled += 1;
128
+ findMerged(merged, snap) {
129
+ const key = snapKey(snap);
130
+ const linked = this.alias.get(key);
131
+ const at = linked ? merged.indexOf(linked) : -1;
132
+ if (at >= 0) return at;
133
+ return merged.findIndex((todo) => liveKey(todo) === key);
165
134
  }
166
- };
167
135
 
168
- const mergeFreshTodo = (ours, theirs, used, kept, alias, index) => {
169
- const text = liveText(ours[index]);
170
- const ti = claim(theirs, used.theirs, text, snapText);
171
- if (ti < 0) {
172
- kept[index] = true;
173
- return;
136
+ theirPlace(merged, index) {
137
+ const { theirs } = this;
138
+ for (let j = index - 1; j >= 0; j--) {
139
+ const prev = this.findMerged(merged, theirs[j]);
140
+ if (prev >= 0) return prev + 1;
141
+ }
142
+ for (let j = index + 1; j < theirs.length; j++) {
143
+ const next = this.findMerged(merged, theirs[j]);
144
+ if (next >= 0) return next;
145
+ }
146
+ return merged.length;
174
147
  }
175
- const done = ours[index].done === true || theirs[ti].done === true;
176
- ours[index] = withDone(ours[index], done);
177
- keepOurs(ours, kept, alias, index, text);
178
- };
179
148
 
180
- const mergeTodos = (store, base, theirs) => {
181
- const ours = [];
182
- for (const todo of store.todos) {
183
- if (!liveText(todo)) continue;
184
- ours.push(todo);
185
- }
186
- const used = { ours: flags(ours.length), theirs: flags(theirs.length) };
187
- const kept = flags(ours.length);
188
- const dropped = flags(ours.length);
189
- const theirKeep = flags(theirs.length);
190
- const alias = new Map();
191
- for (const item of base) {
192
- mergeBaseTodo(item, ours, theirs, used, kept, dropped, theirKeep, alias);
193
- }
194
- for (let i = 0; i < ours.length; i++) {
195
- if (used.ours[i]) continue;
196
- mergeFreshTodo(ours, theirs, used, kept, alias, i);
197
- }
198
- for (let i = 0; i < theirs.length; i++) {
199
- if (!used.theirs[i]) theirKeep[i] = true;
149
+ place(merged, at, index, item) {
150
+ merged.splice(at, 0, item);
151
+ this.alias.set(snapKey(this.theirs[index]), item);
152
+ this.theirKeep[index] = false;
200
153
  }
201
- const merged = [];
202
- const gaps = [];
203
- let cursor = 0;
204
- for (let i = 0; i < ours.length; i++) {
205
- if (kept[i]) {
206
- merged.push(ours[i]);
207
- cursor += 1;
208
- continue;
154
+
155
+ merge(base) {
156
+ const { ours, theirs } = this;
157
+ for (const item of base) this.mergeBase(item);
158
+ for (let i = 0; i < ours.length; i++) {
159
+ if (!this.usedOurs[i]) this.mergeFresh(i);
209
160
  }
210
- if (!dropped[i]) continue;
211
- gaps.push({ at: cursor, todo: ours[i] });
212
- cursor += 1;
161
+ for (let i = 0; i < theirs.length; i++) {
162
+ if (!this.usedTheirs[i]) this.theirKeep[i] = true;
163
+ }
164
+ const merged = [];
165
+ const gaps = [];
166
+ for (let i = 0; i < ours.length; i++) {
167
+ const at = merged.length + gaps.length;
168
+ if (this.kept[i]) merged.push(ours[i]);
169
+ else if (this.dropped[i]) gaps.push({ at, task: ours[i] });
170
+ }
171
+ for (let i = 0; i < theirs.length && gaps.length; i++) {
172
+ if (!this.theirKeep[i]) continue;
173
+ const gap = gaps.shift();
174
+ this.place(merged, gap.at, i, replaceTodo(gap.task, theirs[i]));
175
+ }
176
+ for (let i = 0; i < theirs.length; i++) {
177
+ if (!this.theirKeep[i]) continue;
178
+ const at = this.theirPlace(merged, i);
179
+ this.place(merged, at, i, adoptTodo(this.store, theirs[i]));
180
+ }
181
+ return merged;
213
182
  }
214
- fillGaps(merged, gaps, theirs, theirKeep, alias);
215
- store.todos = insertTheir(store, merged, theirs, theirKeep, alias);
216
- };
183
+ }
217
184
 
218
185
  const sameNote = (left, right) =>
219
186
  left.text === right.text && !!left.done === !!right.done;
@@ -244,10 +211,7 @@ const pickNote = (ours, base, theirs) => {
244
211
  };
245
212
 
246
213
  const mergeMap = (ours, base, theirs) => {
247
- const keys = new Set();
248
- for (const key of ours.keys()) keys.add(key);
249
- for (const key of base.keys()) keys.add(key);
250
- for (const key of theirs.keys()) keys.add(key);
214
+ const keys = new Set([...ours.keys(), ...base.keys(), ...theirs.keys()]);
251
215
  for (const key of keys) {
252
216
  const next = pickNote(ours.get(key), base.get(key), theirs.get(key));
253
217
  if (!next) ours.delete(key);
@@ -257,13 +221,11 @@ const mergeMap = (ours, base, theirs) => {
257
221
 
258
222
  const mergeReview = (store, disk) => {
259
223
  const base = store.baseline;
260
- const baseTodos = base ? base.todos : [];
261
224
  const baseStatus = base ? base.status : store.status;
262
- mergeTodos(store, baseTodos, snapList(disk.todos));
263
- const feedback = base ? base.feedback : new Map();
264
- const code = base ? base.code : new Map();
265
- mergeMap(store.feedback, feedback, disk.feedback);
266
- mergeMap(store.code, code, disk.code);
225
+ const theirs = snapList(disk.tasks);
226
+ store.tasks = new TodoMerge(store, theirs).merge(base?.tasks ?? []);
227
+ mergeMap(store.feedback, base?.feedback ?? new Map(), disk.feedback);
228
+ mergeMap(store.code, base?.code ?? new Map(), disk.code);
267
229
  if (store.status === baseStatus && disk.status) store.status = disk.status;
268
230
  store.baseline = snapshotSide(disk);
269
231
  };