reslop 0.2.3 → 0.2.5

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 (89) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/README.md +8 -4
  3. package/bin/reslop.js +4 -2
  4. package/lib/api.js +2 -1
  5. package/lib/capabilities.js +0 -4
  6. package/lib/cli.js +19 -10
  7. package/lib/clipboard.js +45 -4
  8. package/lib/deps-diff.js +61 -118
  9. package/lib/deps.js +166 -235
  10. package/lib/detect.js +4 -2
  11. package/lib/diff/align.js +2 -1
  12. package/lib/diff/diff.js +6 -3
  13. package/lib/diff/display.js +2 -1
  14. package/lib/diff/inline.js +68 -2
  15. package/lib/diff/patch.js +2 -1
  16. package/lib/diff/unit.js +15 -30
  17. package/lib/editor.js +91 -13
  18. package/lib/files.js +54 -27
  19. package/lib/git-branches.js +107 -154
  20. package/lib/git-deps.js +78 -155
  21. package/lib/git-worktree.js +508 -0
  22. package/lib/git.js +23 -580
  23. package/lib/github.js +9 -8
  24. package/lib/gitlab.js +5 -4
  25. package/lib/highlight/bash.js +2 -1
  26. package/lib/highlight/core.js +11 -0
  27. package/lib/highlight/css.js +2 -1
  28. package/lib/highlight/csv.js +2 -1
  29. package/lib/highlight/dot.js +3 -12
  30. package/lib/highlight/html.js +2 -1
  31. package/lib/highlight/json.js +2 -1
  32. package/lib/highlight/log.js +5 -11
  33. package/lib/highlight/txt.js +3 -12
  34. package/lib/highlight.js +2 -1
  35. package/lib/keys.js +22 -12
  36. package/lib/manifest.js +4 -6
  37. package/lib/npm-commands.js +82 -24
  38. package/lib/remote.js +21 -20
  39. package/lib/render/branches.js +9 -27
  40. package/lib/render/chrome.js +109 -35
  41. package/lib/render/commits.js +216 -216
  42. package/lib/render/diff.js +160 -47
  43. package/lib/render/files.js +9 -26
  44. package/lib/render/frame.js +97 -118
  45. package/lib/render/notes.js +74 -26
  46. package/lib/render/npm.js +104 -30
  47. package/lib/render/present.js +2 -1
  48. package/lib/render/primitives.js +128 -52
  49. package/lib/render/render.js +2 -1
  50. package/lib/render/unit.js +17 -11
  51. package/lib/report-model.js +6 -4
  52. package/lib/report-parse.js +8 -14
  53. package/lib/report-render.js +38 -21
  54. package/lib/report-run.js +12 -11
  55. package/lib/report-test.js +45 -51
  56. package/lib/report-tools.js +44 -25
  57. package/lib/review-merge.js +102 -131
  58. package/lib/review.js +69 -78
  59. package/lib/select.js +52 -0
  60. package/lib/session/actions.js +72 -87
  61. package/lib/session/branches.js +18 -52
  62. package/lib/session/change-actions.js +175 -147
  63. package/lib/session/commit.js +65 -61
  64. package/lib/session/compose.js +152 -83
  65. package/lib/session/dispatch.js +53 -46
  66. package/lib/session/edit-click.js +57 -0
  67. package/lib/session/files-pane.js +30 -51
  68. package/lib/session/items.js +73 -90
  69. package/lib/session/lifecycle.js +37 -98
  70. package/lib/session/load.js +52 -57
  71. package/lib/session/navigation.js +105 -95
  72. package/lib/session/npm.js +205 -71
  73. package/lib/session/ops.js +200 -45
  74. package/lib/session/pointer.js +33 -8
  75. package/lib/session/progress.js +9 -6
  76. package/lib/session/review.js +35 -53
  77. package/lib/session/tasks.js +292 -0
  78. package/lib/session/terminal.js +17 -19
  79. package/lib/session/unit.js +3 -4
  80. package/lib/session/update.js +76 -96
  81. package/lib/session/view.js +45 -16
  82. package/lib/session/watch.js +47 -27
  83. package/lib/session.js +66 -97
  84. package/lib/source.js +6 -3
  85. package/lib/update.js +5 -13
  86. package/lib/utilities.js +25 -3
  87. package/lib/wrap.js +18 -1
  88. package/package.json +1 -1
  89. package/lib/session/todos.js +0 -293
@@ -1,39 +1,101 @@
1
1
  'use strict';
2
2
 
3
3
  const ansi = require('../ansi.js');
4
+ const files = require('../files.js');
4
5
  const primitives = require('./primitives.js');
5
- const { wrapMultiline, cursorInWrap } = require('../wrap.js');
6
+ const wrap = require('../wrap.js');
7
+ const { shortAge } = files;
8
+ const { wrapMultiline, wrapDoc, cursorInWrap } = wrap;
6
9
  const { measureColumns, padColumns, joinColumns, paintColumns } = primitives;
10
+ const { padVisible } = primitives;
7
11
 
8
12
  const { THEME, paint, visibleWidth, truncateVisible, seq, EL } = ansi;
9
- const { FILE_MARK, paneResult, paintCursorList } = primitives;
10
- const { paintBodyFill, listWindowStart } = primitives;
13
+ const { FILE_MARK, paintCursorList, fieldWindow } = primitives;
14
+ const { paintBodyFill, listLine, paintListWindow } = primitives;
11
15
 
12
16
  const COMMIT_COL_ALIGN = {
13
17
  sha: 'end',
14
18
  refs: 'end',
19
+ add: 'start',
20
+ del: 'start',
15
21
  date: 'start',
16
22
  };
17
23
 
18
24
  const COMMIT_COL_FG = {
19
25
  sha: THEME.shaFg,
20
26
  refs: THEME.warnFg,
27
+ add: THEME.addLineFg,
28
+ del: THEME.delLineFg,
21
29
  date: THEME.mutedFg,
22
30
  };
23
31
 
24
32
  const COMMIT_CURRENT_COL_FG = {
25
33
  sha: THEME.shaDarkFg,
34
+ refs: THEME.shaDarkFg,
26
35
  date: THEME.headerFg,
27
36
  };
28
37
 
29
38
  const REFS_MAX = 28;
30
- const LIST_PAD = 1;
31
39
  const COMMIT_TAIL = 1;
32
- const commitRowFields = (entry) => ({
33
- sha: entry.shortSha ?? '',
34
- refs: truncateVisible(entry.refs ?? '', REFS_MAX),
35
- date: entry.date ?? '',
36
- });
40
+ const lineCounts = (entry) => {
41
+ const added = entry.added ?? 0;
42
+ const removed = entry.removed ?? 0;
43
+ if (!added && !removed) return null;
44
+ return { added, removed };
45
+ };
46
+
47
+ const countLabel = (entry) => {
48
+ if (entry && entry.pending) {
49
+ const stagedAdd = entry.stagedAdded ?? 0;
50
+ const unstagedAdd = entry.unstagedAdded ?? 0;
51
+ const stagedDel = entry.stagedRemoved ?? 0;
52
+ const unstagedDel = entry.unstagedRemoved ?? 0;
53
+ const any = stagedAdd || unstagedAdd || stagedDel || unstagedDel;
54
+ if (!any) return null;
55
+ return {
56
+ add: `+${stagedAdd}/${unstagedAdd}`,
57
+ del: `-${stagedDel}/${unstagedDel}`,
58
+ };
59
+ }
60
+ const counts = lineCounts(entry);
61
+ if (!counts) return null;
62
+ return { add: `+${counts.added}`, del: `-${counts.removed}` };
63
+ };
64
+
65
+ const DIFF_LABEL = 'Diffs:';
66
+ const DIFF_GAP = ' ';
67
+
68
+ const entryCountWidth = (entry) => {
69
+ const label = countLabel(entry);
70
+ if (!label) return { add: 0, del: 0 };
71
+ return {
72
+ add: visibleWidth(label.add),
73
+ del: visibleWidth(label.del),
74
+ };
75
+ };
76
+
77
+ const listCountWidth = (commits) => {
78
+ let add = 0;
79
+ let del = 0;
80
+ for (const entry of commits) {
81
+ const width = entryCountWidth(entry);
82
+ add = Math.max(add, width.add);
83
+ del = Math.max(del, width.del);
84
+ }
85
+ return { add, del };
86
+ };
87
+
88
+ const commitRowFields = (entry) => {
89
+ const refs = `${entry.refs ?? ''}`.trim();
90
+ const label = countLabel(entry);
91
+ return {
92
+ sha: entry.shortSha ?? '',
93
+ refs: refs ? truncateVisible(refs, REFS_MAX) : '',
94
+ add: label ? label.add : '',
95
+ del: label ? label.del : '',
96
+ date: shortAge(entry.date ?? ''),
97
+ };
98
+ };
37
99
 
38
100
  const contentWidth = (width) => Math.max(1, width - COMMIT_TAIL);
39
101
 
@@ -116,46 +178,38 @@ const paintCommitRow = (entry, width, color, selected, cols, current) => {
116
178
  return out;
117
179
  };
118
180
 
119
- const paintCommitEdit = (compose, width, color, entry, cols) => {
181
+ const lineEdit = (text, textX, span, scroll) => ({
182
+ x0: 1,
183
+ textX,
184
+ x1: textX + span,
185
+ start: 0,
186
+ text,
187
+ limit: text.length,
188
+ scroll,
189
+ live: true,
190
+ });
191
+
192
+ const subjectWindow = (compose, rest) => {
193
+ const line = splitMessage(compose.text).line;
194
+ const at = Math.min(compose.cursor ?? 0, line.length);
195
+ return fieldWindow(line, at, compose.scrollCol, rest);
196
+ };
197
+
198
+ const paintCommitEdit = (compose, width, color, entry = null, cols = {}) => {
120
199
  const text = splitMessage(compose.text).line;
121
- if (entry && cols) {
122
- const shown = { ...entry, body: text, subject: text };
123
- const row = paintCommitRow(shown, width, color, true, cols);
124
- const inner = contentWidth(width);
125
- const prefix = ` ${FILE_MARK} `;
126
- const parts = padColumns(commitRowFields(entry), cols, COMMIT_COL_ALIGN);
127
- const suffix = joinColumns(parts, cols);
128
- const rest = Math.max(1, inner - visibleWidth(prefix + suffix));
129
- const clipped = truncateVisible(text, rest);
130
- const prefixW = visibleWidth(prefix);
131
- const col = Math.min(compose.cursor ?? 0, visibleWidth(clipped));
132
- return {
133
- row,
134
- cursor: { x: prefixW + col + 1 },
135
- at: 'replace',
136
- };
137
- }
138
- const inner = contentWidth(width);
139
200
  const prefix = ` ${FILE_MARK} `;
140
201
  const prefixW = visibleWidth(prefix);
141
- const rest = Math.max(1, inner - prefixW);
142
- const clipped = truncateVisible(text, rest);
143
- const pad = Math.max(0, rest - visibleWidth(clipped));
144
- const gap = ' '.repeat(pad);
145
- const tail = ' '.repeat(COMMIT_TAIL);
146
- const fgRgb = THEME.chromeFg;
147
- const bgRgb = THEME.buttonBg;
148
- const nameFg = THEME.buttonHotFg;
149
- let row = `${prefix}${clipped}${gap}${tail}`;
150
- if (color) {
151
- row = `${seq(fgRgb, bgRgb)}${EL}`;
152
- row += paint(prefix, fgRgb, bgRgb, color);
153
- row += paint(clipped, nameFg, bgRgb, color);
154
- row += paint(gap, fgRgb, bgRgb, color);
155
- row += paint(tail, fgRgb, bgRgb, color);
156
- }
157
- const col = Math.min(compose.cursor ?? 0, visibleWidth(clipped));
158
- return { row, cursor: { x: prefixW + col + 1 }, at: 'start' };
202
+ const fields = commitRowFields(entry ?? {});
203
+ const suffix = joinColumns(padColumns(fields, cols, COMMIT_COL_ALIGN), cols);
204
+ const rest = Math.max(1, contentWidth(width) - visibleWidth(prefix + suffix));
205
+ const win = subjectWindow(compose, rest);
206
+ const shown = { ...entry, body: win.text, subject: win.text };
207
+ return {
208
+ row: paintCommitRow(shown, width, color, true, cols),
209
+ cursor: { x: prefixW + win.col + 1, scroll: win.scroll },
210
+ at: entry ? 'replace' : 'start',
211
+ edit: lineEdit(text, prefixW + 1, rest, win.scroll),
212
+ };
159
213
  };
160
214
 
161
215
  const pendingAt = (commits) => {
@@ -268,19 +322,45 @@ const partsWidth = (parts) => {
268
322
 
269
323
  const timeNeed = (entry) => {
270
324
  const when = `${entry.when ?? ''}`.trim();
271
- const ago = `${entry.date ?? ''}`.trim();
325
+ const ago = shortAge(entry.date ?? '');
272
326
  if (when && ago) return visibleWidth(when) + COL_GAP + visibleWidth(ago);
273
327
  return visibleWidth(when || ago);
274
328
  };
275
329
 
276
330
  const refsText = (entry) => `${entry.refs ?? ''}`.trim();
277
331
 
278
- const rightNeed = (entry) =>
279
- Math.max(
332
+ const diffLine = (entry, widths) => {
333
+ const label = countLabel(entry);
334
+ if (!label) return null;
335
+ const add = padVisible(label.add, widths.add, 'start');
336
+ const del = padVisible(label.del, widths.del, 'start');
337
+ const text = `${DIFF_LABEL}${DIFF_GAP}${add}${DIFF_GAP}${del}`;
338
+ return { add, del, text };
339
+ };
340
+
341
+ const diffCountParts = (entry, widths, rightW) => {
342
+ const line = diffLine(entry, widths);
343
+ if (!line || !rightW) return [];
344
+ const pad = Math.max(0, rightW - visibleWidth(line.text));
345
+ return [
346
+ { text: ' '.repeat(pad), kind: 'meta' },
347
+ { text: DIFF_LABEL, kind: 'meta' },
348
+ { text: DIFF_GAP, kind: 'meta' },
349
+ { text: line.add, kind: 'add' },
350
+ { text: DIFF_GAP, kind: 'meta' },
351
+ { text: line.del, kind: 'del' },
352
+ ];
353
+ };
354
+
355
+ const rightNeed = (entry, widths = entryCountWidth(entry)) => {
356
+ const line = diffLine(entry, widths);
357
+ return Math.max(
280
358
  partsWidth(authorParts(entry)),
281
359
  timeNeed(entry),
282
360
  visibleWidth(refsText(entry)),
361
+ line ? visibleWidth(line.text) : 0,
283
362
  );
363
+ };
284
364
 
285
365
  const spreadTime = (when, ago, width) => {
286
366
  const agoW = visibleWidth(ago);
@@ -309,7 +389,7 @@ const alignEnd = (text, width, kind) => {
309
389
 
310
390
  const timeParts = (entry, width) => {
311
391
  const when = `${entry.when ?? ''}`.trim();
312
- const ago = `${entry.date ?? ''}`.trim();
392
+ const ago = shortAge(entry.date ?? '');
313
393
  if (!width) return [];
314
394
  if (when && ago) return spreadTime(when, ago, width);
315
395
  if (ago) return alignEnd(ago, width, 'meta');
@@ -317,10 +397,16 @@ const timeParts = (entry, width) => {
317
397
  return [];
318
398
  };
319
399
 
320
- const rightRows = (entry, rightW) => {
321
- const rows = [authorParts(entry), timeParts(entry, rightW)];
400
+ const rightRows = (entry, rightW, widths) => {
401
+ const rows = [];
402
+ const author = authorParts(entry);
403
+ if (author.length) rows.push(author);
404
+ const time = timeParts(entry, rightW);
405
+ if (time.length) rows.push(time);
322
406
  const refs = refsText(entry);
323
407
  if (refs) rows.push([{ text: refs, kind: 'refs' }]);
408
+ const diff = diffCountParts(entry, widths, rightW);
409
+ if (diff.length) rows.push(diff);
324
410
  return rows;
325
411
  };
326
412
 
@@ -342,7 +428,8 @@ const panelLeft = (entry, leftW, edit) => {
342
428
  const parts = edit
343
429
  ? messagePartsFrom(edit.text ?? '', leftW)
344
430
  : messageParts(entry, leftW);
345
- return [{ text: entry.sha ?? '', kind: 'hash' }, ...parts];
431
+ if (!entry.sha) return parts;
432
+ return [{ text: entry.sha, kind: 'hash' }, ...parts];
346
433
  };
347
434
 
348
435
  const commitMessageWidth = (entry, screenWidth) => {
@@ -368,9 +455,11 @@ const messageCaret = (text, cursor, width, row, first, selected) => {
368
455
  };
369
456
 
370
457
  const pieceFg = (kind, tone) => {
458
+ if (kind === 'add') return THEME.addLineFg;
459
+ if (kind === 'del') return THEME.delLineFg;
371
460
  if (tone.current) {
372
461
  if (kind === 'hash') return THEME.shaDarkFg;
373
- if (kind === 'refs') return THEME.warnFg;
462
+ if (kind === 'refs') return THEME.shaDarkFg;
374
463
  if (kind === 'text' || kind === 'body') return THEME.mutedFg;
375
464
  return tone.fgRgb;
376
465
  }
@@ -424,20 +513,32 @@ const paintPanelLine = (spec) => {
424
513
  );
425
514
  };
426
515
 
427
- const lineRecord = (commit, row, hit, cursor = null) => ({
428
- commit,
429
- row,
430
- hit,
431
- cursor,
432
- });
516
+ const editFromDoc = (doc, row, textX, span) => {
517
+ if (row < 0 || row >= doc.length) return null;
518
+ const piece = doc[row];
519
+ return {
520
+ x0: 1,
521
+ textX,
522
+ x1: textX + span,
523
+ start: piece.start,
524
+ text: piece.text,
525
+ limit: piece.start + piece.text.length,
526
+ live: true,
527
+ };
528
+ };
529
+
530
+ const editLines = (editHit) => (editHit ? [editHit] : undefined);
433
531
 
434
- const commitLines = (entry, index, width, color, selected, edit, current) => {
532
+ const commitLines = (entry, index, spec) => {
533
+ const { width, color, selected, edit, current, diffWidths } = spec;
435
534
  const inner = contentWidth(width);
436
535
  const hashW = visibleWidth(entry.sha ?? '');
437
- const cols = panelWidths(rightNeed(entry), hashW, inner);
438
- const rights = rightRows(entry, cols.rightW);
536
+ const widths = diffWidths ?? entryCountWidth(entry);
537
+ const cols = panelWidths(rightNeed(entry, widths), hashW, inner);
538
+ const rights = rightRows(entry, cols.rightW, widths);
439
539
  const left = panelLeft(entry, cols.leftW, edit);
440
540
  const count = Math.max(left.length, rights.length);
541
+ const doc = edit ? wrapDoc(`${edit.text ?? ''}`, cols.leftW) : null;
441
542
  const lines = [];
442
543
  for (let row = 0; row < count; row++) {
443
544
  const line = left[row] ?? { text: '', kind: 'text' };
@@ -455,17 +556,23 @@ const commitLines = (entry, index, width, color, selected, edit, current) => {
455
556
  leftKind: line.kind,
456
557
  rightKind: 'meta',
457
558
  });
559
+ const messageRow = entry.sha ? row - 1 : row;
560
+ const first = !entry.sha && row === 0;
458
561
  const caret = edit
459
562
  ? messageCaret(
460
563
  edit.text,
461
564
  edit.cursor,
462
565
  cols.leftW,
463
- row - 1,
464
- false,
566
+ messageRow,
567
+ first,
465
568
  selected,
466
569
  )
467
570
  : null;
468
- lines.push(lineRecord(index, painted, true, caret));
571
+ const textX = prefixWidth(first, selected) + 1;
572
+ const editHit = doc
573
+ ? editFromDoc(doc, messageRow, textX, cols.leftW)
574
+ : null;
575
+ lines.push(listLine(painted, index, caret, editLines(editHit)));
469
576
  }
470
577
  return lines;
471
578
  };
@@ -474,6 +581,7 @@ const draftLines = (text, cursor, width, color) => {
474
581
  const inner = contentWidth(width);
475
582
  const leftW = Math.max(1, inner - visibleWidth(FULL_INDENT));
476
583
  const parts = messagePartsFrom(text, leftW);
584
+ const doc = wrapDoc(`${text ?? ''}`, leftW);
477
585
  const lines = [];
478
586
  for (let row = 0; row < parts.length; row++) {
479
587
  const line = parts[row];
@@ -491,7 +599,9 @@ const draftLines = (text, cursor, width, color) => {
491
599
  rightKind: 'meta',
492
600
  });
493
601
  const caret = messageCaret(text, cursor, leftW, row, row === 0, true);
494
- lines.push(lineRecord(-1, painted, false, caret));
602
+ const textX = prefixWidth(row === 0, true) + 1;
603
+ const editHit = editFromDoc(doc, row, textX, leftW);
604
+ lines.push(listLine(painted, -1, caret, editLines(editHit)));
495
605
  }
496
606
  return lines;
497
607
  };
@@ -511,181 +621,71 @@ const composeShowsDraft = (compose, commits) => {
511
621
  return true;
512
622
  };
513
623
 
514
- const gapLine = (width, color) =>
515
- lineRecord(-1, paintBodyFill(width, color, 'files'), false);
516
-
517
- const flattenCommits = (commits, cursor, width, color, compose, rev, short) => {
518
- const lines = [];
624
+ const flattenCommits = (view, commits, width, color) => {
625
+ const cursor = view.commitCursor ?? 0;
626
+ const compose = view.compose ?? null;
519
627
  const editing = compose && compose.kind === 'commit';
520
- const pushGap = () => {
521
- if (lines.length) lines.push(gapLine(width, color));
522
- };
628
+ const diffWidths = listCountWidth(commits);
629
+ const gap = listLine(paintBodyFill(width, color, 'files'), -1);
630
+ const lines = [];
523
631
  if (composeShowsDraft(compose, commits)) {
524
- const draft = draftLines(
525
- compose.text ?? '',
526
- compose.cursor ?? 0,
527
- width,
528
- color,
529
- );
530
- for (const line of draft) lines.push(line);
632
+ const text = compose.text ?? '';
633
+ lines.push(...draftLines(text, compose.cursor ?? 0, width, color));
531
634
  }
532
635
  for (let index = 0; index < commits.length; index++) {
533
- pushGap();
636
+ if (lines.length) lines.push(gap);
637
+ const entry = commits[index];
534
638
  const inplace = composeEditsIndex(compose, commits, index, cursor);
535
639
  const selected = inplace || (!editing && index === cursor);
536
- const edit = inplace
537
- ? { text: compose.text ?? '', cursor: compose.cursor ?? 0 }
538
- : null;
539
- const block = commitLines(
540
- commits[index],
541
- index,
640
+ const text = compose?.text ?? '';
641
+ const caret = compose?.cursor ?? 0;
642
+ const edit = inplace ? { text, cursor: caret } : null;
643
+ const current = viewedCommit(entry, view.rev, view.revShort);
644
+ const block = commitLines(entry, index, {
542
645
  width,
543
646
  color,
544
647
  selected,
545
648
  edit,
546
- viewedCommit(commits[index], rev, short),
547
- );
548
- for (const line of block) lines.push(line);
649
+ current,
650
+ diffWidths,
651
+ });
652
+ lines.push(...block);
549
653
  }
550
654
  return lines;
551
655
  };
552
656
 
553
657
  const focusLine = (lines, cursor, compose) => {
554
658
  if (compose && compose.kind === 'commit') {
555
- for (let i = 0; i < lines.length; i++) {
556
- if (lines[i].cursor) return i;
557
- }
659
+ const at = lines.findIndex((line) => line.cursor);
660
+ if (at >= 0) return at;
558
661
  }
559
- for (let i = 0; i < lines.length; i++) {
560
- const line = lines[i];
561
- if (line.hit && line.commit === cursor) return i;
562
- }
563
- return 0;
564
- };
565
-
566
- const paintLineWindow = (
567
- lines,
568
- focus,
569
- width,
570
- color,
571
- bodyH,
572
- headerLines,
573
- offset,
574
- ) => {
575
- const pad = bodyH >= LIST_PAD * 2 + 1 ? LIST_PAD : 0;
576
- const listH = bodyH - pad * 2;
577
- const start = listWindowStart(focus, offset, listH, lines.length);
578
- const blank = paintBodyFill(width, color, 'files');
579
- const body = [];
580
- const fileHits = [];
581
- let textCursor = null;
582
- if (pad) body.push(blank);
583
- for (let i = 0; i < listH; i++) {
584
- const line = lines[start + i];
585
- if (!line) break;
586
- body.push(line.row);
587
- if (line.cursor) {
588
- textCursor = { x: line.cursor.x, row: body.length - 1 };
589
- }
590
- if (!line.hit) continue;
591
- const y = headerLines + pad + i + 1;
592
- fileHits.push({ y, cursor: line.commit });
593
- }
594
- if (pad) body.push(blank);
595
- return { body, fileHits, cursor: textCursor, offset: start };
662
+ const at = lines.findIndex((line) => line.hit && line.index === cursor);
663
+ return Math.max(0, at);
596
664
  };
597
665
 
598
- const paintFullCommits = (view, width, color, bodyH, headerLines) => {
666
+ const paintBodyCommits = (view, width, color, bodyH, headerLines) => {
667
+ const pane = { width, color, bodyH, headerLines, offset: view.listScroll };
599
668
  const commits = view.commits ?? [];
600
669
  const cursor = view.commitCursor ?? 0;
601
- const compose = view.compose ?? null;
602
- const lines = flattenCommits(
603
- commits,
604
- cursor,
605
- width,
606
- color,
607
- compose,
608
- view.rev,
609
- view.revShort,
610
- );
611
- const focus = focusLine(lines, cursor, compose);
612
- return paintLineWindow(
613
- lines,
614
- focus,
615
- width,
616
- color,
617
- bodyH,
618
- headerLines,
619
- view.listScroll,
620
- );
621
- };
622
-
623
- const paintBriefCommits = (
624
- commits,
625
- cursor,
626
- width,
627
- color,
628
- bodyH,
629
- headerLines,
630
- extra,
631
- offset,
632
- cols,
633
- rev,
634
- revShort,
635
- ) => {
636
- const paintRow = (entry, rowWidth, rowColor, selected) =>
637
- paintCommitRow(
638
- entry,
639
- rowWidth,
640
- rowColor,
641
- selected,
642
- cols,
643
- viewedCommit(entry, rev, revShort),
644
- );
645
- return paintCursorList(
670
+ if (view.commitView === 'full') {
671
+ const lines = flattenCommits(view, commits, width, color);
672
+ const focus = focusLine(lines, cursor, view.compose);
673
+ return paintListWindow(lines.length, focus, pane, (i) => lines[i]);
674
+ }
675
+ const cols = measureColumns(commits, commitRowFields, COMMIT_COL_ALIGN);
676
+ const extra = commitEditRow(
677
+ view.compose,
646
678
  commits,
647
679
  cursor,
648
680
  width,
649
681
  color,
650
- bodyH,
651
- headerLines,
652
- paintRow,
653
- extra,
654
- offset,
682
+ cols,
655
683
  );
656
- };
657
-
658
- const paintBodyCommits = (view, width, color, bodyH, headerLines) => {
659
- const commits = view.commits ?? [];
660
- const cols = measureColumns(commits, commitRowFields, COMMIT_COL_ALIGN);
661
- const cursor = view.commitCursor ?? 0;
662
- const full = view.commitView === 'full';
663
- const extra = full
664
- ? null
665
- : commitEditRow(view.compose, commits, cursor, width, color, cols);
666
- const painted = full
667
- ? paintFullCommits(view, width, color, bodyH, headerLines)
668
- : paintBriefCommits(
669
- commits,
670
- cursor,
671
- width,
672
- color,
673
- bodyH,
674
- headerLines,
675
- extra,
676
- view.listScroll,
677
- cols,
678
- view.rev,
679
- view.revShort,
680
- );
681
- return paneResult({
682
- body: painted.body,
683
- fileHits: painted.fileHits,
684
- todoOwners: [],
685
- cursor: painted.cursor,
686
- splitBody: false,
687
- listScroll: painted.offset,
688
- });
684
+ const paintRow = (entry, selected) => {
685
+ const current = viewedCommit(entry, view.rev, view.revShort);
686
+ return paintCommitRow(entry, width, color, selected, cols, current);
687
+ };
688
+ return paintCursorList(commits, cursor, pane, paintRow, extra);
689
689
  };
690
690
 
691
691
  module.exports = {