@pierre/diffs 1.2.0-beta.5 → 1.2.0-beta.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 (48) hide show
  1. package/dist/components/CodeView.d.ts +3 -0
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +40 -1
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts.map +1 -1
  6. package/dist/components/FileDiff.d.ts.map +1 -1
  7. package/dist/components/VirtualizedFile.d.ts +1 -0
  8. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  9. package/dist/components/VirtualizedFile.js +19 -6
  10. package/dist/components/VirtualizedFile.js.map +1 -1
  11. package/dist/components/VirtualizedFileDiff.d.ts +6 -0
  12. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  13. package/dist/components/VirtualizedFileDiff.js +75 -35
  14. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  15. package/dist/constants.d.ts.map +1 -1
  16. package/dist/constants.js +0 -1
  17. package/dist/constants.js.map +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/managers/InteractionManager.d.ts.map +1 -1
  20. package/dist/managers/ResizeManager.d.ts +7 -2
  21. package/dist/managers/ResizeManager.d.ts.map +1 -1
  22. package/dist/managers/ResizeManager.js +52 -16
  23. package/dist/managers/ResizeManager.js.map +1 -1
  24. package/dist/react/CodeView.d.ts +1 -0
  25. package/dist/react/CodeView.d.ts.map +1 -1
  26. package/dist/react/CodeView.js +9 -0
  27. package/dist/react/CodeView.js.map +1 -1
  28. package/dist/react/constants.d.ts.map +1 -1
  29. package/dist/types.d.ts +3 -2
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/utils/computeVirtualFileMetrics.d.ts +11 -0
  32. package/dist/utils/computeVirtualFileMetrics.d.ts.map +1 -0
  33. package/dist/utils/{resolveVirtualFileMetrics.js → computeVirtualFileMetrics.js} +7 -10
  34. package/dist/utils/computeVirtualFileMetrics.js.map +1 -0
  35. package/dist/utils/detachString.d.ts +5 -0
  36. package/dist/utils/detachString.d.ts.map +1 -0
  37. package/dist/utils/detachString.js +19 -0
  38. package/dist/utils/detachString.js.map +1 -0
  39. package/dist/utils/parsePatchFiles.js +163 -56
  40. package/dist/utils/parsePatchFiles.js.map +1 -1
  41. package/dist/worker/worker-portable.js +0 -1
  42. package/dist/worker/worker-portable.js.map +1 -1
  43. package/dist/worker/worker.js +0 -1
  44. package/dist/worker/worker.js.map +1 -1
  45. package/package.json +1 -1
  46. package/dist/utils/resolveVirtualFileMetrics.d.ts +0 -10
  47. package/dist/utils/resolveVirtualFileMetrics.d.ts.map +0 -1
  48. package/dist/utils/resolveVirtualFileMetrics.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } from "../constants.js";
2
2
  import { areObjectsEqual } from "../utils/areObjectsEqual.js";
3
3
  import { areOptionsEqual } from "../utils/areOptionsEqual.js";
4
- import { getVirtualFileHeaderRegion, getVirtualFilePaddingBottom, resolveVirtualFileMetrics } from "../utils/resolveVirtualFileMetrics.js";
4
+ import { computeVirtualFileMetrics, getDefaultHunkSeparatorHeight, getVirtualFileHeaderRegion, getVirtualFilePaddingBottom } from "../utils/computeVirtualFileMetrics.js";
5
5
  import { iterateOverDiff } from "../utils/iterateOverDiff.js";
6
6
  import { parseDiffFromFile } from "../utils/parseDiffFromFile.js";
7
7
  import { FileDiff } from "./FileDiff.js";
@@ -22,16 +22,15 @@ var VirtualizedFileDiff = class extends FileDiff {
22
22
  isVisible = false;
23
23
  isSetup = false;
24
24
  virtualizer;
25
+ layoutDirty = true;
25
26
  forceRenderOverride;
26
27
  constructor(options, virtualizer, metrics, workerManager, isContainerManaged = false) {
27
28
  super(options, workerManager, isContainerManaged);
28
- const { hunkSeparators = "line-info" } = this.options;
29
29
  this.virtualizer = virtualizer;
30
- this.metrics = resolveVirtualFileMetrics(typeof hunkSeparators === "function" ? "custom" : hunkSeparators, metrics);
30
+ this.metrics = computeVirtualFileMetrics(metrics);
31
31
  }
32
32
  setMetrics(metrics, force = false) {
33
- const { hunkSeparators = "line-info" } = this.options;
34
- const nextMetrics = resolveVirtualFileMetrics(typeof hunkSeparators === "function" ? "custom" : hunkSeparators, metrics);
33
+ const nextMetrics = computeVirtualFileMetrics(metrics);
35
34
  if (!force && areObjectsEqual(this.metrics, nextMetrics)) return;
36
35
  this.metrics = nextMetrics;
37
36
  this.resetLayoutCache();
@@ -53,6 +52,7 @@ var VirtualizedFileDiff = class extends FileDiff {
53
52
  if (optionsChanged && this.isSimpleMode()) this.virtualizer.instanceChanged(this, layoutChanged);
54
53
  }
55
54
  resetLayoutCache(recompute = false) {
55
+ this.layoutDirty = true;
56
56
  this.cache.heights.clear();
57
57
  this.cache.checkpoints = [];
58
58
  this.cache.totalLines = 0;
@@ -93,7 +93,7 @@ var VirtualizedFileDiff = class extends FileDiff {
93
93
  else this.cache.heights.set(lineIndex, measuredHeight);
94
94
  }
95
95
  }
96
- if (hasHeightChange || this.isResizeDebuggingEnabled()) this.computeApproximateSize();
96
+ if (hasHeightChange || this.isResizeDebuggingEnabled()) this.computeApproximateSize(true);
97
97
  return hasHeightChange;
98
98
  }
99
99
  onRender = (dirty) => {
@@ -102,6 +102,7 @@ var VirtualizedFileDiff = class extends FileDiff {
102
102
  return this.render();
103
103
  };
104
104
  prepareVirtualizedItem(fileDiff) {
105
+ if (this.fileDiff !== fileDiff) this.layoutDirty = true;
105
106
  this.fileDiff = fileDiff;
106
107
  this.top = this.getVirtualizedTop();
107
108
  this.computeApproximateSize();
@@ -111,10 +112,11 @@ var VirtualizedFileDiff = class extends FileDiff {
111
112
  if (this.fileDiff == null) return;
112
113
  const targetLineIndexes = this.getLineIndex(lineNumber, side);
113
114
  if (targetLineIndexes == null) return;
114
- const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
115
- const { hunkSeparatorHeight, spacing } = this.metrics;
115
+ const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } = this.options;
116
116
  const diffStyle = this.getDiffStyle();
117
- const separatorGap = hunkSeparators !== "simple" && hunkSeparators !== "metadata" && hunkSeparators !== "line-info-basic" ? spacing : 0;
117
+ const hunkSeparators = this.getHunkSeparatorType();
118
+ const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);
119
+ const separatorGap = this.getSeparatorGap(hunkSeparators);
118
120
  const targetLineIndex = diffStyle === "split" ? targetLineIndexes[1] : targetLineIndexes[0];
119
121
  const checkpoint = this.getLayoutCheckpointBeforeLineIndex(targetLineIndex);
120
122
  let top = checkpoint?.top ?? getVirtualFileHeaderRegion(this.metrics, disableFileHeader);
@@ -129,10 +131,10 @@ var VirtualizedFileDiff = class extends FileDiff {
129
131
  startingLine: checkpoint?.renderedLineIndex ?? 0,
130
132
  expandedHunks: expandUnchanged ? true : this.hunksRenderer.getExpandedHunksMap(),
131
133
  collapsedContextThreshold,
132
- callback: ({ hunkIndex, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
134
+ callback: ({ hunkIndex, hunk, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
133
135
  const lineIndex = diffStyle === "split" ? additionLine?.splitLineIndex ?? deletionLine?.splitLineIndex : additionLine?.unifiedLineIndex ?? deletionLine?.unifiedLineIndex;
134
136
  if (lineIndex == null) throw new Error("VirtualizedFileDiff.getLinePosition: missing line index data");
135
- if (collapsedBefore > 0) {
137
+ if (collapsedBefore > 0 && this.hasLeadingHunkSeparator(hunkIndex, hunk?.hunkSpecs, hunkSeparators)) {
136
138
  if (hunkIndex > 0) top += separatorGap;
137
139
  if (targetLineIndex >= lineIndex - collapsedBefore && targetLineIndex < lineIndex) {
138
140
  position = {
@@ -152,7 +154,7 @@ var VirtualizedFileDiff = class extends FileDiff {
152
154
  return true;
153
155
  }
154
156
  top += lineHeight;
155
- if (collapsedAfter > 0 && hunkSeparators !== "simple") {
157
+ if (collapsedAfter > 0 && this.hasTrailingHunkSeparator(hunkSeparators)) {
156
158
  if (targetLineIndex > lineIndex && targetLineIndex <= lineIndex + collapsedAfter) {
157
159
  position = {
158
160
  top: top + separatorGap,
@@ -169,11 +171,12 @@ var VirtualizedFileDiff = class extends FileDiff {
169
171
  }
170
172
  getNumericScrollAnchor(localViewportTop) {
171
173
  if (this.fileDiff == null) return;
172
- const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
174
+ const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } = this.options;
173
175
  if (collapsed) return;
174
- const { hunkSeparatorHeight, spacing } = this.metrics;
175
176
  const diffStyle = this.getDiffStyle();
176
- const separatorGap = hunkSeparators !== "simple" && hunkSeparators !== "metadata" && hunkSeparators !== "line-info-basic" ? spacing : 0;
177
+ const hunkSeparators = this.getHunkSeparatorType();
178
+ const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);
179
+ const separatorGap = this.getSeparatorGap(hunkSeparators);
177
180
  const checkpoint = this.getLayoutCheckpointBeforeTop(localViewportTop);
178
181
  let top = checkpoint?.top ?? getVirtualFileHeaderRegion(this.metrics, disableFileHeader);
179
182
  let anchor;
@@ -183,10 +186,10 @@ var VirtualizedFileDiff = class extends FileDiff {
183
186
  startingLine: checkpoint?.renderedLineIndex ?? 0,
184
187
  expandedHunks: expandUnchanged ? true : this.hunksRenderer.getExpandedHunksMap(),
185
188
  collapsedContextThreshold,
186
- callback: ({ hunkIndex, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
189
+ callback: ({ hunkIndex, hunk, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
187
190
  const lineIndex = diffStyle === "split" ? additionLine?.splitLineIndex ?? deletionLine?.splitLineIndex : additionLine?.unifiedLineIndex ?? deletionLine?.unifiedLineIndex;
188
191
  if (lineIndex == null) throw new Error("VirtualizedFileDiff.getNumericScrollAnchor: missing line index data");
189
- if (collapsedBefore > 0) {
192
+ if (collapsedBefore > 0 && this.hasLeadingHunkSeparator(hunkIndex, hunk?.hunkSpecs, hunkSeparators)) {
190
193
  if (hunkIndex > 0) top += separatorGap;
191
194
  top += hunkSeparatorHeight + separatorGap;
192
195
  }
@@ -205,7 +208,7 @@ var VirtualizedFileDiff = class extends FileDiff {
205
208
  }
206
209
  const lineHeight = this.getLineHeight(lineIndex, (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false));
207
210
  top += lineHeight;
208
- if (collapsedAfter > 0 && hunkSeparators !== "simple") top += separatorGap + hunkSeparatorHeight;
211
+ if (collapsedAfter > 0 && this.hasTrailingHunkSeparator(hunkSeparators)) top += separatorGap + hunkSeparatorHeight;
209
212
  return false;
210
213
  }
211
214
  });
@@ -230,11 +233,13 @@ var VirtualizedFileDiff = class extends FileDiff {
230
233
  }
231
234
  cleanUp(recycle = false) {
232
235
  if (this.fileContainer != null && this.isSimpleMode()) this.getSimpleVirtualizer()?.disconnect(this.fileContainer);
236
+ if (!recycle) this.layoutDirty = true;
233
237
  this.isSetup = false;
234
238
  super.cleanUp(recycle);
235
239
  }
236
240
  expandHunk = (hunkIndex, direction, expansionLineCountOverride) => {
237
241
  this.hunksRenderer.expandHunk(hunkIndex, direction, expansionLineCountOverride);
242
+ this.layoutDirty = true;
238
243
  this.computeApproximateSize();
239
244
  this.renderRange = void 0;
240
245
  this.virtualizer.instanceChanged(this, true);
@@ -255,44 +260,53 @@ var VirtualizedFileDiff = class extends FileDiff {
255
260
  this.forceRenderOverride = true;
256
261
  this.virtualizer.instanceChanged(this, false);
257
262
  }
258
- computeApproximateSize() {
263
+ computeApproximateSize(force = false) {
264
+ const shouldValidateSize = this.isResizeDebuggingEnabled();
265
+ if (!force && !this.layoutDirty && !shouldValidateSize) return;
259
266
  const isFirstCompute = this.height === 0;
260
267
  this.height = 0;
261
268
  this.cache.checkpoints = [];
262
269
  this.cache.totalLines = 0;
263
- if (this.fileDiff == null) return;
264
- const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
265
- const { spacing, hunkSeparatorHeight } = this.metrics;
270
+ if (this.fileDiff == null) {
271
+ this.layoutDirty = false;
272
+ return;
273
+ }
274
+ const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } = this.options;
266
275
  const diffStyle = this.getDiffStyle();
267
- const separatorGap = hunkSeparators !== "simple" && hunkSeparators !== "metadata" && hunkSeparators !== "line-info-basic" ? spacing : 0;
276
+ const hunkSeparators = this.getHunkSeparatorType();
277
+ const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);
278
+ const separatorGap = this.getSeparatorGap(hunkSeparators);
268
279
  const headerRegion = getVirtualFileHeaderRegion(this.metrics, disableFileHeader);
269
280
  const paddingBottom = getVirtualFilePaddingBottom(this.metrics);
270
281
  this.height += headerRegion;
271
- if (collapsed) return;
282
+ if (collapsed) {
283
+ this.layoutDirty = false;
284
+ return;
285
+ }
272
286
  let renderedLineIndex = 0;
273
287
  iterateOverDiff({
274
288
  diff: this.fileDiff,
275
289
  diffStyle,
276
290
  expandedHunks: expandUnchanged ? true : this.hunksRenderer.getExpandedHunksMap(),
277
291
  collapsedContextThreshold,
278
- callback: ({ hunkIndex, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
292
+ callback: ({ hunkIndex, hunk, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
279
293
  const splitLineIndex = additionLine != null ? additionLine.splitLineIndex : deletionLine.splitLineIndex;
280
294
  const unifiedLineIndex = additionLine != null ? additionLine.unifiedLineIndex : deletionLine.unifiedLineIndex;
281
295
  const hasMetadata = (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);
282
296
  const lineIndex = diffStyle === "split" ? splitLineIndex : unifiedLineIndex;
283
297
  this.addLayoutCheckpoint(renderedLineIndex, lineIndex, this.height);
284
- if (collapsedBefore > 0) {
298
+ if (collapsedBefore > 0 && this.hasLeadingHunkSeparator(hunkIndex, hunk?.hunkSpecs, hunkSeparators)) {
285
299
  if (hunkIndex > 0) this.height += separatorGap;
286
300
  this.height += hunkSeparatorHeight + separatorGap;
287
301
  }
288
302
  this.height += this.getLineHeight(lineIndex, hasMetadata);
289
- if (collapsedAfter > 0 && hunkSeparators !== "simple") this.height += separatorGap + hunkSeparatorHeight;
303
+ if (collapsedAfter > 0 && this.hasTrailingHunkSeparator(hunkSeparators)) this.height += separatorGap + hunkSeparatorHeight;
290
304
  renderedLineIndex++;
291
305
  }
292
306
  });
293
307
  this.cache.totalLines = renderedLineIndex;
294
308
  if (this.fileDiff.hunks.length > 0) this.height += paddingBottom;
295
- if (this.fileContainer != null && this.isResizeDebuggingEnabled() && !isFirstCompute) {
309
+ if (this.fileContainer != null && shouldValidateSize && !isFirstCompute) {
296
310
  const rect = this.fileContainer.getBoundingClientRect();
297
311
  if (rect.height !== this.height) console.log("VirtualizedFileDiff.computeApproximateSize: computed height doesnt match", {
298
312
  name: this.fileDiff.name,
@@ -301,6 +315,7 @@ var VirtualizedFileDiff = class extends FileDiff {
301
315
  });
302
316
  else console.log("VirtualizedFileDiff.computeApproximateSize: computed height IS CORRECT");
303
317
  }
318
+ this.layoutDirty = false;
304
319
  }
305
320
  render({ fileContainer, oldFile, newFile, fileDiff, forceRender = false,...props } = {}) {
306
321
  const { forceRenderOverride, isSetup } = this;
@@ -362,6 +377,27 @@ var VirtualizedFileDiff = class extends FileDiff {
362
377
  getDiffStyle() {
363
378
  return this.options.diffStyle ?? "split";
364
379
  }
380
+ getHunkSeparatorType() {
381
+ return getOptionHunkSeparatorType(this.options.hunkSeparators);
382
+ }
383
+ getHunkSeparatorHeight(type = this.getHunkSeparatorType()) {
384
+ return this.metrics.hunkSeparatorHeight ?? getDefaultHunkSeparatorHeight(type);
385
+ }
386
+ getSeparatorGap(type = this.getHunkSeparatorType()) {
387
+ return type === "simple" || type === "metadata" || type === "line-info-basic" ? 0 : this.metrics.spacing;
388
+ }
389
+ hasLeadingHunkSeparator(hunkIndex, hunkSpecs, type = this.getHunkSeparatorType()) {
390
+ switch (type) {
391
+ case "simple": return hunkIndex > 0;
392
+ case "metadata": return hunkSpecs != null;
393
+ case "line-info":
394
+ case "line-info-basic":
395
+ case "custom": return true;
396
+ }
397
+ }
398
+ hasTrailingHunkSeparator(type = this.getHunkSeparatorType()) {
399
+ return type !== "simple" && type !== "metadata";
400
+ }
365
401
  addLayoutCheckpoint(renderedLineIndex, lineIndex, top) {
366
402
  if (renderedLineIndex % LAYOUT_CHECKPOINT_INTERVAL !== 0) return;
367
403
  this.cache.checkpoints.push({
@@ -459,9 +495,11 @@ var VirtualizedFileDiff = class extends FileDiff {
459
495
  return count;
460
496
  }
461
497
  computeRenderRangeFromWindow(fileDiff, fileTop, { top, bottom }) {
462
- const { disableFileHeader = false, expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
463
- const { spacing, hunkLineCount, hunkSeparatorHeight, lineHeight } = this.metrics;
498
+ const { disableFileHeader = false, expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } = this.options;
499
+ const { hunkLineCount, lineHeight } = this.metrics;
464
500
  const diffStyle = this.getDiffStyle();
501
+ const hunkSeparators = this.getHunkSeparatorType();
502
+ const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);
465
503
  const fileHeight = this.height;
466
504
  const lineCount = this.cache.totalLines > 0 ? this.cache.totalLines : this.getExpandedLineCount(fileDiff, diffStyle);
467
505
  const headerRegion = getVirtualFileHeaderRegion(this.metrics, disableFileHeader);
@@ -484,7 +522,7 @@ var VirtualizedFileDiff = class extends FileDiff {
484
522
  const overflowHunks = totalHunks;
485
523
  const hunkOffsets = [];
486
524
  const viewportCenter = (top + bottom) / 2;
487
- const separatorGap = hunkSeparators === "simple" || hunkSeparators === "metadata" || hunkSeparators === "line-info-basic" ? 0 : spacing;
525
+ const separatorGap = this.getSeparatorGap(hunkSeparators);
488
526
  const checkpoint = this.getLayoutCheckpointBeforeTop(Math.max(0, top - fileTop - totalLines * lineHeight * 2), hunkLineCount);
489
527
  let absoluteLineTop = fileTop + (checkpoint?.top ?? headerRegion);
490
528
  let currentLine = checkpoint?.renderedLineIndex ?? 0;
@@ -497,12 +535,11 @@ var VirtualizedFileDiff = class extends FileDiff {
497
535
  startingLine: checkpoint?.renderedLineIndex ?? 0,
498
536
  expandedHunks: expandUnchanged ? true : this.hunksRenderer.getExpandedHunksMap(),
499
537
  collapsedContextThreshold,
500
- callback: ({ hunkIndex, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
538
+ callback: ({ hunkIndex, hunk, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
501
539
  const splitLineIndex = additionLine != null ? additionLine.splitLineIndex : deletionLine.splitLineIndex;
502
540
  const unifiedLineIndex = additionLine != null ? additionLine.unifiedLineIndex : deletionLine.unifiedLineIndex;
503
541
  const hasMetadata = (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);
504
- let gapAdjustment = collapsedBefore > 0 ? hunkSeparatorHeight + separatorGap + (hunkIndex > 0 ? separatorGap : 0) : 0;
505
- if (hunkIndex === 0 && hunkSeparators === "simple") gapAdjustment = 0;
542
+ const gapAdjustment = collapsedBefore > 0 && this.hasLeadingHunkSeparator(hunkIndex, hunk?.hunkSpecs, hunkSeparators) ? hunkSeparatorHeight + separatorGap + (hunkIndex > 0 ? separatorGap : 0) : 0;
506
543
  absoluteLineTop += gapAdjustment;
507
544
  const isAtHunkBoundary = currentLine % hunkLineCount === 0;
508
545
  const currentHunk = Math.floor(currentLine / hunkLineCount);
@@ -519,7 +556,7 @@ var VirtualizedFileDiff = class extends FileDiff {
519
556
  if (overflowCounter == null && absoluteLineTop >= bottom && isAtHunkBoundary) overflowCounter = overflowHunks;
520
557
  currentLine++;
521
558
  absoluteLineTop += lineHeight$1;
522
- if (collapsedAfter > 0 && hunkSeparators !== "simple") absoluteLineTop += hunkSeparatorHeight + separatorGap;
559
+ if (collapsedAfter > 0 && this.hasTrailingHunkSeparator(hunkSeparators)) absoluteLineTop += hunkSeparatorHeight + separatorGap;
523
560
  return false;
524
561
  }
525
562
  });
@@ -548,6 +585,9 @@ var VirtualizedFileDiff = class extends FileDiff {
548
585
  function hasDiffLayoutOptionChanged(previousOptions, nextOptions) {
549
586
  return (previousOptions.diffStyle ?? "split") !== (nextOptions.diffStyle ?? "split") || (previousOptions.overflow ?? "scroll") !== (nextOptions.overflow ?? "scroll") || (previousOptions.collapsed ?? false) !== (nextOptions.collapsed ?? false) || (previousOptions.disableLineNumbers ?? false) !== (nextOptions.disableLineNumbers ?? false) || (previousOptions.disableFileHeader ?? false) !== (nextOptions.disableFileHeader ?? false) || (previousOptions.diffIndicators ?? "bars") !== (nextOptions.diffIndicators ?? "bars") || (previousOptions.hunkSeparators ?? "line-info") !== (nextOptions.hunkSeparators ?? "line-info") || (previousOptions.expandUnchanged ?? false) !== (nextOptions.expandUnchanged ?? false) || (previousOptions.collapsedContextThreshold ?? DEFAULT_COLLAPSED_CONTEXT_THRESHOLD) !== (nextOptions.collapsedContextThreshold ?? DEFAULT_COLLAPSED_CONTEXT_THRESHOLD) || previousOptions.unsafeCSS !== nextOptions.unsafeCSS;
550
587
  }
588
+ function getOptionHunkSeparatorType(hunkSeparators) {
589
+ return typeof hunkSeparators === "function" ? "custom" : hunkSeparators ?? "line-info";
590
+ }
551
591
  function hasFinalHunk(fileDiff) {
552
592
  const lastHunk = fileDiff.hunks.at(-1);
553
593
  if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return false;
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizedFileDiff.js","names":["position: { top: number; height: number } | undefined","anchor: NumericScrollLineAnchor | undefined","result: DiffLayoutCheckpoint | undefined","hunkOffsets: number[]","firstVisibleHunk: number | undefined","centerHunk: number | undefined","overflowCounter: number | undefined","lineHeight"],"sources":["../../src/components/VirtualizedFileDiff.ts"],"sourcesContent":["import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } from '../constants';\nimport type {\n ExpansionDirections,\n FileDiffMetadata,\n NumericScrollLineAnchor,\n RenderRange,\n RenderWindow,\n SelectionSide,\n StickySpecs,\n VirtualFileMetrics,\n} from '../types';\nimport { areObjectsEqual } from '../utils/areObjectsEqual';\nimport { areOptionsEqual } from '../utils/areOptionsEqual';\nimport { iterateOverDiff } from '../utils/iterateOverDiff';\nimport { parseDiffFromFile } from '../utils/parseDiffFromFile';\nimport {\n getVirtualFileHeaderRegion,\n getVirtualFilePaddingBottom,\n resolveVirtualFileMetrics,\n} from '../utils/resolveVirtualFileMetrics';\nimport type { WorkerPoolManager } from '../worker';\nimport type { CodeView } from './CodeView';\nimport {\n FileDiff,\n type FileDiffOptions,\n type FileDiffRenderProps,\n} from './FileDiff';\nimport type { Virtualizer } from './Virtualizer';\n\ninterface ExpandedRegionSpecs {\n fromStart: number;\n fromEnd: number;\n collapsedLines: number;\n renderAll: boolean;\n}\n\ninterface DiffLayoutCheckpoint {\n renderedLineIndex: number;\n lineIndex: number;\n top: number;\n}\n\ninterface DiffLayoutCache {\n // Sparse map: view-specific line index -> measured height. Only stores lines\n // that differ from what is returned by `getLineHeight`.\n heights: Map<number, number>;\n // Sparse measured positions used to resume deep geometry scans near a target\n // diff line, rendered row, or scroll offset instead of replaying layout from\n // the first hunk.\n checkpoints: DiffLayoutCheckpoint[];\n // Total renderable diff rows for the current diff style and expansion state.\n totalLines: number;\n}\n\nconst LAYOUT_CHECKPOINT_INTERVAL = 5_000;\n\nlet instanceId = -1;\n\nexport class VirtualizedFileDiff<\n LAnnotation = undefined,\n> extends FileDiff<LAnnotation> {\n override readonly __id: string = `little-virtualized-file-diff:${++instanceId}`;\n\n public top: number | undefined;\n public height: number = 0;\n private metrics: VirtualFileMetrics;\n private cache: DiffLayoutCache = {\n heights: new Map(),\n checkpoints: [],\n totalLines: 0,\n };\n private isVisible: boolean = false;\n private isSetup: boolean = false;\n private virtualizer: Virtualizer | CodeView<LAnnotation>;\n private forceRenderOverride: true | undefined;\n\n constructor(\n options: FileDiffOptions<LAnnotation> | undefined,\n virtualizer: Virtualizer | CodeView<LAnnotation>,\n metrics?: Partial<VirtualFileMetrics>,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\n const { hunkSeparators = 'line-info' } = this.options;\n this.virtualizer = virtualizer;\n this.metrics = resolveVirtualFileMetrics(\n typeof hunkSeparators === 'function' ? 'custom' : hunkSeparators,\n metrics\n );\n }\n\n public setMetrics(\n metrics?: Partial<VirtualFileMetrics>,\n force = false\n ): void {\n const { hunkSeparators = 'line-info' } = this.options;\n const nextMetrics = resolveVirtualFileMetrics(\n typeof hunkSeparators === 'function' ? 'custom' : hunkSeparators,\n metrics\n );\n if (!force && areObjectsEqual(this.metrics, nextMetrics)) {\n return;\n }\n\n this.metrics = nextMetrics;\n this.resetLayoutCache();\n }\n\n // Get the height for a line, using cached value if available.\n // If not cached and hasMetadataLine is true, adds lineHeight for the metadata.\n private getLineHeight(lineIndex: number, hasMetadataLine = false): number {\n const cached = this.cache.heights.get(lineIndex);\n if (cached != null) {\n return cached;\n }\n const multiplier = hasMetadataLine ? 2 : 1;\n return this.metrics.lineHeight * multiplier;\n }\n\n override setOptions(options: FileDiffOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n const { options: previousOptions } = this;\n const optionsChanged = !areOptionsEqual(previousOptions, options);\n const layoutChanged =\n optionsChanged && hasDiffLayoutOptionChanged(previousOptions, options);\n\n super.setOptions(options);\n\n if (layoutChanged) {\n this.resetLayoutCache(true);\n }\n // Any option can affect rendered DOM; only layout-affecting options clear\n // the measured height cache above.\n if (optionsChanged) {\n this.forceRenderOverride = true;\n }\n if (optionsChanged && this.isSimpleMode()) {\n this.virtualizer.instanceChanged(this, layoutChanged);\n }\n }\n\n private resetLayoutCache(recompute = false): void {\n this.cache.heights.clear();\n this.cache.checkpoints = [];\n this.cache.totalLines = 0;\n this.renderRange = undefined;\n // NOTE(amadeus): In CodeView we intentionally batch computes to all happen\n // at the same time, so we shouldn't trigger this there.\n if (recompute && this.isSimpleMode()) {\n this.computeApproximateSize();\n }\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n // Definitely need to optimize this in cases where there aren't any custom\n // line heights or in cases of extremely large files...\n public reconcileHeights(): boolean {\n let hasHeightChange = false;\n const { overflow = 'scroll' } = this.options;\n if (this.fileContainer == null || this.fileDiff == null) {\n if (this.height !== 0) {\n hasHeightChange = true;\n }\n this.height = 0;\n return hasHeightChange;\n }\n this.top = this.getVirtualizedTop();\n // NOTE(amadeus): We can probably be a lot smarter about this, and we\n // should be thinking about ways to improve this\n // If the file has no annotations and we are using the scroll variant, then\n // we can probably skip everything\n if (\n overflow === 'scroll' &&\n this.lineAnnotations.length === 0 &&\n !this.isResizeDebuggingEnabled()\n ) {\n return hasHeightChange;\n }\n const diffStyle = this.getDiffStyle();\n const codeGroups =\n diffStyle === 'split'\n ? [this.codeDeletions, this.codeAdditions]\n : [this.codeUnified];\n\n for (const codeGroup of codeGroups) {\n if (codeGroup == null) continue;\n const content = codeGroup.children[1];\n if (!(content instanceof HTMLElement)) continue;\n for (const line of content.children) {\n if (!(line instanceof HTMLElement)) continue;\n\n const lineIndexAttr = line.dataset.lineIndex;\n if (lineIndexAttr == null) continue;\n\n const lineIndex = parseLineIndex(lineIndexAttr, diffStyle);\n let measuredHeight = line.getBoundingClientRect().height;\n let hasMetadata = false;\n // Annotations or noNewline metadata increase the size of the their\n // attached line\n if (\n line.nextElementSibling instanceof HTMLElement &&\n ('lineAnnotation' in line.nextElementSibling.dataset ||\n 'noNewline' in line.nextElementSibling.dataset)\n ) {\n if ('noNewline' in line.nextElementSibling.dataset) {\n hasMetadata = true;\n }\n measuredHeight +=\n line.nextElementSibling.getBoundingClientRect().height;\n }\n const expectedHeight = this.getLineHeight(lineIndex, hasMetadata);\n\n if (measuredHeight === expectedHeight) {\n continue;\n }\n\n hasHeightChange = true;\n // Line is back to standard height (e.g., after window resize)\n // Remove from cache\n if (\n measuredHeight ===\n this.metrics.lineHeight * (hasMetadata ? 2 : 1)\n ) {\n this.cache.heights.delete(lineIndex);\n }\n // Non-standard height, cache it\n else {\n this.cache.heights.set(lineIndex, measuredHeight);\n }\n }\n }\n\n if (hasHeightChange || this.isResizeDebuggingEnabled()) {\n this.computeApproximateSize();\n }\n return hasHeightChange;\n }\n\n public onRender = (dirty: boolean): boolean => {\n if (this.fileContainer == null) {\n return false;\n }\n if (dirty) {\n this.top = this.getVirtualizedTop();\n }\n return this.render();\n };\n\n public prepareVirtualizedItem(fileDiff: FileDiffMetadata): number {\n this.fileDiff = fileDiff;\n this.top = this.getVirtualizedTop();\n this.computeApproximateSize();\n return this.height;\n }\n\n public getLinePosition(\n lineNumber: number,\n side: SelectionSide = 'additions'\n ): { top: number; height: number } | undefined {\n if (this.fileDiff == null) {\n return undefined;\n }\n\n const targetLineIndexes = this.getLineIndex(lineNumber, side);\n if (targetLineIndexes == null) {\n return undefined;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsed = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n hunkSeparators = 'line-info',\n } = this.options;\n const { hunkSeparatorHeight, spacing } = this.metrics;\n const diffStyle = this.getDiffStyle();\n const separatorGap =\n hunkSeparators !== 'simple' &&\n hunkSeparators !== 'metadata' &&\n hunkSeparators !== 'line-info-basic'\n ? spacing\n : 0;\n const targetLineIndex =\n diffStyle === 'split' ? targetLineIndexes[1] : targetLineIndexes[0];\n const checkpoint = this.getLayoutCheckpointBeforeLineIndex(targetLineIndex);\n let top =\n checkpoint?.top ??\n getVirtualFileHeaderRegion(this.metrics, disableFileHeader);\n\n if (collapsed) {\n return { top, height: 0 };\n }\n\n let position: { top: number; height: number } | undefined;\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n startingLine: checkpoint?.renderedLineIndex ?? 0,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const lineIndex =\n diffStyle === 'split'\n ? (additionLine?.splitLineIndex ?? deletionLine?.splitLineIndex)\n : (additionLine?.unifiedLineIndex ??\n deletionLine?.unifiedLineIndex);\n if (lineIndex == null) {\n throw new Error(\n 'VirtualizedFileDiff.getLinePosition: missing line index data'\n );\n }\n\n if (collapsedBefore > 0) {\n if (hunkIndex > 0) {\n top += separatorGap;\n }\n if (\n targetLineIndex >= lineIndex - collapsedBefore &&\n targetLineIndex < lineIndex\n ) {\n position = {\n top,\n height: hunkSeparatorHeight,\n };\n return true;\n }\n top += hunkSeparatorHeight + separatorGap;\n }\n\n const lineHeight = this.getLineHeight(\n lineIndex,\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false)\n );\n if (lineIndex === targetLineIndex) {\n position = {\n top,\n height: lineHeight,\n };\n return true;\n }\n top += lineHeight;\n\n if (collapsedAfter > 0 && hunkSeparators !== 'simple') {\n if (\n targetLineIndex > lineIndex &&\n targetLineIndex <= lineIndex + collapsedAfter\n ) {\n position = {\n top: top + separatorGap,\n height: hunkSeparatorHeight,\n };\n return true;\n }\n top += separatorGap + hunkSeparatorHeight;\n }\n\n return false;\n },\n });\n\n return position;\n }\n\n public getNumericScrollAnchor(\n localViewportTop: number\n ): NumericScrollLineAnchor | undefined {\n if (this.fileDiff == null) {\n return undefined;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsed = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n hunkSeparators = 'line-info',\n } = this.options;\n if (collapsed) {\n return undefined;\n }\n\n const { hunkSeparatorHeight, spacing } = this.metrics;\n const diffStyle = this.getDiffStyle();\n const separatorGap =\n hunkSeparators !== 'simple' &&\n hunkSeparators !== 'metadata' &&\n hunkSeparators !== 'line-info-basic'\n ? spacing\n : 0;\n\n const checkpoint = this.getLayoutCheckpointBeforeTop(localViewportTop);\n let top =\n checkpoint?.top ??\n getVirtualFileHeaderRegion(this.metrics, disableFileHeader);\n let anchor: NumericScrollLineAnchor | undefined;\n\n // This may end up being quite expensive on extremely large files, we may\n // need to figure out how to anchor on different regions, or utilize\n // renderRange to shortcut this for us somehow\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n startingLine: checkpoint?.renderedLineIndex ?? 0,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const lineIndex =\n diffStyle === 'split'\n ? (additionLine?.splitLineIndex ?? deletionLine?.splitLineIndex)\n : (additionLine?.unifiedLineIndex ??\n deletionLine?.unifiedLineIndex);\n if (lineIndex == null) {\n throw new Error(\n 'VirtualizedFileDiff.getNumericScrollAnchor: missing line index data'\n );\n }\n\n if (collapsedBefore > 0) {\n if (hunkIndex > 0) {\n top += separatorGap;\n }\n top += hunkSeparatorHeight + separatorGap;\n }\n\n if (top >= localViewportTop) {\n if (deletionLine != null) {\n anchor = {\n lineNumber: deletionLine.lineNumber,\n side: 'deletions',\n top,\n };\n } else if (additionLine != null) {\n anchor = {\n lineNumber: additionLine.lineNumber,\n side: 'additions',\n top,\n };\n }\n if (anchor != null) {\n return true;\n }\n }\n\n const lineHeight = this.getLineHeight(\n lineIndex,\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false)\n );\n top += lineHeight;\n\n if (collapsedAfter > 0 && hunkSeparators !== 'simple') {\n top += separatorGap + hunkSeparatorHeight;\n }\n\n return false;\n },\n });\n\n return anchor;\n }\n\n public getVirtualizedHeight(): number {\n return this.height;\n }\n\n public getAdvancedStickySpecs(\n windowSpecs?: RenderWindow\n ): StickySpecs | undefined {\n if (this.top == null || this.fileDiff == null) {\n return undefined;\n }\n if (this.options.collapsed === true) {\n return { topOffset: this.top, height: this.height };\n }\n const renderRange =\n windowSpecs != null\n ? this.computeRenderRangeFromWindow(\n this.fileDiff,\n this.top,\n windowSpecs\n )\n : this.renderRange;\n if (renderRange == null) {\n return undefined;\n }\n const { bufferBefore, bufferAfter, totalLines } = renderRange;\n return {\n topOffset: this.top + bufferBefore + (totalLines === 0 ? bufferAfter : 0),\n height: this.height - (bufferBefore + bufferAfter),\n };\n }\n\n override cleanUp(recycle = false): void {\n if (this.fileContainer != null && this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.disconnect(this.fileContainer);\n }\n this.isSetup = false;\n super.cleanUp(recycle);\n }\n\n override expandHunk = (\n hunkIndex: number,\n direction: ExpansionDirections,\n expansionLineCountOverride?: number\n ): void => {\n this.hunksRenderer.expandHunk(\n hunkIndex,\n direction,\n expansionLineCountOverride\n );\n this.computeApproximateSize();\n this.renderRange = undefined;\n this.virtualizer.instanceChanged(this, true);\n };\n\n public setVisibility(visible: boolean): void {\n if (this.isAdvancedMode() || this.fileContainer == null) {\n return;\n }\n this.renderRange = undefined;\n if (visible && !this.isVisible) {\n this.top = this.getVirtualizedTop();\n this.isVisible = true;\n } else if (!visible && this.isVisible) {\n this.isVisible = false;\n this.rerender();\n }\n }\n\n override rerender(): void {\n if (\n !this.enabled ||\n (this.fileDiff == null &&\n this.additionFile == null &&\n this.deletionFile == null)\n ) {\n return;\n }\n this.forceRenderOverride = true;\n this.virtualizer.instanceChanged(this, false);\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\n // We should probably optimize this if there are no custom line heights...\n // The reason we refer to this as `approximate size` is because heights my\n // dynamically change for a number of reasons so we can never be fully sure\n // if the height is 100% accurate\n private computeApproximateSize(): void {\n const isFirstCompute = this.height === 0;\n this.height = 0;\n this.cache.checkpoints = [];\n this.cache.totalLines = 0;\n if (this.fileDiff == null) {\n return;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsed = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n hunkSeparators = 'line-info',\n } = this.options;\n const { spacing, hunkSeparatorHeight } = this.metrics;\n const diffStyle = this.getDiffStyle();\n const separatorGap =\n hunkSeparators !== 'simple' &&\n hunkSeparators !== 'metadata' &&\n hunkSeparators !== 'line-info-basic'\n ? spacing\n : 0;\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const paddingBottom = getVirtualFilePaddingBottom(this.metrics);\n\n this.height += headerRegion;\n if (collapsed) {\n return;\n }\n\n let renderedLineIndex = 0;\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const splitLineIndex =\n additionLine != null\n ? additionLine.splitLineIndex\n : deletionLine.splitLineIndex;\n const unifiedLineIndex =\n additionLine != null\n ? additionLine.unifiedLineIndex\n : deletionLine.unifiedLineIndex;\n const hasMetadata =\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);\n const lineIndex =\n diffStyle === 'split' ? splitLineIndex : unifiedLineIndex;\n this.addLayoutCheckpoint(renderedLineIndex, lineIndex, this.height);\n if (collapsedBefore > 0) {\n if (hunkIndex > 0) {\n this.height += separatorGap;\n }\n this.height += hunkSeparatorHeight + separatorGap;\n }\n\n this.height += this.getLineHeight(lineIndex, hasMetadata);\n\n if (collapsedAfter > 0 && hunkSeparators !== 'simple') {\n this.height += separatorGap + hunkSeparatorHeight;\n }\n renderedLineIndex++;\n },\n });\n this.cache.totalLines = renderedLineIndex;\n\n // Bottom padding\n if (this.fileDiff.hunks.length > 0) {\n this.height += paddingBottom;\n }\n\n if (\n this.fileContainer != null &&\n this.isResizeDebuggingEnabled() &&\n !isFirstCompute\n ) {\n const rect = this.fileContainer.getBoundingClientRect();\n if (rect.height !== this.height) {\n console.log(\n 'VirtualizedFileDiff.computeApproximateSize: computed height doesnt match',\n {\n name: this.fileDiff.name,\n elementHeight: rect.height,\n computedHeight: this.height,\n }\n );\n } else {\n console.log(\n 'VirtualizedFileDiff.computeApproximateSize: computed height IS CORRECT'\n );\n }\n }\n }\n\n override render({\n fileContainer,\n oldFile,\n newFile,\n fileDiff,\n forceRender = false,\n ...props\n }: FileDiffRenderProps<LAnnotation> = {}): boolean {\n const { forceRenderOverride, isSetup } = this;\n this.forceRenderOverride = undefined;\n\n this.fileDiff ??=\n fileDiff ??\n (oldFile != null && newFile != null\n ? // NOTE(amadeus): We might be forcing ourselves to double up the\n // computation of fileDiff (in the super.render() call), so we might want\n // to figure out a way to avoid that. That also could be just as simple as\n // passing through fileDiff though... so maybe we good?\n parseDiffFromFile(oldFile, newFile, this.options.parseDiffOptions)\n : undefined);\n\n fileContainer = this.getOrCreateFileContainer(fileContainer);\n\n if (this.fileDiff == null) {\n console.error(\n 'VirtualizedFileDiff.render: attempting to virtually render when we dont have the correct data'\n );\n return false;\n }\n\n if (!isSetup) {\n this.computeApproximateSize();\n const virtualizer = this.getSimpleVirtualizer();\n this.top ??= this.getVirtualizedTop();\n if (this.isAdvancedMode()) {\n this.isVisible = true;\n } else {\n if (virtualizer == null) {\n throw new Error(\n 'VirtualizedFileDiff.render: simple virtualizer is not available'\n );\n }\n virtualizer.connect(fileContainer, this);\n this.isVisible = virtualizer.isInstanceVisible(\n this.top ?? 0,\n this.height\n );\n }\n this.isSetup = true;\n } else {\n this.top ??= this.getVirtualizedTop();\n }\n\n if (!this.isVisible && this.isSimpleMode()) {\n return this.renderPlaceholder(this.height);\n }\n\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const fileTop = this.top ?? 0;\n const renderRange = this.computeRenderRangeFromWindow(\n this.fileDiff,\n fileTop,\n windowSpecs\n );\n return super.render({\n fileDiff: this.fileDiff,\n fileContainer,\n renderRange,\n oldFile,\n newFile,\n forceRender: forceRenderOverride ?? forceRender,\n ...props,\n });\n }\n\n public syncVirtualizedTop(): void {\n this.top = this.getVirtualizedTop();\n }\n\n protected override shouldDisableVirtualizationBuffers(): boolean {\n return this.isAdvancedMode() || super.shouldDisableVirtualizationBuffers();\n }\n\n private isSimpleMode(): boolean {\n return this.virtualizer.type === 'simple';\n }\n\n private isAdvancedMode(): boolean {\n return this.virtualizer.type === 'advanced';\n }\n\n private getVirtualizedTop(): number | undefined {\n if (this.virtualizer.type === 'advanced') {\n return this.virtualizer.getLocalTopForInstance(this);\n }\n return this.fileContainer != null\n ? this.virtualizer.getOffsetInScrollContainer(this.fileContainer)\n : 0;\n }\n\n private getSimpleVirtualizer(): Virtualizer | undefined {\n return this.virtualizer.type === 'simple' ? this.virtualizer : undefined;\n }\n\n private isResizeDebuggingEnabled(): boolean {\n return this.getSimpleVirtualizer()?.config.resizeDebugging ?? false;\n }\n\n private getDiffStyle(): 'split' | 'unified' {\n return this.options.diffStyle ?? 'split';\n }\n\n private addLayoutCheckpoint(\n renderedLineIndex: number,\n lineIndex: number,\n top: number\n ): void {\n if (renderedLineIndex % LAYOUT_CHECKPOINT_INTERVAL !== 0) {\n return;\n }\n this.cache.checkpoints.push({ renderedLineIndex, lineIndex, top });\n }\n\n // Find the nearest sparse layout checkpoint at or before an active\n // diff-style line index. Diff checkpoints also store the dense rendered-row\n // index, so deep line-position lookups can resume iteration from that\n // rendered row and replay only the nearby layout work instead of walking\n // from the first hunk.\n private getLayoutCheckpointBeforeLineIndex(\n lineIndex: number\n ): DiffLayoutCheckpoint | undefined {\n if (lineIndex <= 0 || this.cache.checkpoints.length === 0) {\n return undefined;\n }\n\n let low = 0;\n let high = this.cache.checkpoints.length - 1;\n let result: DiffLayoutCheckpoint | undefined;\n\n while (low <= high) {\n const mid = (low + high) >> 1;\n const checkpoint = this.cache.checkpoints[mid];\n if (checkpoint == null) {\n throw new Error('VirtualizedFileDiff: invalid checkpoint index');\n }\n if (checkpoint.lineIndex <= lineIndex) {\n result = checkpoint;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return result;\n }\n\n // Find the nearest sparse layout checkpoint at or before a scroll offset.\n // Render-range scans start from this checkpoint so variable-height diffs\n // only replay nearby rows. When `hunkLineCount` is provided, step backward\n // to a rendered hunk boundary so buffer calculations can reuse absolute hunk\n // offsets safely.\n private getLayoutCheckpointBeforeTop(\n top: number,\n hunkLineCount?: number\n ): DiffLayoutCheckpoint | undefined {\n let low = 0;\n let high = this.cache.checkpoints.length - 1;\n let resultIndex = -1;\n\n while (low <= high) {\n const mid = (low + high) >> 1;\n const checkpoint = this.cache.checkpoints[mid];\n if (checkpoint == null) {\n throw new Error('VirtualizedFileDiff: invalid checkpoint index');\n }\n if (checkpoint.top <= top) {\n resultIndex = mid;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n if (hunkLineCount == null) {\n return resultIndex >= 0 ? this.cache.checkpoints[resultIndex] : undefined;\n }\n\n for (let index = resultIndex; index >= 0; index--) {\n const checkpoint = this.cache.checkpoints[index];\n if (checkpoint == null) {\n throw new Error('VirtualizedFileDiff: invalid checkpoint index');\n }\n if (checkpoint.renderedLineIndex % hunkLineCount === 0) {\n return checkpoint;\n }\n }\n\n return undefined;\n }\n\n private getExpandedRegion(\n isPartial: boolean,\n hunkIndex: number,\n rangeSize: number\n ): ExpandedRegionSpecs {\n if (rangeSize <= 0 || isPartial) {\n return {\n fromStart: 0,\n fromEnd: 0,\n collapsedLines: Math.max(rangeSize, 0),\n renderAll: false,\n };\n }\n const {\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n if (expandUnchanged || rangeSize <= collapsedContextThreshold) {\n return {\n fromStart: rangeSize,\n fromEnd: 0,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n const region = this.hunksRenderer.getExpandedHunk(hunkIndex);\n const fromStart = Math.min(Math.max(region.fromStart, 0), rangeSize);\n const fromEnd = Math.min(Math.max(region.fromEnd, 0), rangeSize);\n const expandedCount = fromStart + fromEnd;\n const renderAll = expandedCount >= rangeSize;\n return {\n fromStart,\n fromEnd,\n collapsedLines: Math.max(rangeSize - expandedCount, 0),\n renderAll,\n };\n }\n\n private getExpandedLineCount(\n fileDiff: FileDiffMetadata,\n diffStyle: 'split' | 'unified'\n ): number {\n let count = 0;\n if (fileDiff.isPartial) {\n for (const hunk of fileDiff.hunks) {\n count +=\n diffStyle === 'split' ? hunk.splitLineCount : hunk.unifiedLineCount;\n }\n return count;\n }\n\n for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {\n const hunkCount =\n diffStyle === 'split' ? hunk.splitLineCount : hunk.unifiedLineCount;\n count += hunkCount;\n const collapsedBefore = Math.max(hunk.collapsedBefore, 0);\n const { fromStart, fromEnd, renderAll } = this.getExpandedRegion(\n fileDiff.isPartial,\n hunkIndex,\n collapsedBefore\n );\n if (collapsedBefore > 0) {\n count += renderAll ? collapsedBefore : fromStart + fromEnd;\n }\n }\n\n const lastHunk = fileDiff.hunks.at(-1);\n if (lastHunk != null && hasFinalHunk(fileDiff)) {\n const additionRemaining =\n fileDiff.additionLines.length -\n (lastHunk.additionLineIndex + lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n (lastHunk.deletionLineIndex + lastHunk.deletionCount);\n if (lastHunk != null && additionRemaining !== deletionRemaining) {\n throw new Error(\n `VirtualizedFileDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`\n );\n }\n const trailingRangeSize = Math.min(additionRemaining, deletionRemaining);\n if (lastHunk != null && trailingRangeSize > 0) {\n const { fromStart, renderAll } = this.getExpandedRegion(\n fileDiff.isPartial,\n fileDiff.hunks.length,\n trailingRangeSize\n );\n count += renderAll ? trailingRangeSize : fromStart;\n }\n }\n\n return count;\n }\n\n private computeRenderRangeFromWindow(\n fileDiff: FileDiffMetadata,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n hunkSeparators = 'line-info',\n } = this.options;\n const { spacing, hunkLineCount, hunkSeparatorHeight, lineHeight } =\n this.metrics;\n const diffStyle = this.getDiffStyle();\n const fileHeight = this.height;\n const lineCount =\n this.cache.totalLines > 0\n ? this.cache.totalLines\n : this.getExpandedLineCount(fileDiff, diffStyle);\n\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const paddingBottom =\n fileDiff.hunks.length > 0 ? getVirtualFilePaddingBottom(this.metrics) : 0;\n\n // File is outside render window\n if (fileTop < top - fileHeight || fileTop > bottom) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n\n // Whole file is under hunkLineCount, just render it all\n if (lineCount <= hunkLineCount || fileDiff.hunks.length === 0) {\n return {\n startingLine: 0,\n totalLines: hunkLineCount,\n bufferBefore: 0,\n bufferAfter: 0,\n };\n }\n const estimatedTargetLines = Math.ceil(\n Math.max(bottom - top, 0) / lineHeight\n );\n const totalLines =\n Math.ceil(estimatedTargetLines / hunkLineCount) * hunkLineCount +\n hunkLineCount;\n const totalHunks = totalLines / hunkLineCount;\n const overflowHunks = totalHunks;\n const hunkOffsets: number[] = [];\n // Halfway between top & bottom, represented as an absolute position\n const viewportCenter = (top + bottom) / 2;\n const separatorGap =\n hunkSeparators === 'simple' ||\n hunkSeparators === 'metadata' ||\n hunkSeparators === 'line-info-basic'\n ? 0\n : spacing;\n // Start the scan before the viewport so we collect hunk offsets that may be\n // needed for bufferBefore. This only chooses the scan origin; the returned\n // render range is still computed from the visible window below.\n const checkpoint = this.getLayoutCheckpointBeforeTop(\n Math.max(0, top - fileTop - totalLines * lineHeight * 2),\n hunkLineCount\n );\n\n let absoluteLineTop = fileTop + (checkpoint?.top ?? headerRegion);\n let currentLine = checkpoint?.renderedLineIndex ?? 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n iterateOverDiff({\n diff: fileDiff,\n diffStyle,\n startingLine: checkpoint?.renderedLineIndex ?? 0,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const splitLineIndex =\n additionLine != null\n ? additionLine.splitLineIndex\n : deletionLine.splitLineIndex;\n const unifiedLineIndex =\n additionLine != null\n ? additionLine.unifiedLineIndex\n : deletionLine.unifiedLineIndex;\n const hasMetadata =\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);\n let gapAdjustment =\n collapsedBefore > 0\n ? hunkSeparatorHeight +\n separatorGap +\n (hunkIndex > 0 ? separatorGap : 0)\n : 0;\n if (hunkIndex === 0 && hunkSeparators === 'simple') {\n gapAdjustment = 0;\n }\n\n absoluteLineTop += gapAdjustment;\n\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n const currentHunk = Math.floor(currentLine / hunkLineCount);\n\n // Track the boundary positional offset at a hunk\n if (isAtHunkBoundary) {\n hunkOffsets[currentHunk] =\n absoluteLineTop - (fileTop + headerRegion + gapAdjustment);\n\n // Check if we should bail (overflow complete)\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n return true;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(\n diffStyle === 'split' ? splitLineIndex : unifiedLineIndex,\n hasMetadata\n );\n\n // Track visible region\n if (absoluteLineTop > top - lineHeight && absoluteLineTop < bottom) {\n firstVisibleHunk ??= currentHunk;\n }\n\n // Track which hunk contains the viewport center\n // If viewport center is above this line and we haven't set centerHunk yet,\n // this is the first line at or past the center\n if (\n centerHunk == null &&\n absoluteLineTop + lineHeight > viewportCenter\n ) {\n centerHunk = currentHunk;\n }\n\n // Start overflow when we are out of the viewport at a hunk boundary\n if (\n overflowCounter == null &&\n absoluteLineTop >= bottom &&\n isAtHunkBoundary\n ) {\n overflowCounter = overflowHunks;\n }\n\n currentLine++;\n absoluteLineTop += lineHeight;\n\n if (collapsedAfter > 0 && hunkSeparators !== 'simple') {\n absoluteLineTop += hunkSeparatorHeight + separatorGap;\n }\n\n return false;\n },\n });\n\n // No visible lines found\n if (firstVisibleHunk == null) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n\n // Calculate balanced startingLine centered around the viewport center\n // Fall back to firstVisibleHunk if center wasn't found (e.g., center in a gap)\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift startHunk back\n const maxStartHunk = Math.max(\n 0,\n Math.ceil(lineCount / hunkLineCount) - totalHunks\n );\n const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));\n const startingLine = startHunk * hunkLineCount;\n\n // If we wanted to start before 0, reduce totalLines by the clamped amount\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n // Use hunkOffsets array for efficient buffer calculations\n const bufferBefore = hunkOffsets[startHunk] ?? 0;\n\n // Calculate bufferAfter using hunkOffset if available, otherwise use cumulative height\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? fileHeight -\n headerRegion -\n hunkOffsets[finalHunkIndex] -\n // We gotta subtract the bottom padding off of the buffer\n paddingBottom\n : // We stopped early, calculate from current position\n fileHeight -\n (absoluteLineTop - fileTop) -\n // We gotta subtract the bottom padding off of the buffer\n paddingBottom;\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n}\n\nfunction hasDiffLayoutOptionChanged<LAnnotation>(\n previousOptions: FileDiffOptions<LAnnotation>,\n nextOptions: FileDiffOptions<LAnnotation>\n): boolean {\n return (\n (previousOptions.diffStyle ?? 'split') !==\n (nextOptions.diffStyle ?? 'split') ||\n (previousOptions.overflow ?? 'scroll') !==\n (nextOptions.overflow ?? 'scroll') ||\n (previousOptions.collapsed ?? false) !== (nextOptions.collapsed ?? false) ||\n (previousOptions.disableLineNumbers ?? false) !==\n (nextOptions.disableLineNumbers ?? false) ||\n (previousOptions.disableFileHeader ?? false) !==\n (nextOptions.disableFileHeader ?? false) ||\n (previousOptions.diffIndicators ?? 'bars') !==\n (nextOptions.diffIndicators ?? 'bars') ||\n (previousOptions.hunkSeparators ?? 'line-info') !==\n (nextOptions.hunkSeparators ?? 'line-info') ||\n (previousOptions.expandUnchanged ?? false) !==\n (nextOptions.expandUnchanged ?? false) ||\n (previousOptions.collapsedContextThreshold ??\n DEFAULT_COLLAPSED_CONTEXT_THRESHOLD) !==\n (nextOptions.collapsedContextThreshold ??\n DEFAULT_COLLAPSED_CONTEXT_THRESHOLD) ||\n previousOptions.unsafeCSS !== nextOptions.unsafeCSS\n );\n}\n\nfunction hasFinalHunk(fileDiff: FileDiffMetadata): boolean {\n const lastHunk = fileDiff.hunks.at(-1);\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n return (\n lastHunk.additionLineIndex + lastHunk.additionCount <\n fileDiff.additionLines.length ||\n lastHunk.deletionLineIndex + lastHunk.deletionCount <\n fileDiff.deletionLines.length\n );\n}\n\n// Extracts the view-specific line index from the data-line-index attribute.\n// Format is \"unifiedIndex,splitIndex\"\nfunction parseLineIndex(\n lineIndexAttr: string,\n diffStyle: 'split' | 'unified'\n): number {\n const [unifiedIndex, splitIndex] = lineIndexAttr.split(',').map(Number);\n return diffStyle === 'split' ? splitIndex : unifiedIndex;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"VirtualizedFileDiff.js","names":["position: { top: number; height: number } | undefined","anchor: NumericScrollLineAnchor | undefined","result: DiffLayoutCheckpoint | undefined","hunkOffsets: number[]","firstVisibleHunk: number | undefined","centerHunk: number | undefined","overflowCounter: number | undefined","lineHeight"],"sources":["../../src/components/VirtualizedFileDiff.ts"],"sourcesContent":["import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } from '../constants';\nimport type {\n ExpansionDirections,\n FileDiffMetadata,\n HunkSeparators,\n NumericScrollLineAnchor,\n RenderRange,\n RenderWindow,\n SelectionSide,\n StickySpecs,\n VirtualFileMetrics,\n} from '../types';\nimport { areObjectsEqual } from '../utils/areObjectsEqual';\nimport { areOptionsEqual } from '../utils/areOptionsEqual';\nimport {\n computeVirtualFileMetrics,\n getDefaultHunkSeparatorHeight,\n getVirtualFileHeaderRegion,\n getVirtualFilePaddingBottom,\n} from '../utils/computeVirtualFileMetrics';\nimport { iterateOverDiff } from '../utils/iterateOverDiff';\nimport { parseDiffFromFile } from '../utils/parseDiffFromFile';\nimport type { WorkerPoolManager } from '../worker';\nimport type { CodeView } from './CodeView';\nimport {\n FileDiff,\n type FileDiffOptions,\n type FileDiffRenderProps,\n} from './FileDiff';\nimport type { Virtualizer } from './Virtualizer';\n\ninterface ExpandedRegionSpecs {\n fromStart: number;\n fromEnd: number;\n collapsedLines: number;\n renderAll: boolean;\n}\n\ninterface DiffLayoutCheckpoint {\n renderedLineIndex: number;\n lineIndex: number;\n top: number;\n}\n\ninterface DiffLayoutCache {\n // Sparse map: view-specific line index -> measured height. Only stores lines\n // that differ from what is returned by `getLineHeight`.\n heights: Map<number, number>;\n // Sparse measured positions used to resume deep geometry scans near a target\n // diff line, rendered row, or scroll offset instead of replaying layout from\n // the first hunk.\n checkpoints: DiffLayoutCheckpoint[];\n // Total renderable diff rows for the current diff style and expansion state.\n totalLines: number;\n}\n\nconst LAYOUT_CHECKPOINT_INTERVAL = 5_000;\n\nlet instanceId = -1;\n\nexport class VirtualizedFileDiff<\n LAnnotation = undefined,\n> extends FileDiff<LAnnotation> {\n override readonly __id: string = `little-virtualized-file-diff:${++instanceId}`;\n\n public top: number | undefined;\n public height: number = 0;\n private metrics: VirtualFileMetrics;\n private cache: DiffLayoutCache = {\n heights: new Map(),\n checkpoints: [],\n totalLines: 0,\n };\n private isVisible: boolean = false;\n private isSetup: boolean = false;\n private virtualizer: Virtualizer | CodeView<LAnnotation>;\n private layoutDirty = true;\n private forceRenderOverride: true | undefined;\n\n constructor(\n options: FileDiffOptions<LAnnotation> | undefined,\n virtualizer: Virtualizer | CodeView<LAnnotation>,\n metrics?: Partial<VirtualFileMetrics>,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\n this.virtualizer = virtualizer;\n this.metrics = computeVirtualFileMetrics(metrics);\n }\n\n public setMetrics(\n metrics?: Partial<VirtualFileMetrics>,\n force = false\n ): void {\n const nextMetrics = computeVirtualFileMetrics(metrics);\n if (!force && areObjectsEqual(this.metrics, nextMetrics)) {\n return;\n }\n\n this.metrics = nextMetrics;\n this.resetLayoutCache();\n }\n\n // Get the height for a line, using cached value if available.\n // If not cached and hasMetadataLine is true, adds lineHeight for the metadata.\n private getLineHeight(lineIndex: number, hasMetadataLine = false): number {\n const cached = this.cache.heights.get(lineIndex);\n if (cached != null) {\n return cached;\n }\n const multiplier = hasMetadataLine ? 2 : 1;\n return this.metrics.lineHeight * multiplier;\n }\n\n override setOptions(options: FileDiffOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n const { options: previousOptions } = this;\n const optionsChanged = !areOptionsEqual(previousOptions, options);\n const layoutChanged =\n optionsChanged && hasDiffLayoutOptionChanged(previousOptions, options);\n\n super.setOptions(options);\n\n if (layoutChanged) {\n this.resetLayoutCache(true);\n }\n // Any option can affect rendered DOM; only layout-affecting options clear\n // the measured height cache above.\n if (optionsChanged) {\n this.forceRenderOverride = true;\n }\n if (optionsChanged && this.isSimpleMode()) {\n this.virtualizer.instanceChanged(this, layoutChanged);\n }\n }\n\n private resetLayoutCache(recompute = false): void {\n this.layoutDirty = true;\n this.cache.heights.clear();\n this.cache.checkpoints = [];\n this.cache.totalLines = 0;\n this.renderRange = undefined;\n // NOTE(amadeus): In CodeView we intentionally batch computes to all happen\n // at the same time, so we shouldn't trigger this there.\n if (recompute && this.isSimpleMode()) {\n this.computeApproximateSize();\n }\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n // Definitely need to optimize this in cases where there aren't any custom\n // line heights or in cases of extremely large files...\n public reconcileHeights(): boolean {\n let hasHeightChange = false;\n const { overflow = 'scroll' } = this.options;\n if (this.fileContainer == null || this.fileDiff == null) {\n if (this.height !== 0) {\n hasHeightChange = true;\n }\n this.height = 0;\n return hasHeightChange;\n }\n this.top = this.getVirtualizedTop();\n // NOTE(amadeus): We can probably be a lot smarter about this, and we\n // should be thinking about ways to improve this\n // If the file has no annotations and we are using the scroll variant, then\n // we can probably skip everything\n if (\n overflow === 'scroll' &&\n this.lineAnnotations.length === 0 &&\n !this.isResizeDebuggingEnabled()\n ) {\n return hasHeightChange;\n }\n const diffStyle = this.getDiffStyle();\n const codeGroups =\n diffStyle === 'split'\n ? [this.codeDeletions, this.codeAdditions]\n : [this.codeUnified];\n\n for (const codeGroup of codeGroups) {\n if (codeGroup == null) continue;\n const content = codeGroup.children[1];\n if (!(content instanceof HTMLElement)) continue;\n for (const line of content.children) {\n if (!(line instanceof HTMLElement)) continue;\n\n const lineIndexAttr = line.dataset.lineIndex;\n if (lineIndexAttr == null) continue;\n\n const lineIndex = parseLineIndex(lineIndexAttr, diffStyle);\n let measuredHeight = line.getBoundingClientRect().height;\n let hasMetadata = false;\n // Annotations or noNewline metadata increase the size of the their\n // attached line\n if (\n line.nextElementSibling instanceof HTMLElement &&\n ('lineAnnotation' in line.nextElementSibling.dataset ||\n 'noNewline' in line.nextElementSibling.dataset)\n ) {\n if ('noNewline' in line.nextElementSibling.dataset) {\n hasMetadata = true;\n }\n measuredHeight +=\n line.nextElementSibling.getBoundingClientRect().height;\n }\n const expectedHeight = this.getLineHeight(lineIndex, hasMetadata);\n\n if (measuredHeight === expectedHeight) {\n continue;\n }\n\n hasHeightChange = true;\n // Line is back to standard height (e.g., after window resize)\n // Remove from cache\n if (\n measuredHeight ===\n this.metrics.lineHeight * (hasMetadata ? 2 : 1)\n ) {\n this.cache.heights.delete(lineIndex);\n }\n // Non-standard height, cache it\n else {\n this.cache.heights.set(lineIndex, measuredHeight);\n }\n }\n }\n\n if (hasHeightChange || this.isResizeDebuggingEnabled()) {\n this.computeApproximateSize(true);\n }\n return hasHeightChange;\n }\n\n public onRender = (dirty: boolean): boolean => {\n if (this.fileContainer == null) {\n return false;\n }\n if (dirty) {\n this.top = this.getVirtualizedTop();\n }\n return this.render();\n };\n\n // Prepares this item for CodeView layout by binding the latest diff, syncing\n // its virtualized top, and returning an approximate height. This method is\n // called while downstream items are being re-positioned, so later changes\n // should keep clean instances on a cached-height fast path.\n public prepareVirtualizedItem(fileDiff: FileDiffMetadata): number {\n if (this.fileDiff !== fileDiff) {\n this.layoutDirty = true;\n }\n this.fileDiff = fileDiff;\n this.top = this.getVirtualizedTop();\n this.computeApproximateSize();\n return this.height;\n }\n\n public getLinePosition(\n lineNumber: number,\n side: SelectionSide = 'additions'\n ): { top: number; height: number } | undefined {\n if (this.fileDiff == null) {\n return undefined;\n }\n\n const targetLineIndexes = this.getLineIndex(lineNumber, side);\n if (targetLineIndexes == null) {\n return undefined;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsed = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n const diffStyle = this.getDiffStyle();\n const hunkSeparators = this.getHunkSeparatorType();\n const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);\n const separatorGap = this.getSeparatorGap(hunkSeparators);\n const targetLineIndex =\n diffStyle === 'split' ? targetLineIndexes[1] : targetLineIndexes[0];\n const checkpoint = this.getLayoutCheckpointBeforeLineIndex(targetLineIndex);\n let top =\n checkpoint?.top ??\n getVirtualFileHeaderRegion(this.metrics, disableFileHeader);\n\n if (collapsed) {\n return { top, height: 0 };\n }\n\n let position: { top: number; height: number } | undefined;\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n startingLine: checkpoint?.renderedLineIndex ?? 0,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n hunk,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const lineIndex =\n diffStyle === 'split'\n ? (additionLine?.splitLineIndex ?? deletionLine?.splitLineIndex)\n : (additionLine?.unifiedLineIndex ??\n deletionLine?.unifiedLineIndex);\n if (lineIndex == null) {\n throw new Error(\n 'VirtualizedFileDiff.getLinePosition: missing line index data'\n );\n }\n\n if (\n collapsedBefore > 0 &&\n this.hasLeadingHunkSeparator(\n hunkIndex,\n hunk?.hunkSpecs,\n hunkSeparators\n )\n ) {\n if (hunkIndex > 0) {\n top += separatorGap;\n }\n if (\n targetLineIndex >= lineIndex - collapsedBefore &&\n targetLineIndex < lineIndex\n ) {\n position = {\n top,\n height: hunkSeparatorHeight,\n };\n return true;\n }\n top += hunkSeparatorHeight + separatorGap;\n }\n\n const lineHeight = this.getLineHeight(\n lineIndex,\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false)\n );\n if (lineIndex === targetLineIndex) {\n position = {\n top,\n height: lineHeight,\n };\n return true;\n }\n top += lineHeight;\n\n if (\n collapsedAfter > 0 &&\n this.hasTrailingHunkSeparator(hunkSeparators)\n ) {\n if (\n targetLineIndex > lineIndex &&\n targetLineIndex <= lineIndex + collapsedAfter\n ) {\n position = {\n top: top + separatorGap,\n height: hunkSeparatorHeight,\n };\n return true;\n }\n top += separatorGap + hunkSeparatorHeight;\n }\n\n return false;\n },\n });\n\n return position;\n }\n\n public getNumericScrollAnchor(\n localViewportTop: number\n ): NumericScrollLineAnchor | undefined {\n if (this.fileDiff == null) {\n return undefined;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsed = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n if (collapsed) {\n return undefined;\n }\n\n const diffStyle = this.getDiffStyle();\n const hunkSeparators = this.getHunkSeparatorType();\n const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);\n const separatorGap = this.getSeparatorGap(hunkSeparators);\n\n const checkpoint = this.getLayoutCheckpointBeforeTop(localViewportTop);\n let top =\n checkpoint?.top ??\n getVirtualFileHeaderRegion(this.metrics, disableFileHeader);\n let anchor: NumericScrollLineAnchor | undefined;\n\n // This may end up being quite expensive on extremely large files, we may\n // need to figure out how to anchor on different regions, or utilize\n // renderRange to shortcut this for us somehow\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n startingLine: checkpoint?.renderedLineIndex ?? 0,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n hunk,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const lineIndex =\n diffStyle === 'split'\n ? (additionLine?.splitLineIndex ?? deletionLine?.splitLineIndex)\n : (additionLine?.unifiedLineIndex ??\n deletionLine?.unifiedLineIndex);\n if (lineIndex == null) {\n throw new Error(\n 'VirtualizedFileDiff.getNumericScrollAnchor: missing line index data'\n );\n }\n\n if (\n collapsedBefore > 0 &&\n this.hasLeadingHunkSeparator(\n hunkIndex,\n hunk?.hunkSpecs,\n hunkSeparators\n )\n ) {\n if (hunkIndex > 0) {\n top += separatorGap;\n }\n top += hunkSeparatorHeight + separatorGap;\n }\n\n if (top >= localViewportTop) {\n if (deletionLine != null) {\n anchor = {\n lineNumber: deletionLine.lineNumber,\n side: 'deletions',\n top,\n };\n } else if (additionLine != null) {\n anchor = {\n lineNumber: additionLine.lineNumber,\n side: 'additions',\n top,\n };\n }\n if (anchor != null) {\n return true;\n }\n }\n\n const lineHeight = this.getLineHeight(\n lineIndex,\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false)\n );\n top += lineHeight;\n\n if (\n collapsedAfter > 0 &&\n this.hasTrailingHunkSeparator(hunkSeparators)\n ) {\n top += separatorGap + hunkSeparatorHeight;\n }\n\n return false;\n },\n });\n\n return anchor;\n }\n\n public getVirtualizedHeight(): number {\n return this.height;\n }\n\n public getAdvancedStickySpecs(\n windowSpecs?: RenderWindow\n ): StickySpecs | undefined {\n if (this.top == null || this.fileDiff == null) {\n return undefined;\n }\n if (this.options.collapsed === true) {\n return { topOffset: this.top, height: this.height };\n }\n const renderRange =\n windowSpecs != null\n ? this.computeRenderRangeFromWindow(\n this.fileDiff,\n this.top,\n windowSpecs\n )\n : this.renderRange;\n if (renderRange == null) {\n return undefined;\n }\n const { bufferBefore, bufferAfter, totalLines } = renderRange;\n return {\n topOffset: this.top + bufferBefore + (totalLines === 0 ? bufferAfter : 0),\n height: this.height - (bufferBefore + bufferAfter),\n };\n }\n\n override cleanUp(recycle = false): void {\n if (this.fileContainer != null && this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.disconnect(this.fileContainer);\n }\n if (!recycle) {\n this.layoutDirty = true;\n }\n this.isSetup = false;\n super.cleanUp(recycle);\n }\n\n override expandHunk = (\n hunkIndex: number,\n direction: ExpansionDirections,\n expansionLineCountOverride?: number\n ): void => {\n this.hunksRenderer.expandHunk(\n hunkIndex,\n direction,\n expansionLineCountOverride\n );\n this.layoutDirty = true;\n this.computeApproximateSize();\n this.renderRange = undefined;\n this.virtualizer.instanceChanged(this, true);\n };\n\n public setVisibility(visible: boolean): void {\n if (this.isAdvancedMode() || this.fileContainer == null) {\n return;\n }\n this.renderRange = undefined;\n if (visible && !this.isVisible) {\n this.top = this.getVirtualizedTop();\n this.isVisible = true;\n } else if (!visible && this.isVisible) {\n this.isVisible = false;\n this.rerender();\n }\n }\n\n override rerender(): void {\n if (\n !this.enabled ||\n (this.fileDiff == null &&\n this.additionFile == null &&\n this.deletionFile == null)\n ) {\n return;\n }\n this.forceRenderOverride = true;\n this.virtualizer.instanceChanged(this, false);\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\n // We should probably optimize this if there are no custom line heights...\n // The reason we refer to this as `approximate size` is because heights my\n // dynamically change for a number of reasons so we can never be fully sure\n // if the height is 100% accurate\n private computeApproximateSize(force = false): void {\n const shouldValidateSize = this.isResizeDebuggingEnabled();\n if (!force && !this.layoutDirty && !shouldValidateSize) {\n return;\n }\n\n const isFirstCompute = this.height === 0;\n this.height = 0;\n this.cache.checkpoints = [];\n this.cache.totalLines = 0;\n if (this.fileDiff == null) {\n this.layoutDirty = false;\n return;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsed = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n const diffStyle = this.getDiffStyle();\n const hunkSeparators = this.getHunkSeparatorType();\n const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);\n const separatorGap = this.getSeparatorGap(hunkSeparators);\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const paddingBottom = getVirtualFilePaddingBottom(this.metrics);\n\n this.height += headerRegion;\n if (collapsed) {\n this.layoutDirty = false;\n return;\n }\n\n let renderedLineIndex = 0;\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n hunk,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const splitLineIndex =\n additionLine != null\n ? additionLine.splitLineIndex\n : deletionLine.splitLineIndex;\n const unifiedLineIndex =\n additionLine != null\n ? additionLine.unifiedLineIndex\n : deletionLine.unifiedLineIndex;\n const hasMetadata =\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);\n const lineIndex =\n diffStyle === 'split' ? splitLineIndex : unifiedLineIndex;\n this.addLayoutCheckpoint(renderedLineIndex, lineIndex, this.height);\n if (\n collapsedBefore > 0 &&\n this.hasLeadingHunkSeparator(\n hunkIndex,\n hunk?.hunkSpecs,\n hunkSeparators\n )\n ) {\n if (hunkIndex > 0) {\n this.height += separatorGap;\n }\n this.height += hunkSeparatorHeight + separatorGap;\n }\n\n this.height += this.getLineHeight(lineIndex, hasMetadata);\n\n if (\n collapsedAfter > 0 &&\n this.hasTrailingHunkSeparator(hunkSeparators)\n ) {\n this.height += separatorGap + hunkSeparatorHeight;\n }\n renderedLineIndex++;\n },\n });\n this.cache.totalLines = renderedLineIndex;\n\n // Bottom padding\n if (this.fileDiff.hunks.length > 0) {\n this.height += paddingBottom;\n }\n\n if (this.fileContainer != null && shouldValidateSize && !isFirstCompute) {\n const rect = this.fileContainer.getBoundingClientRect();\n if (rect.height !== this.height) {\n console.log(\n 'VirtualizedFileDiff.computeApproximateSize: computed height doesnt match',\n {\n name: this.fileDiff.name,\n elementHeight: rect.height,\n computedHeight: this.height,\n }\n );\n } else {\n console.log(\n 'VirtualizedFileDiff.computeApproximateSize: computed height IS CORRECT'\n );\n }\n }\n this.layoutDirty = false;\n }\n\n override render({\n fileContainer,\n oldFile,\n newFile,\n fileDiff,\n forceRender = false,\n ...props\n }: FileDiffRenderProps<LAnnotation> = {}): boolean {\n const { forceRenderOverride, isSetup } = this;\n this.forceRenderOverride = undefined;\n\n this.fileDiff ??=\n fileDiff ??\n (oldFile != null && newFile != null\n ? // NOTE(amadeus): We might be forcing ourselves to double up the\n // computation of fileDiff (in the super.render() call), so we might want\n // to figure out a way to avoid that. That also could be just as simple as\n // passing through fileDiff though... so maybe we good?\n parseDiffFromFile(oldFile, newFile, this.options.parseDiffOptions)\n : undefined);\n\n fileContainer = this.getOrCreateFileContainer(fileContainer);\n\n if (this.fileDiff == null) {\n console.error(\n 'VirtualizedFileDiff.render: attempting to virtually render when we dont have the correct data'\n );\n return false;\n }\n\n if (!isSetup) {\n this.computeApproximateSize();\n const virtualizer = this.getSimpleVirtualizer();\n this.top ??= this.getVirtualizedTop();\n if (this.isAdvancedMode()) {\n this.isVisible = true;\n } else {\n if (virtualizer == null) {\n throw new Error(\n 'VirtualizedFileDiff.render: simple virtualizer is not available'\n );\n }\n virtualizer.connect(fileContainer, this);\n this.isVisible = virtualizer.isInstanceVisible(\n this.top ?? 0,\n this.height\n );\n }\n this.isSetup = true;\n } else {\n this.top ??= this.getVirtualizedTop();\n }\n\n if (!this.isVisible && this.isSimpleMode()) {\n return this.renderPlaceholder(this.height);\n }\n\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const fileTop = this.top ?? 0;\n const renderRange = this.computeRenderRangeFromWindow(\n this.fileDiff,\n fileTop,\n windowSpecs\n );\n return super.render({\n fileDiff: this.fileDiff,\n fileContainer,\n renderRange,\n oldFile,\n newFile,\n forceRender: forceRenderOverride ?? forceRender,\n ...props,\n });\n }\n\n public syncVirtualizedTop(): void {\n this.top = this.getVirtualizedTop();\n }\n\n protected override shouldDisableVirtualizationBuffers(): boolean {\n return this.isAdvancedMode() || super.shouldDisableVirtualizationBuffers();\n }\n\n private isSimpleMode(): boolean {\n return this.virtualizer.type === 'simple';\n }\n\n private isAdvancedMode(): boolean {\n return this.virtualizer.type === 'advanced';\n }\n\n private getVirtualizedTop(): number | undefined {\n if (this.virtualizer.type === 'advanced') {\n return this.virtualizer.getLocalTopForInstance(this);\n }\n return this.fileContainer != null\n ? this.virtualizer.getOffsetInScrollContainer(this.fileContainer)\n : 0;\n }\n\n private getSimpleVirtualizer(): Virtualizer | undefined {\n return this.virtualizer.type === 'simple' ? this.virtualizer : undefined;\n }\n\n private isResizeDebuggingEnabled(): boolean {\n return this.getSimpleVirtualizer()?.config.resizeDebugging ?? false;\n }\n\n private getDiffStyle(): 'split' | 'unified' {\n return this.options.diffStyle ?? 'split';\n }\n\n private getHunkSeparatorType(): HunkSeparators {\n return getOptionHunkSeparatorType(this.options.hunkSeparators);\n }\n\n private getHunkSeparatorHeight(type = this.getHunkSeparatorType()): number {\n return (\n this.metrics.hunkSeparatorHeight ?? getDefaultHunkSeparatorHeight(type)\n );\n }\n\n private getSeparatorGap(type = this.getHunkSeparatorType()): number {\n return type === 'simple' ||\n type === 'metadata' ||\n type === 'line-info-basic'\n ? 0\n : this.metrics.spacing;\n }\n\n private hasLeadingHunkSeparator(\n hunkIndex: number,\n hunkSpecs: string | undefined,\n type = this.getHunkSeparatorType()\n ): boolean {\n switch (type) {\n case 'simple':\n return hunkIndex > 0;\n case 'metadata':\n return hunkSpecs != null;\n case 'line-info':\n case 'line-info-basic':\n case 'custom':\n return true;\n }\n }\n\n private hasTrailingHunkSeparator(\n type = this.getHunkSeparatorType()\n ): boolean {\n return type !== 'simple' && type !== 'metadata';\n }\n\n private addLayoutCheckpoint(\n renderedLineIndex: number,\n lineIndex: number,\n top: number\n ): void {\n if (renderedLineIndex % LAYOUT_CHECKPOINT_INTERVAL !== 0) {\n return;\n }\n this.cache.checkpoints.push({ renderedLineIndex, lineIndex, top });\n }\n\n // Find the nearest sparse layout checkpoint at or before an active\n // diff-style line index. Diff checkpoints also store the dense rendered-row\n // index, so deep line-position lookups can resume iteration from that\n // rendered row and replay only the nearby layout work instead of walking\n // from the first hunk.\n private getLayoutCheckpointBeforeLineIndex(\n lineIndex: number\n ): DiffLayoutCheckpoint | undefined {\n if (lineIndex <= 0 || this.cache.checkpoints.length === 0) {\n return undefined;\n }\n\n let low = 0;\n let high = this.cache.checkpoints.length - 1;\n let result: DiffLayoutCheckpoint | undefined;\n\n while (low <= high) {\n const mid = (low + high) >> 1;\n const checkpoint = this.cache.checkpoints[mid];\n if (checkpoint == null) {\n throw new Error('VirtualizedFileDiff: invalid checkpoint index');\n }\n if (checkpoint.lineIndex <= lineIndex) {\n result = checkpoint;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return result;\n }\n\n // Find the nearest sparse layout checkpoint at or before a scroll offset.\n // Render-range scans start from this checkpoint so variable-height diffs\n // only replay nearby rows. When `hunkLineCount` is provided, step backward\n // to a rendered hunk boundary so buffer calculations can reuse absolute hunk\n // offsets safely.\n private getLayoutCheckpointBeforeTop(\n top: number,\n hunkLineCount?: number\n ): DiffLayoutCheckpoint | undefined {\n let low = 0;\n let high = this.cache.checkpoints.length - 1;\n let resultIndex = -1;\n\n while (low <= high) {\n const mid = (low + high) >> 1;\n const checkpoint = this.cache.checkpoints[mid];\n if (checkpoint == null) {\n throw new Error('VirtualizedFileDiff: invalid checkpoint index');\n }\n if (checkpoint.top <= top) {\n resultIndex = mid;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n if (hunkLineCount == null) {\n return resultIndex >= 0 ? this.cache.checkpoints[resultIndex] : undefined;\n }\n\n for (let index = resultIndex; index >= 0; index--) {\n const checkpoint = this.cache.checkpoints[index];\n if (checkpoint == null) {\n throw new Error('VirtualizedFileDiff: invalid checkpoint index');\n }\n if (checkpoint.renderedLineIndex % hunkLineCount === 0) {\n return checkpoint;\n }\n }\n\n return undefined;\n }\n\n private getExpandedRegion(\n isPartial: boolean,\n hunkIndex: number,\n rangeSize: number\n ): ExpandedRegionSpecs {\n if (rangeSize <= 0 || isPartial) {\n return {\n fromStart: 0,\n fromEnd: 0,\n collapsedLines: Math.max(rangeSize, 0),\n renderAll: false,\n };\n }\n const {\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n if (expandUnchanged || rangeSize <= collapsedContextThreshold) {\n return {\n fromStart: rangeSize,\n fromEnd: 0,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n const region = this.hunksRenderer.getExpandedHunk(hunkIndex);\n const fromStart = Math.min(Math.max(region.fromStart, 0), rangeSize);\n const fromEnd = Math.min(Math.max(region.fromEnd, 0), rangeSize);\n const expandedCount = fromStart + fromEnd;\n const renderAll = expandedCount >= rangeSize;\n return {\n fromStart,\n fromEnd,\n collapsedLines: Math.max(rangeSize - expandedCount, 0),\n renderAll,\n };\n }\n\n private getExpandedLineCount(\n fileDiff: FileDiffMetadata,\n diffStyle: 'split' | 'unified'\n ): number {\n let count = 0;\n if (fileDiff.isPartial) {\n for (const hunk of fileDiff.hunks) {\n count +=\n diffStyle === 'split' ? hunk.splitLineCount : hunk.unifiedLineCount;\n }\n return count;\n }\n\n for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {\n const hunkCount =\n diffStyle === 'split' ? hunk.splitLineCount : hunk.unifiedLineCount;\n count += hunkCount;\n const collapsedBefore = Math.max(hunk.collapsedBefore, 0);\n const { fromStart, fromEnd, renderAll } = this.getExpandedRegion(\n fileDiff.isPartial,\n hunkIndex,\n collapsedBefore\n );\n if (collapsedBefore > 0) {\n count += renderAll ? collapsedBefore : fromStart + fromEnd;\n }\n }\n\n const lastHunk = fileDiff.hunks.at(-1);\n if (lastHunk != null && hasFinalHunk(fileDiff)) {\n const additionRemaining =\n fileDiff.additionLines.length -\n (lastHunk.additionLineIndex + lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n (lastHunk.deletionLineIndex + lastHunk.deletionCount);\n if (lastHunk != null && additionRemaining !== deletionRemaining) {\n throw new Error(\n `VirtualizedFileDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`\n );\n }\n const trailingRangeSize = Math.min(additionRemaining, deletionRemaining);\n if (lastHunk != null && trailingRangeSize > 0) {\n const { fromStart, renderAll } = this.getExpandedRegion(\n fileDiff.isPartial,\n fileDiff.hunks.length,\n trailingRangeSize\n );\n count += renderAll ? trailingRangeSize : fromStart;\n }\n }\n\n return count;\n }\n\n private computeRenderRangeFromWindow(\n fileDiff: FileDiffMetadata,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n const { hunkLineCount, lineHeight } = this.metrics;\n const diffStyle = this.getDiffStyle();\n const hunkSeparators = this.getHunkSeparatorType();\n const hunkSeparatorHeight = this.getHunkSeparatorHeight(hunkSeparators);\n const fileHeight = this.height;\n const lineCount =\n this.cache.totalLines > 0\n ? this.cache.totalLines\n : this.getExpandedLineCount(fileDiff, diffStyle);\n\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const paddingBottom =\n fileDiff.hunks.length > 0 ? getVirtualFilePaddingBottom(this.metrics) : 0;\n\n // File is outside render window\n if (fileTop < top - fileHeight || fileTop > bottom) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n\n // Whole file is under hunkLineCount, just render it all\n if (lineCount <= hunkLineCount || fileDiff.hunks.length === 0) {\n return {\n startingLine: 0,\n totalLines: hunkLineCount,\n bufferBefore: 0,\n bufferAfter: 0,\n };\n }\n const estimatedTargetLines = Math.ceil(\n Math.max(bottom - top, 0) / lineHeight\n );\n const totalLines =\n Math.ceil(estimatedTargetLines / hunkLineCount) * hunkLineCount +\n hunkLineCount;\n const totalHunks = totalLines / hunkLineCount;\n const overflowHunks = totalHunks;\n const hunkOffsets: number[] = [];\n // Halfway between top & bottom, represented as an absolute position\n const viewportCenter = (top + bottom) / 2;\n const separatorGap = this.getSeparatorGap(hunkSeparators);\n // Start the scan before the viewport so we collect hunk offsets that may be\n // needed for bufferBefore. This only chooses the scan origin; the returned\n // render range is still computed from the visible window below.\n const checkpoint = this.getLayoutCheckpointBeforeTop(\n Math.max(0, top - fileTop - totalLines * lineHeight * 2),\n hunkLineCount\n );\n\n let absoluteLineTop = fileTop + (checkpoint?.top ?? headerRegion);\n let currentLine = checkpoint?.renderedLineIndex ?? 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n iterateOverDiff({\n diff: fileDiff,\n diffStyle,\n startingLine: checkpoint?.renderedLineIndex ?? 0,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n hunk,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const splitLineIndex =\n additionLine != null\n ? additionLine.splitLineIndex\n : deletionLine.splitLineIndex;\n const unifiedLineIndex =\n additionLine != null\n ? additionLine.unifiedLineIndex\n : deletionLine.unifiedLineIndex;\n const hasMetadata =\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);\n const gapAdjustment =\n collapsedBefore > 0 &&\n this.hasLeadingHunkSeparator(\n hunkIndex,\n hunk?.hunkSpecs,\n hunkSeparators\n )\n ? hunkSeparatorHeight +\n separatorGap +\n (hunkIndex > 0 ? separatorGap : 0)\n : 0;\n\n absoluteLineTop += gapAdjustment;\n\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n const currentHunk = Math.floor(currentLine / hunkLineCount);\n\n // Track the boundary positional offset at a hunk\n if (isAtHunkBoundary) {\n hunkOffsets[currentHunk] =\n absoluteLineTop - (fileTop + headerRegion + gapAdjustment);\n\n // Check if we should bail (overflow complete)\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n return true;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(\n diffStyle === 'split' ? splitLineIndex : unifiedLineIndex,\n hasMetadata\n );\n\n // Track visible region\n if (absoluteLineTop > top - lineHeight && absoluteLineTop < bottom) {\n firstVisibleHunk ??= currentHunk;\n }\n\n // Track which hunk contains the viewport center\n // If viewport center is above this line and we haven't set centerHunk yet,\n // this is the first line at or past the center\n if (\n centerHunk == null &&\n absoluteLineTop + lineHeight > viewportCenter\n ) {\n centerHunk = currentHunk;\n }\n\n // Start overflow when we are out of the viewport at a hunk boundary\n if (\n overflowCounter == null &&\n absoluteLineTop >= bottom &&\n isAtHunkBoundary\n ) {\n overflowCounter = overflowHunks;\n }\n\n currentLine++;\n absoluteLineTop += lineHeight;\n\n if (\n collapsedAfter > 0 &&\n this.hasTrailingHunkSeparator(hunkSeparators)\n ) {\n absoluteLineTop += hunkSeparatorHeight + separatorGap;\n }\n\n return false;\n },\n });\n\n // No visible lines found\n if (firstVisibleHunk == null) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n\n // Calculate balanced startingLine centered around the viewport center\n // Fall back to firstVisibleHunk if center wasn't found (e.g., center in a gap)\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift startHunk back\n const maxStartHunk = Math.max(\n 0,\n Math.ceil(lineCount / hunkLineCount) - totalHunks\n );\n const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));\n const startingLine = startHunk * hunkLineCount;\n\n // If we wanted to start before 0, reduce totalLines by the clamped amount\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n // Use hunkOffsets array for efficient buffer calculations\n const bufferBefore = hunkOffsets[startHunk] ?? 0;\n\n // Calculate bufferAfter using hunkOffset if available, otherwise use cumulative height\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? fileHeight -\n headerRegion -\n hunkOffsets[finalHunkIndex] -\n // We gotta subtract the bottom padding off of the buffer\n paddingBottom\n : // We stopped early, calculate from current position\n fileHeight -\n (absoluteLineTop - fileTop) -\n // We gotta subtract the bottom padding off of the buffer\n paddingBottom;\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n}\n\nfunction hasDiffLayoutOptionChanged<LAnnotation>(\n previousOptions: FileDiffOptions<LAnnotation>,\n nextOptions: FileDiffOptions<LAnnotation>\n): boolean {\n return (\n (previousOptions.diffStyle ?? 'split') !==\n (nextOptions.diffStyle ?? 'split') ||\n (previousOptions.overflow ?? 'scroll') !==\n (nextOptions.overflow ?? 'scroll') ||\n (previousOptions.collapsed ?? false) !== (nextOptions.collapsed ?? false) ||\n (previousOptions.disableLineNumbers ?? false) !==\n (nextOptions.disableLineNumbers ?? false) ||\n (previousOptions.disableFileHeader ?? false) !==\n (nextOptions.disableFileHeader ?? false) ||\n (previousOptions.diffIndicators ?? 'bars') !==\n (nextOptions.diffIndicators ?? 'bars') ||\n (previousOptions.hunkSeparators ?? 'line-info') !==\n (nextOptions.hunkSeparators ?? 'line-info') ||\n (previousOptions.expandUnchanged ?? false) !==\n (nextOptions.expandUnchanged ?? false) ||\n (previousOptions.collapsedContextThreshold ??\n DEFAULT_COLLAPSED_CONTEXT_THRESHOLD) !==\n (nextOptions.collapsedContextThreshold ??\n DEFAULT_COLLAPSED_CONTEXT_THRESHOLD) ||\n previousOptions.unsafeCSS !== nextOptions.unsafeCSS\n );\n}\n\nfunction getOptionHunkSeparatorType<LAnnotation>(\n hunkSeparators: FileDiffOptions<LAnnotation>['hunkSeparators'] | undefined\n): HunkSeparators {\n return typeof hunkSeparators === 'function'\n ? 'custom'\n : (hunkSeparators ?? 'line-info');\n}\n\nfunction hasFinalHunk(fileDiff: FileDiffMetadata): boolean {\n const lastHunk = fileDiff.hunks.at(-1);\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n return (\n lastHunk.additionLineIndex + lastHunk.additionCount <\n fileDiff.additionLines.length ||\n lastHunk.deletionLineIndex + lastHunk.deletionCount <\n fileDiff.deletionLines.length\n );\n}\n\n// Extracts the view-specific line index from the data-line-index attribute.\n// Format is \"unifiedIndex,splitIndex\"\nfunction parseLineIndex(\n lineIndexAttr: string,\n diffStyle: 'split' | 'unified'\n): number {\n const [unifiedIndex, splitIndex] = lineIndexAttr.split(',').map(Number);\n return diffStyle === 'split' ? splitIndex : unifiedIndex;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","names":["CodeViewLayout","HunkExpansionRegion","RenderRange","SmoothScrollSettings","ThemesType","VirtualFileMetrics","DIFFS_TAG_NAME","DIFFS_DEVELOPMENT_BUILD","COMMIT_METADATA_SPLIT","RegExp","GIT_DIFF_FILE_BREAK_REGEX","UNIFIED_DIFF_FILE_BREAK_REGEX","FILE_CONTEXT_BLOB","HUNK_HEADER","SPLIT_WITH_NEWLINES","FILENAME_HEADER_REGEX","FILENAME_HEADER_REGEX_GIT","ALTERNATE_FILE_NAMES_GIT","INDEX_LINE_METADATA","MERGE_CONFLICT_START_MARKER_REGEX","MERGE_CONFLICT_BASE_MARKER_REGEX","MERGE_CONFLICT_SEPARATOR_MARKER_REGEX","MERGE_CONFLICT_END_MARKER_REGEX","HEADER_PREFIX_SLOT_ID","HEADER_METADATA_SLOT_ID","CUSTOM_HEADER_SLOT_ID","DEFAULT_THEMES","THEME_CSS_ATTRIBUTE","UNSAFE_CSS_ATTRIBUTE","CORE_CSS_ATTRIBUTE","DIFFS_SCROLLBAR_MEASURE_ATTRIBUTE","DIFFS_SCROLLBAR_GUTTER_MEASURED_PROPERTY","DEFAULT_COLLAPSED_CONTEXT_THRESHOLD","DEFAULT_TOKENIZE_MAX_LENGTH","DEFAULT_VIRTUAL_FILE_METRICS","DEFAULT_CODE_VIEW_FILE_METRICS","DEFAULT_CODE_VIEW_LAYOUT","DEFAULT_SMOOTH_SCROLL_SETTINGS","DEFAULT_EXPANDED_REGION","DEFAULT_RENDER_RANGE","EMPTY_RENDER_RANGE"],"sources":["../src/constants.d.ts"],"sourcesContent":["import type { CodeViewLayout, HunkExpansionRegion, RenderRange, SmoothScrollSettings, ThemesType, VirtualFileMetrics } from './types';\nexport declare const DIFFS_TAG_NAME: \"diffs-container\";\nexport declare const DIFFS_DEVELOPMENT_BUILD: boolean;\nexport declare const COMMIT_METADATA_SPLIT: RegExp;\nexport declare const GIT_DIFF_FILE_BREAK_REGEX: RegExp;\nexport declare const UNIFIED_DIFF_FILE_BREAK_REGEX: RegExp;\nexport declare const FILE_CONTEXT_BLOB: RegExp;\nexport declare const HUNK_HEADER: RegExp;\nexport declare const SPLIT_WITH_NEWLINES: RegExp;\nexport declare const FILENAME_HEADER_REGEX: RegExp;\nexport declare const FILENAME_HEADER_REGEX_GIT: RegExp;\nexport declare const ALTERNATE_FILE_NAMES_GIT: RegExp;\nexport declare const INDEX_LINE_METADATA: RegExp;\nexport declare const MERGE_CONFLICT_START_MARKER_REGEX: RegExp;\nexport declare const MERGE_CONFLICT_BASE_MARKER_REGEX: RegExp;\nexport declare const MERGE_CONFLICT_SEPARATOR_MARKER_REGEX: RegExp;\nexport declare const MERGE_CONFLICT_END_MARKER_REGEX: RegExp;\nexport declare const HEADER_PREFIX_SLOT_ID = \"header-prefix\";\nexport declare const HEADER_METADATA_SLOT_ID = \"header-metadata\";\nexport declare const CUSTOM_HEADER_SLOT_ID = \"header-custom\";\nexport declare const DEFAULT_THEMES: ThemesType;\nexport declare const THEME_CSS_ATTRIBUTE = \"data-theme-css\";\nexport declare const UNSAFE_CSS_ATTRIBUTE = \"data-unsafe-css\";\nexport declare const CORE_CSS_ATTRIBUTE = \"data-core-css\";\nexport declare const DIFFS_SCROLLBAR_MEASURE_ATTRIBUTE = \"data-diffs-scrollbar-measure\";\nexport declare const DIFFS_SCROLLBAR_GUTTER_MEASURED_PROPERTY = \"--diffs-scrollbar-gutter-measured\";\nexport declare const DEFAULT_COLLAPSED_CONTEXT_THRESHOLD = 1;\nexport declare const DEFAULT_TOKENIZE_MAX_LENGTH = 100000;\nexport declare const DEFAULT_VIRTUAL_FILE_METRICS: VirtualFileMetrics;\nexport declare const DEFAULT_CODE_VIEW_FILE_METRICS: VirtualFileMetrics;\nexport declare const DEFAULT_CODE_VIEW_LAYOUT: CodeViewLayout;\nexport declare const DEFAULT_SMOOTH_SCROLL_SETTINGS: SmoothScrollSettings;\nexport declare const DEFAULT_EXPANDED_REGION: HunkExpansionRegion;\nexport declare const DEFAULT_RENDER_RANGE: RenderRange;\nexport declare const EMPTY_RENDER_RANGE: RenderRange;\n//# sourceMappingURL=constants.d.ts.map"],"mappings":";;;cACqBM;cACAC;AADAD,cAEAE,qBAFiC,EAEVC,MAFU;AACjCF,cAEAG,yBAFgC,EAELD,MAFK;AAChCD,cAEAG,6BAF6B,EAEEF,MAFF;AAC7BC,cAEAE,iBAFiC,EAEdH,MAFQA;AAC3BE,cAEAE,WAFAF,EAEaF,MAFwB;AACrCG,cAEAE,mBAFmBL,EAEEA,MAFI;AACzBI,cAEAE,qBAFmB,EAEIN,MAFJ;AACnBK,cAEAE,yBAF2B,EAEAP,MAFA;AAC3BM,cAEAE,wBAFuBR,EAEGA,MAFG;AAC7BO,cAEAE,mBAFiC,EAEZT,MAFMA;AAC3BQ,cAEAE,iCAFgC,EAEGV,MAFH;AAChCS,cAEAE,gCAF2B,EAEOX,MAFP;AAC3BU,cAEAE,qCAFmCZ,EAEIA,MAFE;AACzCW,cAEAE,+BAFkCb,EAEDA,MAFO;AACxCY,cAEAE,qBAAAA,GAF6C,eAANd;AACvCa,cAEAE,uBAAAA,GAFuC,iBAAA;AACvCD,cAEAE,qBAAAA,GAFqB,eAAA;AACrBD,cAEAE,cAFuB,EAEPtB,UAFO;AACvBqB,cAEAE,mBAAAA,GAFqB,gBAAA;AACrBD,cAEAE,oBAAAA,GAF0B,iBAAA;AAC1BD,cAEAE,kBAAAA,GAFmB,eAAA;AACnBD,cAEAE,iCAAAA,GAFoB,8BAAA;AACpBD,cAEAE,wCAAAA,GAFkB,mCAAA;AAClBD,cAEAE,mCAAAA,GAFiC,CAAA;AACjCD,cAEAE,2BAAAA,GAFwC,MAAA;AACxCD,cAEAE,4BAFmC,EAEL7B,kBAFK;AACnC4B,cAEAE,8BAF2B,EAEK9B,kBAFL;AAC3B6B,cAEAE,wBAFgD,EAEtBpC,cAFIK;AAC9B8B,cAEAE,8BAFgChC,EAEAF,oBAFkB;AAClDiC,cAEAE,uBAF0BtC,EAEDC,mBAFe;AACxCoC,cAEAE,oBAFoD,EAE9BrC,WAFUC;AAChCmC,cAEAE,kBAF4C,EAExBtC,WAFKD"}
1
+ {"version":3,"file":"constants.d.ts","names":["CodeViewLayout","HunkExpansionRegion","RenderRange","SmoothScrollSettings","ThemesType","VirtualFileMetrics","DIFFS_TAG_NAME","DIFFS_DEVELOPMENT_BUILD","COMMIT_METADATA_SPLIT","RegExp","GIT_DIFF_FILE_BREAK_REGEX","UNIFIED_DIFF_FILE_BREAK_REGEX","FILE_CONTEXT_BLOB","HUNK_HEADER","SPLIT_WITH_NEWLINES","FILENAME_HEADER_REGEX","FILENAME_HEADER_REGEX_GIT","ALTERNATE_FILE_NAMES_GIT","INDEX_LINE_METADATA","MERGE_CONFLICT_START_MARKER_REGEX","MERGE_CONFLICT_BASE_MARKER_REGEX","MERGE_CONFLICT_SEPARATOR_MARKER_REGEX","MERGE_CONFLICT_END_MARKER_REGEX","HEADER_PREFIX_SLOT_ID","HEADER_METADATA_SLOT_ID","CUSTOM_HEADER_SLOT_ID","DEFAULT_THEMES","THEME_CSS_ATTRIBUTE","UNSAFE_CSS_ATTRIBUTE","CORE_CSS_ATTRIBUTE","DIFFS_SCROLLBAR_MEASURE_ATTRIBUTE","DIFFS_SCROLLBAR_GUTTER_MEASURED_PROPERTY","DEFAULT_COLLAPSED_CONTEXT_THRESHOLD","DEFAULT_TOKENIZE_MAX_LENGTH","DEFAULT_VIRTUAL_FILE_METRICS","DEFAULT_CODE_VIEW_FILE_METRICS","DEFAULT_CODE_VIEW_LAYOUT","DEFAULT_SMOOTH_SCROLL_SETTINGS","DEFAULT_EXPANDED_REGION","DEFAULT_RENDER_RANGE","EMPTY_RENDER_RANGE"],"sources":["../src/constants.d.ts"],"sourcesContent":["import type { CodeViewLayout, HunkExpansionRegion, RenderRange, SmoothScrollSettings, ThemesType, VirtualFileMetrics } from './types';\nexport declare const DIFFS_TAG_NAME: \"diffs-container\";\nexport declare const DIFFS_DEVELOPMENT_BUILD: boolean;\nexport declare const COMMIT_METADATA_SPLIT: RegExp;\nexport declare const GIT_DIFF_FILE_BREAK_REGEX: RegExp;\nexport declare const UNIFIED_DIFF_FILE_BREAK_REGEX: RegExp;\nexport declare const FILE_CONTEXT_BLOB: RegExp;\nexport declare const HUNK_HEADER: RegExp;\nexport declare const SPLIT_WITH_NEWLINES: RegExp;\nexport declare const FILENAME_HEADER_REGEX: RegExp;\nexport declare const FILENAME_HEADER_REGEX_GIT: RegExp;\nexport declare const ALTERNATE_FILE_NAMES_GIT: RegExp;\nexport declare const INDEX_LINE_METADATA: RegExp;\nexport declare const MERGE_CONFLICT_START_MARKER_REGEX: RegExp;\nexport declare const MERGE_CONFLICT_BASE_MARKER_REGEX: RegExp;\nexport declare const MERGE_CONFLICT_SEPARATOR_MARKER_REGEX: RegExp;\nexport declare const MERGE_CONFLICT_END_MARKER_REGEX: RegExp;\nexport declare const HEADER_PREFIX_SLOT_ID = \"header-prefix\";\nexport declare const HEADER_METADATA_SLOT_ID = \"header-metadata\";\nexport declare const CUSTOM_HEADER_SLOT_ID = \"header-custom\";\nexport declare const DEFAULT_THEMES: ThemesType;\nexport declare const THEME_CSS_ATTRIBUTE = \"data-theme-css\";\nexport declare const UNSAFE_CSS_ATTRIBUTE = \"data-unsafe-css\";\nexport declare const CORE_CSS_ATTRIBUTE = \"data-core-css\";\nexport declare const DIFFS_SCROLLBAR_MEASURE_ATTRIBUTE = \"data-diffs-scrollbar-measure\";\nexport declare const DIFFS_SCROLLBAR_GUTTER_MEASURED_PROPERTY = \"--diffs-scrollbar-gutter-measured\";\nexport declare const DEFAULT_COLLAPSED_CONTEXT_THRESHOLD = 1;\nexport declare const DEFAULT_TOKENIZE_MAX_LENGTH = 100000;\nexport declare const DEFAULT_VIRTUAL_FILE_METRICS: VirtualFileMetrics;\nexport declare const DEFAULT_CODE_VIEW_FILE_METRICS: VirtualFileMetrics;\nexport declare const DEFAULT_CODE_VIEW_LAYOUT: CodeViewLayout;\nexport declare const DEFAULT_SMOOTH_SCROLL_SETTINGS: SmoothScrollSettings;\nexport declare const DEFAULT_EXPANDED_REGION: HunkExpansionRegion;\nexport declare const DEFAULT_RENDER_RANGE: RenderRange;\nexport declare const EMPTY_RENDER_RANGE: RenderRange;\n//# sourceMappingURL=constants.d.ts.map"],"mappings":";;;cACqBM;cACAC;AADAD,cAEAE,qBAFiC,EAEVC,MAFU;AACjCF,cAEAG,yBAFgC,EAELD,MAFK;AAChCD,cAEAG,6BAF6B,EAEEF,MAFF;AAC7BC,cAEAE,iBAFiC,EAEdH,MAFQA;AAC3BE,cAEAE,WAFAF,EAEaF,MAFwB;AACrCG,cAEAE,mBAFmBL,EAEEA,MAFI;AACzBI,cAEAE,qBAFmB,EAEIN,MAFJ;AACnBK,cAEAE,yBAF2B,EAEAP,MAFA;AAC3BM,cAEAE,wBAFuBR,EAEGA,MAFG;AAC7BO,cAEAE,mBAFiC,EAEZT,MAFMA;AAC3BQ,cAEAE,iCAFgC,EAEGV,MAFH;AAChCS,cAEAE,gCAF2B,EAEOX,MAFP;AAC3BU,cAEAE,qCAFmCZ,EAEIA,MAFE;AACzCW,cAEAE,+BAFkCb,EAEDA,MAFO;AACxCY,cAEAE,qBAAAA,GAF6C,eAANd;AACvCa,cAEAE,uBAAAA,GAFuC,iBAAA;AACvCD,cAEAE,qBAAAA,GAFqB,eAAA;AACrBD,cAEAE,cAFuB,EAEPtB,UAFO;AACvBqB,cAEAE,mBAAAA,GAFqB,gBAAA;AACrBD,cAEAE,oBAAAA,GAFgBxB,iBAAU;AAC1BuB,cAEAE,kBAAAA,GAFmB,eAAA;AACnBD,cAEAE,iCAAAA,GAFoB,8BAAA;AACpBD,cAEAE,wCAAAA,GAFkB,mCAAA;AAClBD,cAEAE,mCAAAA,GAFiC,CAAA;AACjCD,cAEAE,2BAAAA,GAFwC,MAAA;AACxCD,cAEAE,4BAFmC,EAEL7B,kBAFK;AACnC4B,cAEAE,8BAF2B,EAEK9B,kBAFL;AAC3B6B,cAEAE,wBAFgD,EAEtBpC,cAFIK;AAC9B8B,cAEAE,8BAFgChC,EAEAF,oBAFkB;AAClDiC,cAEAE,uBAF0BtC,EAEDC,mBAFe;AACxCoC,cAEAE,oBAFoD,EAE9BrC,WAFUC;AAChCmC,cAEAE,kBAF4C,EAExBtC,WAFKD"}
package/dist/constants.js CHANGED
@@ -39,7 +39,6 @@ const DEFAULT_VIRTUAL_FILE_METRICS = {
39
39
  hunkLineCount: 50,
40
40
  lineHeight: 20,
41
41
  diffHeaderHeight: 44,
42
- hunkSeparatorHeight: 32,
43
42
  spacing: 8
44
43
  };
45
44
  const DEFAULT_CODE_VIEW_FILE_METRICS = {