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
@@ -2,102 +2,61 @@
2
2
 
3
3
  const ansi = require('../ansi.js');
4
4
  const diff = require('../diff/diff.js');
5
- const { displayLines } = diff;
6
5
  const highlight = require('../highlight.js');
7
6
  const detect = require('../detect.js');
8
- const { detectLang } = detect;
9
7
  const files = require('../files.js');
10
8
  const wrap = require('../wrap.js');
11
9
  const primitives = require('./primitives.js');
12
10
 
11
+ const { displayLines } = diff;
12
+ const { detectLang } = detect;
13
13
  const { itemPath } = files;
14
14
  const { tokenize, overlayTokens } = highlight;
15
15
  const { wrapPlain } = wrap;
16
- const { THEME, CODE_FG, codeFg, paint, visibleWidth } = ansi;
17
- const { truncateVisible, graphemes, graphemeWidth } = ansi;
18
- const { GUTTER_W, fill, splitWidths, paintSplitRule, paneResult } = primitives;
16
+ const { THEME, CODE_FG, codeFg, paint, visibleWidth, truncateVisible } = ansi;
17
+ const { GUTTER_W, fill, splitWidths, paintSplitRule } = primitives;
18
+ const { paneResult, sliceVisible } = primitives;
19
+
20
+ const lineStyle = (baseFg, baseBg, chBg = baseBg, mark = ' ') => ({
21
+ baseFg,
22
+ baseBg,
23
+ chBg,
24
+ mark,
25
+ });
19
26
 
20
27
  const STYLES = {
21
- del: {
22
- baseFg: THEME.delLineFg,
23
- baseBg: THEME.delLineBg,
24
- chBg: THEME.delCharBg,
25
- mark: '-',
26
- },
27
- add: {
28
- baseFg: THEME.addLineFg,
29
- baseBg: THEME.addLineBg,
30
- chBg: THEME.addCharBg,
31
- mark: '+',
32
- },
33
- warn: {
34
- baseFg: THEME.delLineFg,
35
- baseBg: THEME.delLineBg,
36
- chBg: THEME.delCharBg,
37
- mark: ' ',
38
- },
39
- note: {
40
- baseFg: THEME.chromeFg,
41
- baseBg: THEME.noteBg,
42
- chBg: THEME.noteBg,
43
- mark: ' ',
44
- },
45
- noteSep: {
46
- baseFg: THEME.mutedFg,
47
- baseBg: THEME.chromeBg,
48
- chBg: THEME.chromeBg,
49
- mark: ' ',
50
- },
51
- ctx: {
52
- baseFg: THEME.ctxFg,
53
- baseBg: THEME.ctxBg,
54
- chBg: THEME.ctxBg,
55
- mark: ' ',
56
- },
28
+ del: lineStyle(THEME.delLineFg, THEME.delLineBg, THEME.delCharBg, '-'),
29
+ add: lineStyle(THEME.addLineFg, THEME.addLineBg, THEME.addCharBg, '+'),
30
+ warn: lineStyle(THEME.delLineFg, THEME.delLineBg, THEME.delCharBg),
31
+ note: lineStyle(THEME.chromeFg, THEME.noteBg),
32
+ noteSep: lineStyle(THEME.mutedFg, THEME.chromeBg),
33
+ ctx: lineStyle(THEME.ctxFg, THEME.ctxBg),
57
34
  };
58
35
 
59
36
  const STAGED_STYLES = {
60
- del: {
61
- baseFg: THEME.stagedDelLineFg,
62
- baseBg: THEME.stagedDelLineBg,
63
- chBg: THEME.stagedDelCharBg,
64
- mark: '-',
65
- },
66
- add: {
67
- baseFg: THEME.stagedAddLineFg,
68
- baseBg: THEME.stagedAddLineBg,
69
- chBg: THEME.stagedAddCharBg,
70
- mark: '+',
71
- },
72
- warn: {
73
- baseFg: THEME.stagedDelLineFg,
74
- baseBg: THEME.stagedDelLineBg,
75
- chBg: THEME.stagedDelCharBg,
76
- mark: ' ',
77
- },
78
- note: STYLES.note,
79
- noteSep: STYLES.noteSep,
80
- ctx: STYLES.ctx,
37
+ ...STYLES,
38
+ del: lineStyle(
39
+ THEME.stagedDelLineFg,
40
+ THEME.stagedDelLineBg,
41
+ THEME.stagedDelCharBg,
42
+ '-',
43
+ ),
44
+ add: lineStyle(
45
+ THEME.stagedAddLineFg,
46
+ THEME.stagedAddLineBg,
47
+ THEME.stagedAddCharBg,
48
+ '+',
49
+ ),
50
+ warn: lineStyle(
51
+ THEME.stagedDelLineFg,
52
+ THEME.stagedDelLineBg,
53
+ THEME.stagedDelCharBg,
54
+ ),
81
55
  };
82
56
 
83
- const delCharBg = () => ansi.bg(THEME.delCharBg);
84
- const addCharBg = () => ansi.bg(THEME.addCharBg);
57
+ const gutterWidth = (width) => Math.min(GUTTER_W, Math.max(0, width));
85
58
 
86
- const skipText = (text, skip) => {
87
- if (skip <= 0) return text ?? '';
88
- const parts = graphemes(text ?? '');
89
- let used = 0;
90
- let i = 0;
91
- while (i < parts.length) {
92
- const w = graphemeWidth(parts[i], used);
93
- if (used + w > skip) break;
94
- used += w;
95
- i += 1;
96
- }
97
- let out = '';
98
- for (; i < parts.length; i++) out += parts[i];
99
- return out;
100
- };
59
+ const textWidth = (width) => Math.max(1, width - gutterWidth(width));
101
60
 
102
61
  const clipPieces = (pieces, skip) => {
103
62
  if (skip <= 0) return pieces;
@@ -110,54 +69,42 @@ const clipPieces = (pieces, skip) => {
110
69
  drop -= width;
111
70
  continue;
112
71
  }
113
- const shown = drop > 0 ? skipText(text, drop) : text;
72
+ const shown = drop > 0 ? sliceVisible(text, drop, Infinity) : text;
114
73
  drop = 0;
115
74
  if (shown) out.push({ ...piece, text: shown });
116
75
  }
117
76
  return out;
118
77
  };
119
78
 
120
- const paintSpans = (pieces, lineStyle, budget, color) => {
79
+ const paintSpans = (pieces, style, budget, color) => {
121
80
  let out = '';
122
81
  let used = 0;
123
82
  for (const piece of pieces) {
124
83
  if (used >= budget) break;
125
- const room = budget - used;
126
- const text = truncateVisible(piece.text, room);
84
+ const text = truncateVisible(piece.text, budget - used);
127
85
  const w = visibleWidth(text);
128
86
  if (w <= 0) continue;
129
- const fgRgb = codeFg(piece.style);
130
- const bgRgb = piece.changed ? lineStyle.chBg : lineStyle.baseBg;
131
- out += paint(text, fgRgb, bgRgb, color);
87
+ const bgRgb = piece.changed ? style.chBg : style.baseBg;
88
+ out += paint(text, codeFg(piece.style), bgRgb, color);
132
89
  used += w;
133
90
  }
134
- if (used < budget) {
135
- out += fill(budget - used, CODE_FG.plain, lineStyle.baseBg, color);
136
- }
137
- return out;
91
+ return out + fill(budget - used, CODE_FG.plain, style.baseBg, color);
138
92
  };
139
93
 
140
94
  const paintAuditNote = (line, width, color) => {
141
- const style = STYLES.note;
142
- const gutterW = Math.min(GUTTER_W, Math.max(0, width));
143
- const label = `${style.mark} `.slice(0, gutterW);
144
- const gutter = paint(label, style.baseFg, style.baseBg, color);
95
+ const { baseFg, baseBg, mark } = STYLES.note;
96
+ const gutterW = gutterWidth(width);
97
+ const label = `${mark} `.slice(0, gutterW);
145
98
  const budget = Math.max(0, width - gutterW);
146
99
  const text = truncateVisible(line.text ?? '', budget);
147
- const used = visibleWidth(text);
148
- let out = gutter;
149
- if (text) out += paint(text, style.baseFg, style.baseBg, color);
150
- if (used < budget) {
151
- out += fill(budget - used, style.baseFg, style.baseBg, color);
152
- }
153
- return out;
100
+ let out = paint(label, baseFg, baseBg, color);
101
+ out += paint(text, baseFg, baseBg, color);
102
+ return out + fill(budget - visibleWidth(text), baseFg, baseBg, color);
154
103
  };
155
104
 
156
105
  const paintAuditRule = (width, color) => {
157
- const style = STYLES.noteSep;
158
- const n = Math.max(0, width);
159
- const bar = '─'.repeat(n);
160
- return paint(bar, style.baseFg, style.baseBg, color);
106
+ const { baseFg, baseBg } = STYLES.noteSep;
107
+ return paint('─'.repeat(Math.max(0, width)), baseFg, baseBg, color);
161
108
  };
162
109
 
163
110
  const paintDiffLine = (line, width, color, origin, lang, scrollCol = 0) => {
@@ -168,32 +115,21 @@ const paintDiffLine = (line, width, color, origin, lang, scrollCol = 0) => {
168
115
  const diffSpans = line.spans ?? [{ text: line.text, changed: false }];
169
116
  const tokens = tokenize(lang, line.text ?? '');
170
117
  const pieces = clipPieces(overlayTokens(tokens, diffSpans), scrollCol);
171
- const gutterW = Math.min(GUTTER_W, Math.max(0, width));
118
+ const gutterW = gutterWidth(width);
172
119
  const label = `${line.mark ?? style.mark} `.slice(0, gutterW);
173
120
  const gutter = paint(label, CODE_FG.punct, style.baseBg, color);
174
121
  const budget = Math.max(0, width - gutterW);
175
- const rest = paintSpans(pieces, style, budget, color);
176
- return gutter + rest;
177
- };
178
-
179
- const paintSplitHalf = (line, width, color, origin, lang, scrollCol) => {
180
- if (!line || width <= 0) {
181
- return fill(width, THEME.ctxFg, THEME.ctxBg, color);
182
- }
183
- return paintDiffLine(line, width, color, origin, lang, scrollCol);
122
+ return gutter + paintSpans(pieces, style, budget, color);
184
123
  };
185
124
 
186
125
  const paintSplitRow = (row, width, color, origin, lang, scrollCol) => {
187
126
  const { leftW, rightW } = splitWidths(width);
188
- const left = paintSplitHalf(row.left, leftW, color, origin, lang, scrollCol);
189
- const right = paintSplitHalf(
190
- row.right,
191
- rightW,
192
- color,
193
- origin,
194
- lang,
195
- scrollCol,
196
- );
127
+ const half = (line, halfW) => {
128
+ if (!line) return fill(halfW, THEME.ctxFg, THEME.ctxBg, color);
129
+ return paintDiffLine(line, halfW, color, origin, lang, scrollCol);
130
+ };
131
+ const left = half(row.left, leftW);
132
+ const right = half(row.right, rightW);
197
133
  return `${left}${paintSplitRule(color)}${right}`;
198
134
  };
199
135
 
@@ -213,208 +149,137 @@ const sourceEmpty = (line) => {
213
149
  return !(line.text ?? '').trim();
214
150
  };
215
151
 
216
- const displayRowEmpty = (row, split) => {
152
+ const rowEmpty = (row, split) => {
217
153
  if (!split) return sourceEmpty(row);
218
154
  return sourceEmpty(row.left) && sourceEmpty(row.right);
219
155
  };
220
156
 
221
157
  const dropLeadingEmpty = (lines, split) => {
222
- let i = 0;
223
- while (i < lines.length && displayRowEmpty(lines[i], split)) {
224
- i += 1;
225
- }
226
- return i ? lines.slice(i) : lines;
158
+ const at = lines.findIndex((row) => !rowEmpty(row, split));
159
+ if (at < 0) return [];
160
+ return at ? lines.slice(at) : lines;
227
161
  };
228
162
 
229
163
  const cutSpans = (spans, count) => {
230
164
  const taken = [];
231
165
  const rest = [];
232
166
  let left = count;
233
- let i = 0;
234
- while (i < spans.length) {
235
- const span = spans[i];
167
+ for (const span of spans) {
236
168
  const text = span.text ?? '';
237
169
  if (left <= 0) {
238
170
  rest.push(span);
239
- i += 1;
240
- continue;
241
- }
242
- if (text.length <= left) {
171
+ } else if (text.length <= left) {
243
172
  taken.push(span);
244
173
  left -= text.length;
245
- i += 1;
246
- continue;
174
+ } else {
175
+ const changed = span.changed === true;
176
+ taken.push({ text: text.slice(0, left), changed });
177
+ rest.push({ text: text.slice(left), changed });
178
+ left = 0;
247
179
  }
248
- const changed = span.changed === true;
249
- taken.push({ text: text.slice(0, left), changed });
250
- rest.push({ text: text.slice(left), changed });
251
- left = 0;
252
- i += 1;
253
180
  }
254
181
  return { taken, rest };
255
182
  };
256
183
 
257
184
  const wrapSoftLine = (line, width) => {
258
- const gutterW = Math.min(GUTTER_W, Math.max(0, width));
259
- const budget = Math.max(1, width - gutterW);
260
- const rows = wrapPlain(line.text ?? '', budget);
185
+ const rows = wrapPlain(line.text ?? '', textWidth(width));
261
186
  const changed = line.wrap === true;
262
- const { length } = rows;
263
- const pieces = new Array(length);
264
187
  let used = 0;
265
188
  let spans = line.spans ?? [{ text: line.text ?? '', changed }];
266
- for (let i = 0; i < length; i++) {
267
- const text = rows[i];
268
- const last = i === length - 1;
189
+ return rows.map((text, index) => {
190
+ const last = index === rows.length - 1;
269
191
  const cut = cutSpans(spans, text.length);
270
192
  spans = cut.rest;
271
193
  const nextSpans = cut.taken.length ? cut.taken : [{ text, changed }];
272
194
  const next = { ...line, text, spans: nextSpans, editLast: last };
273
195
  if (line.editStart !== undefined) {
274
196
  next.editStart = line.editStart + used;
275
- if (last) next.editEnd = line.editEnd;
276
- else next.editEnd = next.editStart + text.length;
197
+ next.editEnd = last ? line.editEnd : next.editStart + text.length;
277
198
  }
278
199
  used += text.length;
279
- pieces[i] = next;
280
- }
281
- return pieces;
200
+ return next;
201
+ });
282
202
  };
283
203
 
284
204
  const expandSoftRows = (lines, width, split, wrapView) => {
285
205
  const { leftW, rightW } = splitWidths(width);
286
- const out = [];
287
206
  const partsOf = (line, lineW) => {
288
207
  if (!wrapView || !line || line.type === 'noteSep') return [line];
289
- const gutterW = Math.min(GUTTER_W, Math.max(0, lineW));
290
- const budget = Math.max(1, lineW - gutterW);
291
- if (visibleWidth(line.text ?? '') <= budget) return [line];
208
+ if (visibleWidth(line.text ?? '') <= textWidth(lineW)) return [line];
292
209
  return wrapSoftLine(line, lineW);
293
210
  };
211
+ if (!split) return lines.flatMap((line) => partsOf(line, width));
212
+ const out = [];
294
213
  for (const row of lines) {
295
- if (!split) {
296
- for (const part of partsOf(row, width)) out.push(part);
297
- continue;
298
- }
299
214
  const leftParts = partsOf(row.left, leftW);
300
215
  const rightParts = partsOf(row.right, rightW);
301
216
  const n = Math.max(leftParts.length, rightParts.length);
302
217
  for (let i = 0; i < n; i++) {
303
- out.push({
304
- left: leftParts[i] ?? null,
305
- right: rightParts[i] ?? null,
306
- });
218
+ out.push({ left: leftParts[i] ?? null, right: rightParts[i] ?? null });
307
219
  }
308
220
  }
309
221
  return out;
310
222
  };
311
223
 
312
- const onCodePiece = (line, cursor) => {
313
- if (!line || line.editStart === undefined) return false;
314
- if (cursor < line.editStart) return false;
315
- return cursor <= line.editEnd;
316
- };
317
-
318
- const codeCursorInRows = (rows, split, width, cursor, scrollCol = 0) => {
319
- if (cursor === undefined || cursor === null) return null;
320
- const { leftW, rightW } = splitWidths(width);
321
- for (let i = 0; i < rows.length; i++) {
322
- const line = split ? rows[i].right : rows[i];
323
- if (!onCodePiece(line, cursor)) continue;
324
- const lineW = split ? rightW : width;
325
- const gutterW = Math.min(GUTTER_W, Math.max(0, lineW));
326
- const take = Math.min(cursor - line.editStart, line.text.length);
327
- const col = visibleWidth(line.text.slice(0, take));
328
- const shown = Math.max(0, col - scrollCol);
329
- const x0 = split ? leftW + 1 : 0;
330
- return { x: x0 + gutterW + shown + 1, row: i };
331
- }
332
- return null;
333
- };
334
-
335
- const codeEditHits = (rows, split, width, scrollCol = 0) => {
224
+ const codeHits = (rows, split, width, overlay, editing, scrollCol) => {
336
225
  const { leftW, rightW } = splitWidths(width);
337
- const hits = [];
338
- for (let i = 0; i < rows.length; i++) {
339
- const line = split ? rows[i].right : rows[i];
226
+ const lineW = split ? rightW : width;
227
+ const x0 = split ? leftW + 1 : 0;
228
+ const textX = x0 + gutterWidth(lineW) + 1;
229
+ const at = overlay ? overlay.cursor : null;
230
+ const hasCursor = at !== null && at !== undefined;
231
+ const editHits = [];
232
+ let cursor = null;
233
+ for (let row = 0; row < rows.length; row++) {
234
+ const line = split ? rows[row].right : rows[row];
340
235
  if (!line || line.editStart === undefined) continue;
341
- const lineW = split ? rightW : width;
342
- const gutterW = Math.min(GUTTER_W, Math.max(0, lineW));
343
- const pane = split ? leftW + 1 : 0;
344
- const textX = pane + gutterW + 1;
345
- const end = split ? pane + rightW : width;
346
- hits.push({
347
- row: i,
348
- x0: pane + 1,
349
- textX,
350
- x1: end + 1,
351
- scroll: scrollCol,
352
- start: line.editStart,
353
- text: line.text ?? '',
354
- limit: line.editEnd,
355
- live: true,
356
- });
236
+ if (editing) {
237
+ editHits.push({
238
+ row,
239
+ x0: x0 + 1,
240
+ textX,
241
+ x1: x0 + lineW + 1,
242
+ scroll: scrollCol,
243
+ start: line.editStart,
244
+ text: line.text ?? '',
245
+ limit: line.editEnd,
246
+ live: true,
247
+ });
248
+ }
249
+ if (cursor || !hasCursor) continue;
250
+ const onPiece = at >= line.editStart && at <= line.editEnd;
251
+ if (!onPiece) continue;
252
+ const take = Math.min(at - line.editStart, line.text.length);
253
+ const col = visibleWidth(line.text.slice(0, take));
254
+ cursor = { x: textX + Math.max(0, col - scrollCol), row };
357
255
  }
358
- return hits;
256
+ return { cursor, editHits };
359
257
  };
360
258
 
361
- const codeInnerWidth = (width, layout = 'unified') => {
362
- const lineW = layout === 'side' ? splitWidths(width).rightW : width;
363
- const gutterW = Math.min(GUTTER_W, Math.max(0, lineW));
364
- return Math.max(1, lineW - gutterW);
365
- };
259
+ const codeInnerWidth = (width, layout = 'unified') =>
260
+ textWidth(layout === 'side' ? splitWidths(width).rightW : width);
366
261
 
367
262
  const paintBodyDiff = (view, width, color) => {
368
- const item = view.item;
263
+ const { item, codeOverlay: overlay } = view;
369
264
  const layout = view.layout ?? 'unified';
370
- const overlay = view.codeOverlay;
371
265
  const lang = detectLang(itemPath(item));
372
266
  const splitBody = layout === 'side' && !item.file.isBinary;
373
- const editing = Boolean(overlay && typeof overlay.cursor === 'number');
374
- const picked = editing ? overlay.scrollCol : 0;
375
- const scrollCol = picked ?? 0;
267
+ const editing = typeof overlay?.cursor === 'number';
268
+ const scrollCol = (editing ? overlay.scrollCol : 0) ?? 0;
376
269
  const raw = dropLeadingEmpty(bodyLines(item, layout, overlay), splitBody);
377
270
  const lines = expandSoftRows(raw, width, splitBody, !editing);
378
- const { length } = lines;
379
- const body = new Array(length);
380
- if (splitBody) {
381
- for (let i = 0; i < length; i++) {
382
- body[i] = paintSplitRow(
383
- lines[i],
384
- width,
385
- color,
386
- item.origin,
387
- lang,
388
- scrollCol,
389
- );
390
- }
391
- } else {
392
- for (let i = 0; i < length; i++) {
393
- body[i] = paintDiffLine(
394
- lines[i],
395
- width,
396
- color,
397
- item.origin,
398
- lang,
399
- scrollCol,
400
- );
401
- }
402
- }
403
- const edit = overlay ? overlay.cursor : null;
404
- const cursor = codeCursorInRows(lines, splitBody, width, edit, scrollCol);
405
- const editHits = editing
406
- ? codeEditHits(lines, splitBody, width, scrollCol)
407
- : [];
408
- return paneResult({ body, cursor, splitBody, editHits });
271
+ const paintRow = splitBody ? paintSplitRow : paintDiffLine;
272
+ const body = lines.map((line) =>
273
+ paintRow(line, width, color, item.origin, lang, scrollCol),
274
+ );
275
+ const hits = codeHits(lines, splitBody, width, overlay, editing, scrollCol);
276
+ return paneResult({ body, splitBody, ...hits });
409
277
  };
410
278
 
411
279
  module.exports = {
412
- delCharBg,
413
- addCharBg,
414
280
  paintDiffLine,
415
281
  codeInnerWidth,
416
282
  paintBodyDiff,
417
- codeCursorInRows,
418
- codeEditHits,
419
283
  expandSoftRows,
284
+ codeHits,
420
285
  };