@pierre/diffs 1.4.2 → 1.5.0

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 (72) hide show
  1. package/dist/components/CodeView.d.ts +2 -4
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +23 -12
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts +3 -0
  6. package/dist/components/File.d.ts.map +1 -1
  7. package/dist/components/File.js +10 -0
  8. package/dist/components/File.js.map +1 -1
  9. package/dist/components/FileDiff.d.ts +19 -1
  10. package/dist/components/FileDiff.d.ts.map +1 -1
  11. package/dist/components/FileDiff.js +51 -15
  12. package/dist/components/FileDiff.js.map +1 -1
  13. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  14. package/dist/components/VirtualizedFile.js +18 -19
  15. package/dist/components/VirtualizedFile.js.map +1 -1
  16. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  17. package/dist/components/VirtualizedFileDiff.js +25 -22
  18. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  19. package/dist/constants.d.ts +1 -3
  20. package/dist/constants.d.ts.map +1 -1
  21. package/dist/constants.js +1 -3
  22. package/dist/constants.js.map +1 -1
  23. package/dist/editor/editor.d.ts.map +1 -1
  24. package/dist/editor/editor.js +21 -10
  25. package/dist/editor/editor.js.map +1 -1
  26. package/dist/editor/textMeasure.d.ts.map +1 -1
  27. package/dist/editor/textMeasure.js +27 -3
  28. package/dist/editor/textMeasure.js.map +1 -1
  29. package/dist/highlighter/languages/attachResolvedLanguages.js +8 -1
  30. package/dist/highlighter/languages/attachResolvedLanguages.js.map +1 -1
  31. package/dist/highlighter/languages/registerCustomLanguage.d.ts +3 -1
  32. package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -1
  33. package/dist/highlighter/languages/registerCustomLanguage.js +3 -1
  34. package/dist/highlighter/languages/registerCustomLanguage.js.map +1 -1
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +2 -2
  37. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  38. package/dist/react/utils/useFileDiffInstance.js +47 -11
  39. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  40. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  41. package/dist/renderers/DiffHunksRenderer.js +20 -13
  42. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  43. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  44. package/dist/renderers/FileRenderer.js +30 -11
  45. package/dist/renderers/FileRenderer.js.map +1 -1
  46. package/dist/sprite.d.ts +2 -2
  47. package/dist/sprite.d.ts.map +1 -1
  48. package/dist/sprite.js +57 -0
  49. package/dist/sprite.js.map +1 -1
  50. package/dist/utils/editSessionHunks.d.ts +5 -4
  51. package/dist/utils/editSessionHunks.d.ts.map +1 -1
  52. package/dist/utils/editSessionHunks.js +32 -9
  53. package/dist/utils/editSessionHunks.js.map +1 -1
  54. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  55. package/dist/utils/parsePatchFiles.js +21 -13
  56. package/dist/utils/parsePatchFiles.js.map +1 -1
  57. package/dist/utils/parseQuotedDiffFileName.d.ts +8 -0
  58. package/dist/utils/parseQuotedDiffFileName.d.ts.map +1 -0
  59. package/dist/utils/parseQuotedDiffFileName.js +54 -0
  60. package/dist/utils/parseQuotedDiffFileName.js.map +1 -0
  61. package/dist/utils/realignChangeContent.d.ts +13 -10
  62. package/dist/utils/realignChangeContent.d.ts.map +1 -1
  63. package/dist/utils/realignChangeContent.js +23 -19
  64. package/dist/utils/realignChangeContent.js.map +1 -1
  65. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  66. package/dist/worker/WorkerPoolManager.js +40 -38
  67. package/dist/worker/WorkerPoolManager.js.map +1 -1
  68. package/dist/worker/worker-portable.js +8 -1
  69. package/dist/worker/worker-portable.js.map +1 -1
  70. package/dist/worker/worker.js +8 -1
  71. package/dist/worker/worker.js.map +1 -1
  72. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizedFile.d.ts","names":[],"sources":["../../src/components/VirtualizedFile.ts"],"mappings":";;;;;;;;cA8Ea,gBACX,yBACA,2BACQ,KAAK,aAAa;UAqBhB;UACA;WArBQ;WACF;EAET;EACA;UACC;UAMA;UACA;UACA;UACA;UACA;UACA;EAER,YACE,SAAS,YAAY,aAAa,oBAC1B,aAAa,cAAc,SAAS,aAAa,QACjD,UAAS,oBACjB,gBAAgB,mBAChB;EAKK,WACL,UAAU,QAAQ,qBAClB;EAWO,mBACP,iBAAiB,eAAe;UAO1B;YAiBW,qCACjB,iBAAiB,eAAe;UAS1B;UASA;EAYD,cAAc,mBAAmB;EAS/B,WACP,SAAS,YAAY,aAAa;EA4B3B,aAAa,WAAW;UAUzB;UAyBA;EAkCD;EA2GA,WAAQ;EAYR,qBACL,MAAM,cACN,aACA,QAAQ,4BACR,kBAAkB,eAAe;UA+C3B;EAID,gBACL;IACG;IAAa;;EA6CX,qBAAqB,cAAc;EAMnC,uBACL,2BACC;EAgFI;EAIA,uBACL,cAAc,eACb;EAyCM,QAAQ;UAiCT;EAsED,cAAc;EAcZ;EAwBF;EAYE,oBACP,cAAc,qBAAqB,cACnC,qBAAqB,eAAe,gBACpC;EAoCO,SACP,eACA,MACA,aACA,oBACG,SACF,gBAAgB;YA8FA;UAiBX;EA0BD;YAIY;YAMA;UAIX;UAIA;UAIA;UAWA;UAiCA;UAuCA;UASA;UAIA;UAIA;UAIA"}
1
+ {"version":3,"file":"VirtualizedFile.d.ts","names":[],"sources":["../../src/components/VirtualizedFile.ts"],"mappings":";;;;;;;;cA8Ea,gBACX,yBACA,2BACQ,KAAK,aAAa;UAyBhB;UACA;WAzBQ;WACF;EAET;EACA;UACC;UAUA;UACA;UACA;UACA;UACA;UACA;EAER,YACE,SAAS,YAAY,aAAa,oBAC1B,aAAa,cAAc,SAAS,aAAa,QACjD,UAAS,oBACjB,gBAAgB,mBAChB;EAKK,WACL,UAAU,QAAQ,qBAClB;EAWO,mBACP,iBAAiB,eAAe;UAS1B;YAiBW,qCACjB,iBAAiB,eAAe;UAS1B;UASA;EAYD,cAAc,mBAAmB;EAS/B,WACP,SAAS,YAAY,aAAa;EA4B3B,aAAa,WAAW;UAUzB;UAyBA;EAkCD;EAoHA,WAAQ;EAYR,qBACL,MAAM,cACN,aACA,QAAQ,4BACR,kBAAkB,eAAe;UA6C3B;EAID,gBACL;IACG;IAAa;;EA6CX,qBAAqB,cAAc;EAMnC,uBACL,2BACC;EAgFI;EAIA,uBACL,cAAc,eACb;EAyCM,QAAQ;UAiCT;EAsED,cAAc;EAcZ;EAwBF;EAYE,oBACP,cAAc,qBAAqB,cACnC,qBAAqB,eAAe,gBACpC;EAoCO,SACP,eACA,MACA,aACA,oBACG,SACF,gBAAgB;YA4FA;UAiBX;EA0BD;YAIY;YAMA;UAIX;UAIA;UAIA;UAWA;UAiCA;UAuCA;UASA;UAIA;UAIA;UAIA"}
@@ -43,7 +43,7 @@ var VirtualizedFile = class extends File {
43
43
  this.resetLayoutCache();
44
44
  }
45
45
  setLineAnnotations(lineAnnotations) {
46
- if (this.syncLineAnnotations(lineAnnotations)) this.resetLayoutCache();
46
+ if (this.syncLineAnnotations(lineAnnotations)) this.forceRenderOverride = true;
47
47
  }
48
48
  syncLineAnnotations(lineAnnotations) {
49
49
  if (lineAnnotations == null || !this.isNewAnnotations(lineAnnotations)) return false;
@@ -53,7 +53,7 @@ var VirtualizedFile = class extends File {
53
53
  }
54
54
  syncEditSessionAnnotationsFromEditor(lineAnnotations) {
55
55
  if (super.syncEditSessionAnnotationsFromEditor(lineAnnotations)) {
56
- this.resetLayoutCache();
56
+ this.forceRenderOverride = true;
57
57
  return true;
58
58
  }
59
59
  return false;
@@ -123,31 +123,34 @@ var VirtualizedFile = class extends File {
123
123
  this.top = this.getVirtualizedTop();
124
124
  const ghostTextRows = this.editor?.__getGhostTextRows() ?? NO_GHOST_TEXT_ROWS;
125
125
  hasHeightChange = this.applyGhostTextRows(ghostTextRows);
126
- if (overflow === "scroll" && this.getLatestAnnotations().length === 0 && !this.isResizeDebuggingEnabled()) {
127
- if (hasHeightChange) this.computeApproximateSize(true);
126
+ const measureAllRows = overflow !== "scroll" || this.getLatestAnnotations().length > 0 || this.isResizeDebuggingEnabled();
127
+ if (this.placeHolder != null || !measureAllRows && this.cache.heights.size === 0 && this.cache.fileAnnotationHeight === 0) {
128
+ if (hasHeightChange) {
129
+ this.computeApproximateSize(true);
130
+ this.setPlaceholderHeight(this.height);
131
+ }
128
132
  return hasHeightChange;
129
133
  }
130
134
  const { lineHeight } = this.metrics;
131
135
  if (this.code == null) return hasHeightChange;
132
136
  const content = this.code.children[1];
133
137
  if (!(content instanceof HTMLElement)) return hasHeightChange;
134
- const hasFileAnnotations = includesFileAnnotations(this.getLatestAnnotations());
135
- if (this.renderRange != null && hasFileAnnotations && shouldRenderFileAnnotations(this.renderRange)) {
138
+ if (this.renderRange != null && shouldRenderFileAnnotations(this.renderRange)) {
136
139
  const nextFileAnnotationHeight = measureFileAnnotationHeight(content) ?? 0;
137
140
  if (nextFileAnnotationHeight !== this.cache.fileAnnotationHeight) {
138
141
  this.cache.fileAnnotationHeight = nextFileAnnotationHeight;
139
142
  hasHeightChange = true;
140
143
  }
141
- } else if (!hasFileAnnotations && this.cache.fileAnnotationHeight !== 0) {
142
- this.cache.fileAnnotationHeight = 0;
143
- hasHeightChange = true;
144
144
  }
145
145
  for (const line of content.children) {
146
146
  if (!(line instanceof HTMLElement)) continue;
147
147
  const lineIndexAttr = line.dataset.lineIndex;
148
148
  if (lineIndexAttr == null) continue;
149
149
  const lineIndex = Number(lineIndexAttr);
150
- let measuredHeight = line.getBoundingClientRect().height + (ghostTextRows.get(lineIndex) ?? 0) * lineHeight;
150
+ const ghostHeight = (ghostTextRows.get(lineIndex) ?? 0) * lineHeight;
151
+ const cachedHeight = this.cache.heights.get(lineIndex);
152
+ if (!measureAllRows && (cachedHeight == null || cachedHeight === lineHeight + ghostHeight)) continue;
153
+ let measuredHeight = line.getBoundingClientRect().height + ghostHeight;
151
154
  let hasMetadata = false;
152
155
  if (line.nextElementSibling instanceof HTMLElement && ("lineAnnotation" in line.nextElementSibling.dataset || "noNewline" in line.nextElementSibling.dataset)) {
153
156
  if ("noNewline" in line.nextElementSibling.dataset) hasMetadata = true;
@@ -171,7 +174,7 @@ var VirtualizedFile = class extends File {
171
174
  const targetChanged = !areFileTargetsEqual(this.file, file);
172
175
  if (targetChanged) this.updateExternalFile(file, lineAnnotations);
173
176
  const { pendingRenderFile, layoutFileChanged, renderedFileChanged, annotationsChanged } = this.updatePendingRender(file, lineAnnotations);
174
- let shouldResetLayoutCache = reset?.resetFileLayoutCache === true || layoutFileChanged || annotationsChanged;
177
+ let shouldResetLayoutCache = reset?.resetFileLayoutCache === true || layoutFileChanged;
175
178
  if (reset?.metrics != null) {
176
179
  this.metrics = reset.metrics;
177
180
  shouldResetLayoutCache = true;
@@ -377,13 +380,13 @@ var VirtualizedFile = class extends File {
377
380
  pendingRenderFile: this.pendingRender.file,
378
381
  layoutFileChanged: false,
379
382
  renderedFileChanged: false,
380
- annotationsChanged: false
383
+ annotationsChanged: this.syncLineAnnotations(lineAnnotations)
381
384
  };
382
385
  return this.updatePendingRender(file, lineAnnotations);
383
386
  })();
384
387
  const { forceRenderOverride, isSetup } = this;
385
388
  this.forceRenderOverride = void 0;
386
- if (annotationsChanged || layoutFileChanged) this.resetLayoutCache();
389
+ if (layoutFileChanged) this.resetLayoutCache();
387
390
  fileContainer = this.getOrCreateFileContainerNode(fileContainer);
388
391
  if (!isSetup) {
389
392
  this.computeApproximateSize(false, pendingRenderFile);
@@ -398,16 +401,12 @@ var VirtualizedFile = class extends File {
398
401
  this.isSetup = true;
399
402
  } else {
400
403
  this.top ??= this.getVirtualizedTop();
401
- if (layoutFileChanged && this.isSimpleMode()) {
404
+ if (this.layoutDirty && this.isSimpleMode()) {
402
405
  this.getSimpleVirtualizer()?.markDOMDirty();
403
- this.resetLayoutCache(false);
404
406
  this.computeApproximateSize(false, pendingRenderFile);
405
407
  }
406
408
  }
407
- if (!this.isVisible && this.isSimpleMode() && (!didFileChange || !isSetup)) {
408
- this.pendingRender = void 0;
409
- return this.renderPlaceholder(this.height);
410
- }
409
+ if (!this.isVisible && this.isSimpleMode() && (!didFileChange || !isSetup)) return this.renderPlaceholder(this.height);
411
410
  const windowSpecs = this.virtualizer.getWindowSpecs();
412
411
  const fileTop = this.top ?? 0;
413
412
  const renderRange = this.computeRenderRangeFromWindow(pendingRenderFile, fileTop, windowSpecs);
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizedFile.js","names":[],"sources":["../../src/components/VirtualizedFile.ts"],"sourcesContent":["import { DEFAULT_VIRTUAL_FILE_METRICS } from '../constants';\nimport type { TextDocument } from '../editor/textDocument';\nimport type {\n FileContents,\n LineAnnotation,\n NumericScrollLineAnchor,\n PendingCodeViewLayoutReset,\n RenderRange,\n RenderWindow,\n StickySpecs,\n ThemeTypes,\n VirtualFileMetrics,\n} from '../types';\nimport { areFileTargetsEqual } from '../utils/areFileTargetsEqual';\nimport { areObjectsEqual } from '../utils/areObjectsEqual';\nimport { areOptionsEqual } from '../utils/areOptionsEqual';\nimport {\n computeVirtualFileMetrics,\n getVirtualFileHeaderRegion,\n getVirtualFilePaddingBottom,\n} from '../utils/computeVirtualFileMetrics';\nimport {\n FILE_ANNOTATION_DOM_KEY,\n FILE_ANNOTATION_LINE_NUMBER,\n includesFileAnnotations,\n shouldRenderFileAnnotations,\n} from '../utils/includesFileAnnotations';\nimport type { WorkerPoolManager } from '../worker';\nimport type { CodeView } from './CodeView';\nimport { File, type FileOptions, type FileRenderProps } from './File';\nimport type { Virtualizer } from './Virtualizer';\n\ninterface FileLayoutCheckpoint {\n lineIndex: number;\n top: number;\n}\n\ninterface FileLayoutCache {\n // Sparse map: line index -> measured height. Only stores lines that differ\n // 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 // line or scroll offset instead of replaying layout from the start.\n checkpoints: FileLayoutCheckpoint[];\n // Measured height for the file-level annotation row. Starts at 0 so\n // unmeasured annotations behave like all other unmeasured annotations.\n fileAnnotationHeight: number;\n // Ghost text rows folded into `heights` (zero-based line -> row count), so an\n // entry can be corrected when the editor's ghost text changes or goes away.\n ghostTextRows: ReadonlyMap<number, number>;\n}\n\ninterface PendingRender {\n latestFile: FileContents;\n file: FileContents;\n}\n\nconst LAYOUT_CHECKPOINT_INTERVAL = 5_000;\nconst NO_GHOST_TEXT_ROWS: ReadonlyMap<number, number> = new Map();\n\nlet instanceId = -1;\n\nfunction hasFileLayoutOptionChanged<LAnnotation, Caret>(\n previousOptions: FileOptions<LAnnotation, Caret>,\n nextOptions: FileOptions<LAnnotation, Caret>\n): boolean {\n return (\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.unsafeCSS !== nextOptions.unsafeCSS\n );\n}\n\nexport class VirtualizedFile<\n LAnnotation = undefined,\n Caret = undefined,\n> extends File<LAnnotation, Caret> {\n override readonly __id: string = `virtualized-file:${++instanceId}`;\n public readonly renderType = 'virtualized';\n\n public top: number | undefined;\n public height: number = 0;\n private cache: FileLayoutCache = {\n heights: new Map(),\n checkpoints: [],\n fileAnnotationHeight: 0,\n ghostTextRows: NO_GHOST_TEXT_ROWS,\n };\n private pendingRender: PendingRender | undefined;\n private isVisible: boolean = false;\n private isSetup: boolean = false;\n private layoutDirty = true;\n private forceRenderOverride: true | undefined;\n private currentCollapsed: boolean | undefined;\n\n constructor(\n options: FileOptions<LAnnotation, Caret> | undefined,\n private virtualizer: Virtualizer | CodeView<LAnnotation, Caret>,\n private metrics: VirtualFileMetrics = DEFAULT_VIRTUAL_FILE_METRICS,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\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 override setLineAnnotations(\n lineAnnotations: LineAnnotation<LAnnotation>[]\n ): void {\n if (this.syncLineAnnotations(lineAnnotations)) {\n this.resetLayoutCache();\n }\n }\n\n private syncLineAnnotations(\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined\n ): boolean {\n if (lineAnnotations == null || !this.isNewAnnotations(lineAnnotations)) {\n return false;\n }\n if (\n lineAnnotations.length === 0 &&\n this.getLatestAnnotations().length === 0\n ) {\n return false;\n }\n\n super.setLineAnnotations(lineAnnotations);\n return true;\n }\n\n protected override syncEditSessionAnnotationsFromEditor(\n lineAnnotations: LineAnnotation<LAnnotation>[]\n ): boolean {\n if (super.syncEditSessionAnnotationsFromEditor(lineAnnotations)) {\n this.resetLayoutCache();\n return true;\n }\n return false;\n }\n\n private hasLineAnnotations(): boolean {\n return this.getLatestAnnotations().some(\n (annotation) => annotation.lineNumber > FILE_ANNOTATION_LINE_NUMBER\n );\n }\n\n // Every line is exactly one line height tall, so positions can be multiplied\n // instead of walked: no wrapping, no line annotations, and nothing cached (in\n // such files the cache only fills because of ghost text rows).\n private hasUniformLineHeights(): boolean {\n const { overflow = 'scroll' } = this.options;\n return (\n overflow === 'scroll' &&\n !this.hasLineAnnotations() &&\n this.cache.heights.size === 0\n );\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\n // metadata.\n public 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(\n options: FileOptions<LAnnotation, Caret> | undefined\n ): void {\n if (this.isAdvancedMode()) {\n throw new Error(\n 'VirtualizedFile.setOptions cannot be used inside CodeView. Update CodeView options instead.'\n );\n }\n\n if (options == null) return;\n const { options: previousOptions } = this;\n const optionsChanged = !areOptionsEqual(previousOptions, options);\n const layoutChanged = hasFileLayoutOptionChanged(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) {\n this.virtualizer.instanceChanged(this, layoutChanged);\n }\n }\n\n override setThemeType(themeType: ThemeTypes): void {\n if (this.isAdvancedMode()) {\n throw new Error(\n 'VirtualizedFile.setThemeType cannot be used inside CodeView. Update CodeView options instead.'\n );\n }\n\n super.setThemeType(themeType);\n }\n\n private resetLayoutCache(recompute = false, resetRenderRange = true): void {\n this.layoutDirty = true;\n this.cache.fileAnnotationHeight = 0;\n if (this.cache.heights.size > 0) {\n this.cache.heights.clear();\n }\n if (this.cache.checkpoints.length > 0) {\n this.cache.checkpoints.length = 0;\n }\n this.cache.ghostTextRows = NO_GHOST_TEXT_ROWS;\n if (this.renderRange != null && resetRenderRange) {\n this.renderRange = undefined;\n }\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 // Fold the ghost text rows the editor is showing below lines into the height\n // cache (zero-based line -> row count). Ghost text sits in a margin below the\n // row, which measuring never includes, so the rows are added here on top of\n // the line's own height, and removed again when the ghost text changes or\n // goes away, even for rows that are not rendered right now.\n private applyGhostTextRows(\n ghostTextRows: ReadonlyMap<number, number>\n ): boolean {\n const { heights, ghostTextRows: previous } = this.cache;\n if (previous === ghostTextRows) {\n return false;\n }\n const { lineHeight } = this.metrics;\n let changed = false;\n for (const lineIndex of new Set([\n ...previous.keys(),\n ...ghostTextRows.keys(),\n ])) {\n const previousRows = previous.get(lineIndex) ?? 0;\n const rows = ghostTextRows.get(lineIndex) ?? 0;\n if (rows === previousRows) {\n continue;\n }\n const ownHeight =\n (heights.get(lineIndex) ?? lineHeight) - previousRows * lineHeight;\n const height = ownHeight + rows * lineHeight;\n if (height === lineHeight) {\n heights.delete(lineIndex);\n } else {\n heights.set(lineIndex, height);\n }\n changed = true;\n }\n this.cache.ghostTextRows = ghostTextRows;\n return changed;\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n public reconcileHeights(): boolean {\n let hasHeightChange = false;\n if (this.fileContainer == null || this.getLayoutFile() == null) {\n if (this.height !== 0) {\n hasHeightChange = true;\n }\n this.height = 0;\n return hasHeightChange;\n }\n const { overflow = 'scroll' } = this.options;\n this.top = this.getVirtualizedTop();\n const ghostTextRows =\n this.editor?.__getGhostTextRows() ?? NO_GHOST_TEXT_ROWS;\n hasHeightChange = this.applyGhostTextRows(ghostTextRows);\n\n // If the file has no annotations and we are using the scroll variant, every\n // line is one line height tall apart from those with ghost text under them,\n // so nothing needs measuring.\n if (\n overflow === 'scroll' &&\n this.getLatestAnnotations().length === 0 &&\n !this.isResizeDebuggingEnabled()\n ) {\n if (hasHeightChange) {\n this.computeApproximateSize(true);\n }\n return hasHeightChange;\n }\n const { lineHeight } = this.metrics;\n\n // Single code element (no split mode)\n if (this.code == null) {\n return hasHeightChange;\n }\n const content = this.code.children[1]; // Content column (gutter is [0])\n if (!(content instanceof HTMLElement)) {\n return hasHeightChange;\n }\n\n const hasFileAnnotations = includesFileAnnotations(\n this.getLatestAnnotations()\n );\n if (\n this.renderRange != null &&\n hasFileAnnotations &&\n shouldRenderFileAnnotations(this.renderRange)\n ) {\n const fileAnnotationHeight = measureFileAnnotationHeight(content);\n const nextFileAnnotationHeight = fileAnnotationHeight ?? 0;\n if (nextFileAnnotationHeight !== this.cache.fileAnnotationHeight) {\n this.cache.fileAnnotationHeight = nextFileAnnotationHeight;\n hasHeightChange = true;\n }\n } else if (!hasFileAnnotations && this.cache.fileAnnotationHeight !== 0) {\n this.cache.fileAnnotationHeight = 0;\n hasHeightChange = true;\n }\n\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 = Number(lineIndexAttr);\n let measuredHeight =\n line.getBoundingClientRect().height +\n (ghostTextRows.get(lineIndex) ?? 0) * lineHeight;\n let hasMetadata = false;\n\n // Annotations or noNewline metadata increase the size of their 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\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 (measuredHeight === this.metrics.lineHeight * (hasMetadata ? 2 : 1)) {\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 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 || this.file == null) {\n return false;\n }\n if (dirty) {\n this.top = this.getVirtualizedTop();\n }\n return this.render({ file: this.file });\n };\n\n // CodeView positions every item before updating the DOM. Recalculate this\n // item's layout whenever its content or position changes.\n public updateCodeViewLayout(\n file: FileContents,\n top: number,\n reset?: PendingCodeViewLayoutReset,\n lineAnnotations?: LineAnnotation<LAnnotation>[]\n ): number {\n const targetChanged = !areFileTargetsEqual(this.file, file);\n if (targetChanged) {\n this.updateExternalFile(file, lineAnnotations);\n }\n const {\n pendingRenderFile,\n layoutFileChanged,\n renderedFileChanged,\n annotationsChanged,\n } = this.updatePendingRender(file, lineAnnotations);\n let shouldResetLayoutCache =\n reset?.resetFileLayoutCache === true ||\n layoutFileChanged ||\n annotationsChanged;\n if (reset?.metrics != null) {\n this.metrics = reset.metrics;\n shouldResetLayoutCache = true;\n }\n\n const { collapsed = false } = this.options;\n if (this.currentCollapsed !== collapsed) {\n this.currentCollapsed = collapsed;\n shouldResetLayoutCache = true;\n }\n\n if (shouldResetLayoutCache) {\n this.resetLayoutCache();\n }\n\n if (targetChanged) {\n this.layoutDirty = true;\n }\n if (\n !this.forceRenderOverride &&\n (targetChanged || renderedFileChanged || annotationsChanged)\n ) {\n this.forceRenderOverride = true;\n }\n this.top = top;\n this.computeApproximateSize(false, pendingRenderFile);\n return this.height;\n }\n\n // CodeView calculates layout before it renders the next item. Keep every\n // geometry read in that frame tied to the file selected for that render.\n private getLayoutFile(): FileContents | undefined {\n return this.pendingRender?.file ?? this.getRenderedFile();\n }\n\n public getLinePosition(\n lineNumber: number\n ): { top: number; height: number } | undefined {\n const file = this.getLayoutFile();\n if (file == null || lineNumber < 1) {\n return undefined;\n }\n\n const { disableFileHeader = false, collapsed = false } = this.options;\n const lastLineIndex = this.fileRenderer.getLineCount(file) - 1;\n let top = getVirtualFileHeaderRegion(this.metrics, disableFileHeader);\n\n if (collapsed || lastLineIndex < 0) {\n return { top, height: 0 };\n }\n\n const clampedLineIndex = Math.min(\n Math.max(lineNumber - 1, 0),\n lastLineIndex\n );\n const { lineHeight } = this.metrics;\n top += this.cache.fileAnnotationHeight;\n\n if (this.hasUniformLineHeights()) {\n return {\n top: top + clampedLineIndex * lineHeight,\n height: lineHeight,\n };\n }\n\n const checkpoint =\n this.getLayoutCheckpointBeforeLineIndex(clampedLineIndex);\n top = checkpoint?.top ?? top;\n for (\n let lineIndex = checkpoint?.lineIndex ?? 0;\n lineIndex < clampedLineIndex;\n lineIndex++\n ) {\n top += this.getLineHeight(lineIndex, false);\n }\n\n return {\n top,\n height: this.getLineHeight(clampedLineIndex, false),\n };\n }\n\n public getEditorViewport(): HTMLElement | Document | undefined {\n return this.virtualizer.type === 'simple'\n ? this.virtualizer.getRoot()\n : this.virtualizer.getContainerElement();\n }\n\n public getNumericScrollAnchor(\n localViewportTop: number\n ): NumericScrollLineAnchor | undefined {\n const file = this.getLayoutFile();\n if (file == null || this.renderRange == null) {\n return undefined;\n }\n\n const { disableFileHeader = false, collapsed = false } = this.options;\n if (collapsed || this.renderRange.totalLines <= 0) {\n return undefined;\n }\n\n const lastLineIndex = this.fileRenderer.getLineCount(file) - 1;\n if (lastLineIndex < 0) {\n return undefined;\n }\n\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const firstRenderedLineIndex = Math.min(\n this.renderRange.startingLine,\n lastLineIndex\n );\n const lastRenderedLineIndex = Math.min(\n firstRenderedLineIndex + this.renderRange.totalLines - 1,\n lastLineIndex\n );\n if (lastRenderedLineIndex < firstRenderedLineIndex) {\n return undefined;\n }\n const { fileAnnotationHeight } = this.cache;\n\n // When we have uniform line heights we can just multiply our way to the\n // correct value\n if (this.hasUniformLineHeights()) {\n const { lineHeight } = this.metrics;\n const firstRenderedLineTop =\n headerRegion +\n (firstRenderedLineIndex === 0\n ? fileAnnotationHeight\n : this.renderRange.bufferBefore);\n const deltaLineCount = Math.max(\n Math.ceil((localViewportTop - firstRenderedLineTop) / lineHeight),\n 0\n );\n const lineIndex = firstRenderedLineIndex + deltaLineCount;\n if (lineIndex > lastRenderedLineIndex) {\n return undefined;\n }\n\n return {\n lineNumber: lineIndex + 1,\n top: headerRegion + fileAnnotationHeight + lineIndex * lineHeight,\n };\n }\n\n // Otherwise we gotta iterate through the range\n let top =\n headerRegion +\n (firstRenderedLineIndex === 0\n ? fileAnnotationHeight\n : this.renderRange.bufferBefore);\n for (\n let lineIndex = firstRenderedLineIndex;\n lineIndex <= lastRenderedLineIndex;\n lineIndex++\n ) {\n if (top >= localViewportTop) {\n return {\n lineNumber: lineIndex + 1,\n top,\n };\n }\n top += this.getLineHeight(lineIndex);\n }\n\n return undefined;\n }\n\n public getVirtualizedHeight(): number {\n return this.height;\n }\n\n public getAdvancedStickySpecs(\n windowSpecs?: RenderWindow\n ): StickySpecs | undefined {\n const file = this.getLayoutFile();\n if (this.top == null || file == 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(file, this.top, windowSpecs)\n : this.renderRange;\n if (renderRange == null) {\n return undefined;\n }\n const { bufferBefore, bufferAfter, totalLines } = renderRange;\n // Rendered items flow contiguously in the sticky container with no buffer\n // spacers, so a header-only item (totalLines === 0, none of its rows fall\n // inside the window) must report where its header actually sits in that\n // flow, which depends on which side of the window its content is on:\n // - content ABOVE the window (item starts above window.top): the header\n // sits at the item's bottom so the following item connects, so offset by\n // bufferAfter.\n // - content BELOW the window (item starts at/after window.top, e.g. a\n // trailing header peeking in at the bottom): the header renders at the\n // item's top with nothing after it, so no offset. Always adding\n // bufferAfter here made getStickyBounds over-measure the sticky\n // container for that trailing case.\n let headerOnlyOffset = 0;\n if (totalLines === 0) {\n const activeWindow = windowSpecs ?? this.virtualizer.getWindowSpecs();\n if (this.top < activeWindow.top) {\n headerOnlyOffset = bufferAfter;\n }\n }\n return {\n topOffset: this.top + bufferBefore + headerOnlyOffset,\n height: this.height - (bufferBefore + bufferAfter),\n };\n }\n\n override cleanUp(recycle = false): void {\n // The editor's own cleanUp has already cleared its ghost text rows without\n // asking for a layout pass. Mark the layout dirty so a pooled item drops the\n // folded rows on its next pass instead of keeping phantom height.\n const hadGhostTextRows = this.cache.ghostTextRows.size > 0;\n if (hadGhostTextRows) {\n this.layoutDirty = true;\n }\n const shouldRecomputeLayout =\n recycle &&\n this.isAdvancedMode() &&\n this.fileContainer != null &&\n (hadGhostTextRows ||\n !areFileTargetsEqual(this.getRenderedFile(), this.getLatestFile()));\n if (this.fileContainer != null && this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.disconnect(this.fileContainer);\n }\n if (!recycle) {\n this.resetLayoutCache();\n }\n this.pendingRender = undefined;\n this.isSetup = false;\n super.cleanUp(recycle);\n if (shouldRecomputeLayout) {\n this.virtualizer.instanceChanged(this, true);\n }\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\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(\n force = false,\n file: FileContents | undefined = this.getLayoutFile()\n ): 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 if (file == null) {\n this.layoutDirty = false;\n return;\n }\n this.applyGhostTextRows(\n this.editor?.__getGhostTextRows() ?? NO_GHOST_TEXT_ROWS\n );\n\n const { disableFileHeader = false, collapsed = false } = this.options;\n const { lineHeight } = this.metrics;\n const lineCount = this.fileRenderer.getLineCount(file);\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 this.height += this.cache.fileAnnotationHeight;\n\n if (this.hasUniformLineHeights()) {\n this.height += lineCount * lineHeight;\n } else {\n for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {\n this.addLayoutCheckpoint(lineIndex, this.height);\n this.height += this.getLineHeight(lineIndex, false);\n }\n }\n\n if (lineCount > 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 'VirtualizedFile.computeApproximateSize: computed height doesnt match',\n {\n name: file.name,\n elementHeight: rect.height,\n computedHeight: this.height,\n }\n );\n } else {\n console.log(\n 'VirtualizedFile.computeApproximateSize: computed height IS CORRECT'\n );\n }\n }\n this.layoutDirty = false;\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 (!this.enabled || this.file == null) {\n return;\n }\n const latestFile = this.getLatestFile();\n const nextRenderFile =\n latestFile == null\n ? undefined\n : this.fileRenderer.getFileForNextRender(latestFile);\n // A completed async highlight can change which file the next simple\n // virtualizer render will commit. CodeView refreshes this during layout.\n if (this.isSimpleMode()) {\n this.pendingRender = undefined;\n }\n this.forceRenderOverride = true;\n this.virtualizer.instanceChanged(\n this,\n !areFileTargetsEqual(this.getRenderedFile(), nextRenderFile)\n );\n }\n\n // The editor changed the ghost text rows it shows below lines. Ask the\n // virtualizer for a layout pass, which folds them in (see\n // applyGhostTextRows). Layout state only changes inside that pass.\n public syncGhostTextRows(): void {\n const codeView = this.getAdvancedVirtualizer();\n if (codeView != null) {\n codeView.capturePendingLayoutAnchor();\n this.layoutDirty = true;\n codeView.instanceChanged(this, true);\n } else {\n this.getSimpleVirtualizer()?.requestHeightReconcile(this);\n }\n }\n\n // normally triggered by the host when the document line count changes\n override applyDocumentChange(\n textDocument: TextDocument<'file', LAnnotation>,\n newLineAnnotations?: LineAnnotation<LAnnotation>[],\n shouldUpdateBuffer = false\n ): void {\n const { renderRange: previousRenderRange } = this;\n // Capture the scroll anchor before the synchronous document swap and\n // layout-cache wipe below; the host's next frame resolves it against the\n // new geometry so on-screen rows do not shift.\n this.getAdvancedVirtualizer()?.capturePendingLayoutAnchor();\n super.applyDocumentChange(textDocument, newLineAnnotations);\n this.getSimpleVirtualizer()?.markDOMDirty();\n this.resetLayoutCache(this.isSimpleMode(), false);\n\n const file = this.getRenderedFile();\n if (!this.isSimpleMode()) {\n this.computeApproximateSize(true);\n } else if (\n shouldUpdateBuffer &&\n previousRenderRange != null &&\n file != null\n ) {\n // Update the buffers caused by the line-count change to ensure the host\n // scrolls to the correct position before re-rendering.\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const renderRange = this.computeRenderRangeFromWindow(\n file,\n this.top ?? 0,\n windowSpecs\n );\n if (renderRange.bufferAfter !== previousRenderRange.bufferAfter) {\n this.updateBuffers(renderRange);\n }\n }\n\n this.forceRenderOverride = true;\n this.virtualizer.instanceChanged(this, true);\n }\n\n override render({\n fileContainer,\n file,\n forceRender = false,\n lineAnnotations,\n ...props\n }: FileRenderProps<LAnnotation>): boolean {\n const didFileChange = !areFileTargetsEqual(this.file, file);\n if (didFileChange) {\n this.updateExternalFile(file, lineAnnotations);\n this.cachedHeaderHTML = undefined;\n }\n const {\n pendingRenderFile,\n layoutFileChanged,\n renderedFileChanged,\n annotationsChanged,\n } = (() => {\n if (\n this.pendingRender != null &&\n this.pendingRender.latestFile === (this.getLatestFile(file) ?? file)\n ) {\n return {\n pendingRenderFile: this.pendingRender.file,\n layoutFileChanged: false,\n renderedFileChanged: false,\n annotationsChanged: false,\n };\n }\n return this.updatePendingRender(file, lineAnnotations);\n })();\n const { forceRenderOverride, isSetup } = this;\n this.forceRenderOverride = undefined;\n if (annotationsChanged || layoutFileChanged) {\n this.resetLayoutCache();\n }\n\n fileContainer = this.getOrCreateFileContainerNode(fileContainer);\n\n if (!isSetup) {\n this.computeApproximateSize(false, pendingRenderFile);\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 'VirtualizedFile.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 if (layoutFileChanged && this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.markDOMDirty();\n this.resetLayoutCache(false);\n this.computeApproximateSize(false, pendingRenderFile);\n }\n }\n\n // A hidden live instance receiving a changed file falls through to the\n // full render below so the base's change detection (header cache, stored\n // file) still runs; the placeholder path only serves unchanged data.\n if (\n !this.isVisible &&\n this.isSimpleMode() &&\n (!didFileChange || !isSetup)\n ) {\n this.pendingRender = undefined;\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 pendingRenderFile,\n fileTop,\n windowSpecs\n );\n return super.render({\n file,\n fileContainer,\n renderRange,\n lineAnnotations,\n forceRender:\n (forceRenderOverride ?? forceRender) ||\n annotationsChanged ||\n renderedFileChanged ||\n didFileChange,\n ...props,\n });\n }\n\n protected override finalizeRender(): void {\n if (this.getRenderedFile() !== this.pendingRender?.file) {\n throw new Error(\n 'VirtualizedFile.render: rendered a different file than its prepared layout'\n );\n }\n this.pendingRender = undefined;\n // Renders can be driven from outside the virtualizer (host/React render\n // calls, async highlight completions), and the virtualizer only\n // auto-reconciles renders it initiated. Queue a measured-height\n // reconciliation for every applied content render so line deltas\n // (wrapped lines, annotation heights) survive layout resets.\n if (this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.requestHeightReconcile(this);\n }\n }\n\n private updatePendingRender(\n nextFile: FileContents,\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined\n ) {\n const latestFile = this.getLatestFile(nextFile) ?? nextFile;\n const previousRenderedFile = this.getRenderedFile();\n const previousLayoutFile = this.pendingRender?.file ?? previousRenderedFile;\n const pendingRenderFile =\n this.fileRenderer.getFileForNextRender(latestFile);\n\n this.pendingRender = { latestFile, file: pendingRenderFile };\n\n return {\n pendingRenderFile,\n annotationsChanged: this.syncLineAnnotations(lineAnnotations),\n layoutFileChanged: !areFileTargetsEqual(\n previousLayoutFile,\n pendingRenderFile\n ),\n renderedFileChanged: !areFileTargetsEqual(\n previousRenderedFile,\n pendingRenderFile\n ),\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 // This WebKit dom manipulation scroll fix is not applicable in virtualized\n // environments, so we avoid the performance hit even on Webkit\n protected override shouldGuardRebuildScroll(): boolean {\n return false;\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 addLayoutCheckpoint(lineIndex: number, top: number): void {\n if (lineIndex % LAYOUT_CHECKPOINT_INTERVAL !== 0) {\n return;\n }\n this.cache.checkpoints.push({ lineIndex, top });\n }\n\n // Find the nearest sparse layout checkpoint at or before a raw file line.\n // Checkpoints store measured `top` offsets every few thousand lines, so a\n // binary search lets deep line-position lookups resume from that checkpoint\n // instead of replaying layout from the start of the file.\n private getLayoutCheckpointBeforeLineIndex(\n lineIndex: number\n ): FileLayoutCheckpoint | 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: FileLayoutCheckpoint | 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('VirtualizedFile: 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 files\n // only replay the nearby measured rows. When `hunkLineCount` is provided,\n // step backward to a hunk boundary so hooks that depend on grouped lines\n // still see a complete hunk.\n private getLayoutCheckpointBeforeTop(\n top: number,\n hunkLineCount?: number\n ): FileLayoutCheckpoint | 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('VirtualizedFile: 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('VirtualizedFile: invalid checkpoint index');\n }\n if (checkpoint.lineIndex % hunkLineCount === 0) {\n return checkpoint;\n }\n }\n\n return undefined;\n }\n\n private getVirtualizedTop(): number {\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 getAdvancedVirtualizer(): CodeView<LAnnotation, Caret> | undefined {\n return this.virtualizer.type === 'advanced' ? this.virtualizer : undefined;\n }\n\n private isResizeDebuggingEnabled(): boolean {\n return this.getSimpleVirtualizer()?.config.resizeDebugging ?? false;\n }\n\n private computeRenderRangeFromWindow(\n file: FileContents,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const { disableFileHeader = false } = this.options;\n const { hunkLineCount, lineHeight } = this.metrics;\n const lineCount = this.fileRenderer.getLineCount(file);\n const fileHeight = this.height;\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const paddingBottom =\n lineCount > 0 ? getVirtualFilePaddingBottom(this.metrics) : 0;\n const { fileAnnotationHeight } = this.cache;\n const codeRegionTop = headerRegion + fileAnnotationHeight;\n const codeRowsHeight = Math.max(\n 0,\n fileHeight - headerRegion - fileAnnotationHeight - paddingBottom\n );\n const hasFileAnnotations = includesFileAnnotations(\n this.getLatestAnnotations()\n );\n const fileAnnotationTop = fileTop + headerRegion;\n const measuredFileAnnotationVisible =\n fileAnnotationHeight > 0 &&\n hasFileAnnotations &&\n fileAnnotationTop < bottom &&\n fileAnnotationTop + fileAnnotationHeight > top;\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 // Small file, just render it all\n if (lineCount <= hunkLineCount) {\n return {\n startingLine: 0,\n totalLines: hunkLineCount,\n bufferBefore: 0,\n bufferAfter: 0,\n };\n }\n\n // Calculate totalLines based on viewport size\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 viewportCenter = (top + bottom) / 2;\n // Simple case: every line is one line height tall - pure math!\n if (this.hasUniformLineHeights()) {\n const sourceRowsTop = fileTop + codeRegionTop;\n const sourceRowsBottom = sourceRowsTop + codeRowsHeight;\n const sourceRowsVisible =\n sourceRowsTop < bottom && sourceRowsBottom > top;\n if (!measuredFileAnnotationVisible && !sourceRowsVisible) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n\n // Find which line is at viewport center\n const centerLine = Math.floor(\n measuredFileAnnotationVisible &&\n viewportCenter < fileTop + codeRegionTop\n ? 0\n : (viewportCenter - (fileTop + codeRegionTop)) / lineHeight\n );\n const centerHunk = Math.floor(centerLine / hunkLineCount);\n\n // Calculate ideal start centered around viewport\n const idealStartHunk = centerHunk - Math.floor(totalHunks / 2);\n const totalHunksInFile = Math.ceil(lineCount / hunkLineCount);\n const startingLine =\n Math.max(0, Math.min(idealStartHunk, totalHunksInFile)) * hunkLineCount;\n\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n const bufferBefore =\n startingLine === 0\n ? 0\n : fileAnnotationHeight + startingLine * lineHeight;\n const renderedLines = Math.min(\n clampedTotalLines,\n lineCount - startingLine\n );\n const bufferAfter = Math.max(\n 0,\n (lineCount - startingLine - renderedLines) * lineHeight\n );\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n\n // Complex case: need to account for line annotations or wrap overflow\n const overflowHunks = totalHunks;\n const hunkOffsets: number[] = [];\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 ?? codeRegionTop);\n let currentLine = checkpoint?.lineIndex ?? 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n const startingLineIndex = checkpoint?.lineIndex ?? 0;\n for (\n let lineIndex = startingLineIndex;\n lineIndex < lineCount;\n lineIndex++\n ) {\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n const currentHunk = Math.floor(currentLine / hunkLineCount);\n\n if (isAtHunkBoundary) {\n hunkOffsets[currentHunk] = absoluteLineTop - (fileTop + codeRegionTop);\n\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n break;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(lineIndex, false);\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 (absoluteLineTop + lineHeight > viewportCenter) {\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\n // No visible lines found\n if (firstVisibleHunk == null) {\n if (measuredFileAnnotationVisible) {\n firstVisibleHunk = 0;\n centerHunk = 0;\n } else {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n }\n\n // Calculate balanced startingLine centered around the viewport center\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift\n // 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 codeBufferBefore = hunkOffsets[startHunk] ?? 0;\n const bufferBefore =\n startingLine === 0 ? 0 : fileAnnotationHeight + codeBufferBefore;\n\n // Calculate bufferAfter\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? codeRowsHeight - hunkOffsets[finalHunkIndex]\n : codeRowsHeight - (absoluteLineTop - fileTop - codeRegionTop);\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter: Math.max(0, bufferAfter),\n };\n }\n}\n\nfunction measureFileAnnotationHeight(content: HTMLElement): number | undefined {\n let height: number | undefined;\n for (const child of content.children) {\n if (!(child instanceof HTMLElement)) {\n continue;\n }\n if (child.dataset.lineAnnotation !== FILE_ANNOTATION_DOM_KEY) {\n continue;\n }\n height = Math.max(height ?? 0, child.getBoundingClientRect().height);\n }\n return height;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"VirtualizedFile.js","names":[],"sources":["../../src/components/VirtualizedFile.ts"],"sourcesContent":["import { DEFAULT_VIRTUAL_FILE_METRICS } from '../constants';\nimport type { TextDocument } from '../editor/textDocument';\nimport type {\n FileContents,\n LineAnnotation,\n NumericScrollLineAnchor,\n PendingCodeViewLayoutReset,\n RenderRange,\n RenderWindow,\n StickySpecs,\n ThemeTypes,\n VirtualFileMetrics,\n} from '../types';\nimport { areFileTargetsEqual } from '../utils/areFileTargetsEqual';\nimport { areObjectsEqual } from '../utils/areObjectsEqual';\nimport { areOptionsEqual } from '../utils/areOptionsEqual';\nimport {\n computeVirtualFileMetrics,\n getVirtualFileHeaderRegion,\n getVirtualFilePaddingBottom,\n} from '../utils/computeVirtualFileMetrics';\nimport {\n FILE_ANNOTATION_DOM_KEY,\n FILE_ANNOTATION_LINE_NUMBER,\n includesFileAnnotations,\n shouldRenderFileAnnotations,\n} from '../utils/includesFileAnnotations';\nimport type { WorkerPoolManager } from '../worker';\nimport type { CodeView } from './CodeView';\nimport { File, type FileOptions, type FileRenderProps } from './File';\nimport type { Virtualizer } from './Virtualizer';\n\ninterface FileLayoutCheckpoint {\n lineIndex: number;\n top: number;\n}\n\ninterface FileLayoutCache {\n // Sparse map: line index -> measured height. Only stores lines that differ\n // 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 // line or scroll offset instead of replaying layout from the start.\n checkpoints: FileLayoutCheckpoint[];\n // Measured height for the file-level annotation row. Starts at 0 so\n // unmeasured annotations behave like all other unmeasured annotations.\n fileAnnotationHeight: number;\n // Ghost text rows folded into `heights` (zero-based line -> row count), so an\n // entry can be corrected when the editor's ghost text changes or goes away.\n ghostTextRows: ReadonlyMap<number, number>;\n}\n\ninterface PendingRender {\n latestFile: FileContents;\n file: FileContents;\n}\n\nconst LAYOUT_CHECKPOINT_INTERVAL = 5_000;\nconst NO_GHOST_TEXT_ROWS: ReadonlyMap<number, number> = new Map();\n\nlet instanceId = -1;\n\nfunction hasFileLayoutOptionChanged<LAnnotation, Caret>(\n previousOptions: FileOptions<LAnnotation, Caret>,\n nextOptions: FileOptions<LAnnotation, Caret>\n): boolean {\n return (\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.unsafeCSS !== nextOptions.unsafeCSS\n );\n}\n\nexport class VirtualizedFile<\n LAnnotation = undefined,\n Caret = undefined,\n> extends File<LAnnotation, Caret> {\n override readonly __id: string = `virtualized-file:${++instanceId}`;\n public readonly renderType = 'virtualized';\n\n public top: number | undefined;\n public height: number = 0;\n private cache: FileLayoutCache = {\n heights: new Map(),\n checkpoints: [],\n fileAnnotationHeight: 0,\n ghostTextRows: NO_GHOST_TEXT_ROWS,\n };\n // Remember which file the layout was calculated from, even when only a\n // placeholder is rendered. Async highlighting clears this through rerender()\n // so layout can use the newly available content. CodeView updates it during\n // its layout pass.\n private pendingRender: PendingRender | undefined;\n private isVisible: boolean = false;\n private isSetup: boolean = false;\n private layoutDirty = true;\n private forceRenderOverride: true | undefined;\n private currentCollapsed: boolean | undefined;\n\n constructor(\n options: FileOptions<LAnnotation, Caret> | undefined,\n private virtualizer: Virtualizer | CodeView<LAnnotation, Caret>,\n private metrics: VirtualFileMetrics = DEFAULT_VIRTUAL_FILE_METRICS,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\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 override setLineAnnotations(\n lineAnnotations: LineAnnotation<LAnnotation>[]\n ): void {\n if (this.syncLineAnnotations(lineAnnotations)) {\n this.forceRenderOverride = true;\n }\n }\n\n // Keep measured row heights as estimates when annotations change; rendering\n // will replace them with the updated heights without discarding other rows.\n private syncLineAnnotations(\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined\n ): boolean {\n if (lineAnnotations == null || !this.isNewAnnotations(lineAnnotations)) {\n return false;\n }\n if (\n lineAnnotations.length === 0 &&\n this.getLatestAnnotations().length === 0\n ) {\n return false;\n }\n\n super.setLineAnnotations(lineAnnotations);\n return true;\n }\n\n protected override syncEditSessionAnnotationsFromEditor(\n lineAnnotations: LineAnnotation<LAnnotation>[]\n ): boolean {\n if (super.syncEditSessionAnnotationsFromEditor(lineAnnotations)) {\n this.forceRenderOverride = true;\n return true;\n }\n return false;\n }\n\n private hasLineAnnotations(): boolean {\n return this.getLatestAnnotations().some(\n (annotation) => annotation.lineNumber > FILE_ANNOTATION_LINE_NUMBER\n );\n }\n\n // Every line is exactly one line height tall, so positions can be multiplied\n // instead of walked: no wrapping, no line annotations, and nothing cached (in\n // such files the cache only fills because of ghost text rows).\n private hasUniformLineHeights(): boolean {\n const { overflow = 'scroll' } = this.options;\n return (\n overflow === 'scroll' &&\n !this.hasLineAnnotations() &&\n this.cache.heights.size === 0\n );\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\n // metadata.\n public 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(\n options: FileOptions<LAnnotation, Caret> | undefined\n ): void {\n if (this.isAdvancedMode()) {\n throw new Error(\n 'VirtualizedFile.setOptions cannot be used inside CodeView. Update CodeView options instead.'\n );\n }\n\n if (options == null) return;\n const { options: previousOptions } = this;\n const optionsChanged = !areOptionsEqual(previousOptions, options);\n const layoutChanged = hasFileLayoutOptionChanged(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) {\n this.virtualizer.instanceChanged(this, layoutChanged);\n }\n }\n\n override setThemeType(themeType: ThemeTypes): void {\n if (this.isAdvancedMode()) {\n throw new Error(\n 'VirtualizedFile.setThemeType cannot be used inside CodeView. Update CodeView options instead.'\n );\n }\n\n super.setThemeType(themeType);\n }\n\n private resetLayoutCache(recompute = false, resetRenderRange = true): void {\n this.layoutDirty = true;\n this.cache.fileAnnotationHeight = 0;\n if (this.cache.heights.size > 0) {\n this.cache.heights.clear();\n }\n if (this.cache.checkpoints.length > 0) {\n this.cache.checkpoints.length = 0;\n }\n this.cache.ghostTextRows = NO_GHOST_TEXT_ROWS;\n if (this.renderRange != null && resetRenderRange) {\n this.renderRange = undefined;\n }\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 // Fold the ghost text rows the editor is showing below lines into the height\n // cache (zero-based line -> row count). Ghost text sits in a margin below the\n // row, which measuring never includes, so the rows are added here on top of\n // the line's own height, and removed again when the ghost text changes or\n // goes away, even for rows that are not rendered right now.\n private applyGhostTextRows(\n ghostTextRows: ReadonlyMap<number, number>\n ): boolean {\n const { heights, ghostTextRows: previous } = this.cache;\n if (previous === ghostTextRows) {\n return false;\n }\n const { lineHeight } = this.metrics;\n let changed = false;\n for (const lineIndex of new Set([\n ...previous.keys(),\n ...ghostTextRows.keys(),\n ])) {\n const previousRows = previous.get(lineIndex) ?? 0;\n const rows = ghostTextRows.get(lineIndex) ?? 0;\n if (rows === previousRows) {\n continue;\n }\n const ownHeight =\n (heights.get(lineIndex) ?? lineHeight) - previousRows * lineHeight;\n const height = ownHeight + rows * lineHeight;\n if (height === lineHeight) {\n heights.delete(lineIndex);\n } else {\n heights.set(lineIndex, height);\n }\n changed = true;\n }\n this.cache.ghostTextRows = ghostTextRows;\n return changed;\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n public reconcileHeights(): boolean {\n let hasHeightChange = false;\n if (this.fileContainer == null || this.getLayoutFile() == null) {\n if (this.height !== 0) {\n hasHeightChange = true;\n }\n this.height = 0;\n return hasHeightChange;\n }\n const { overflow = 'scroll' } = this.options;\n this.top = this.getVirtualizedTop();\n const ghostTextRows =\n this.editor?.__getGhostTextRows() ?? NO_GHOST_TEXT_ROWS;\n hasHeightChange = this.applyGhostTextRows(ghostTextRows);\n const measureAllRows =\n overflow !== 'scroll' ||\n this.getLatestAnnotations().length > 0 ||\n this.isResizeDebuggingEnabled();\n\n // Ghost-row changes affect placeholders too, but placeholders have no DOM\n // rows to measure. After the last annotation is removed, keep measuring\n // rendered rows until their previously cached heights have been corrected.\n if (\n this.placeHolder != null ||\n (!measureAllRows &&\n this.cache.heights.size === 0 &&\n this.cache.fileAnnotationHeight === 0)\n ) {\n if (hasHeightChange) {\n this.computeApproximateSize(true);\n this.setPlaceholderHeight(this.height);\n }\n return hasHeightChange;\n }\n const { lineHeight } = this.metrics;\n\n // Single code element (no split mode)\n if (this.code == null) {\n return hasHeightChange;\n }\n const content = this.code.children[1]; // Content column (gutter is [0])\n if (!(content instanceof HTMLElement)) {\n return hasHeightChange;\n }\n\n // Keep offscreen file annotation measurements consistent with the buffers\n // computed for this render. A rendered top row can confirm their removal.\n if (\n this.renderRange != null &&\n shouldRenderFileAnnotations(this.renderRange)\n ) {\n const fileAnnotationHeight = measureFileAnnotationHeight(content);\n const nextFileAnnotationHeight = fileAnnotationHeight ?? 0;\n if (nextFileAnnotationHeight !== this.cache.fileAnnotationHeight) {\n this.cache.fileAnnotationHeight = nextFileAnnotationHeight;\n hasHeightChange = true;\n }\n }\n\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 = Number(lineIndexAttr);\n const ghostHeight = (ghostTextRows.get(lineIndex) ?? 0) * lineHeight;\n const cachedHeight = this.cache.heights.get(lineIndex);\n // With no annotations or wrapping, only stale custom measurements need\n // DOM reads. Ghost rows already have known heights from the editor.\n if (\n !measureAllRows &&\n (cachedHeight == null || cachedHeight === lineHeight + ghostHeight)\n ) {\n continue;\n }\n let measuredHeight = line.getBoundingClientRect().height + ghostHeight;\n let hasMetadata = false;\n\n // Annotations or noNewline metadata increase the size of their 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\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 (measuredHeight === this.metrics.lineHeight * (hasMetadata ? 2 : 1)) {\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 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 || this.file == null) {\n return false;\n }\n if (dirty) {\n this.top = this.getVirtualizedTop();\n }\n return this.render({ file: this.file });\n };\n\n // CodeView positions every item before updating the DOM. Recalculate this\n // item's layout whenever its content or position changes.\n public updateCodeViewLayout(\n file: FileContents,\n top: number,\n reset?: PendingCodeViewLayoutReset,\n lineAnnotations?: LineAnnotation<LAnnotation>[]\n ): number {\n const targetChanged = !areFileTargetsEqual(this.file, file);\n if (targetChanged) {\n this.updateExternalFile(file, lineAnnotations);\n }\n const {\n pendingRenderFile,\n layoutFileChanged,\n renderedFileChanged,\n annotationsChanged,\n } = this.updatePendingRender(file, lineAnnotations);\n let shouldResetLayoutCache =\n reset?.resetFileLayoutCache === true || layoutFileChanged;\n if (reset?.metrics != null) {\n this.metrics = reset.metrics;\n shouldResetLayoutCache = true;\n }\n\n const { collapsed = false } = this.options;\n if (this.currentCollapsed !== collapsed) {\n this.currentCollapsed = collapsed;\n shouldResetLayoutCache = true;\n }\n\n if (shouldResetLayoutCache) {\n this.resetLayoutCache();\n }\n\n if (targetChanged) {\n this.layoutDirty = true;\n }\n if (\n !this.forceRenderOverride &&\n (targetChanged || renderedFileChanged || annotationsChanged)\n ) {\n this.forceRenderOverride = true;\n }\n this.top = top;\n this.computeApproximateSize(false, pendingRenderFile);\n return this.height;\n }\n\n // CodeView calculates layout before it renders the next item. Keep every\n // geometry read in that frame tied to the file selected for that render.\n private getLayoutFile(): FileContents | undefined {\n return this.pendingRender?.file ?? this.getRenderedFile();\n }\n\n public getLinePosition(\n lineNumber: number\n ): { top: number; height: number } | undefined {\n const file = this.getLayoutFile();\n if (file == null || lineNumber < 1) {\n return undefined;\n }\n\n const { disableFileHeader = false, collapsed = false } = this.options;\n const lastLineIndex = this.fileRenderer.getLineCount(file) - 1;\n let top = getVirtualFileHeaderRegion(this.metrics, disableFileHeader);\n\n if (collapsed || lastLineIndex < 0) {\n return { top, height: 0 };\n }\n\n const clampedLineIndex = Math.min(\n Math.max(lineNumber - 1, 0),\n lastLineIndex\n );\n const { lineHeight } = this.metrics;\n top += this.cache.fileAnnotationHeight;\n\n if (this.hasUniformLineHeights()) {\n return {\n top: top + clampedLineIndex * lineHeight,\n height: lineHeight,\n };\n }\n\n const checkpoint =\n this.getLayoutCheckpointBeforeLineIndex(clampedLineIndex);\n top = checkpoint?.top ?? top;\n for (\n let lineIndex = checkpoint?.lineIndex ?? 0;\n lineIndex < clampedLineIndex;\n lineIndex++\n ) {\n top += this.getLineHeight(lineIndex, false);\n }\n\n return {\n top,\n height: this.getLineHeight(clampedLineIndex, false),\n };\n }\n\n public getEditorViewport(): HTMLElement | Document | undefined {\n return this.virtualizer.type === 'simple'\n ? this.virtualizer.getRoot()\n : this.virtualizer.getContainerElement();\n }\n\n public getNumericScrollAnchor(\n localViewportTop: number\n ): NumericScrollLineAnchor | undefined {\n const file = this.getLayoutFile();\n if (file == null || this.renderRange == null) {\n return undefined;\n }\n\n const { disableFileHeader = false, collapsed = false } = this.options;\n if (collapsed || this.renderRange.totalLines <= 0) {\n return undefined;\n }\n\n const lastLineIndex = this.fileRenderer.getLineCount(file) - 1;\n if (lastLineIndex < 0) {\n return undefined;\n }\n\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const firstRenderedLineIndex = Math.min(\n this.renderRange.startingLine,\n lastLineIndex\n );\n const lastRenderedLineIndex = Math.min(\n firstRenderedLineIndex + this.renderRange.totalLines - 1,\n lastLineIndex\n );\n if (lastRenderedLineIndex < firstRenderedLineIndex) {\n return undefined;\n }\n const { fileAnnotationHeight } = this.cache;\n\n // When we have uniform line heights we can just multiply our way to the\n // correct value\n if (this.hasUniformLineHeights()) {\n const { lineHeight } = this.metrics;\n const firstRenderedLineTop =\n headerRegion +\n (firstRenderedLineIndex === 0\n ? fileAnnotationHeight\n : this.renderRange.bufferBefore);\n const deltaLineCount = Math.max(\n Math.ceil((localViewportTop - firstRenderedLineTop) / lineHeight),\n 0\n );\n const lineIndex = firstRenderedLineIndex + deltaLineCount;\n if (lineIndex > lastRenderedLineIndex) {\n return undefined;\n }\n\n return {\n lineNumber: lineIndex + 1,\n top: headerRegion + fileAnnotationHeight + lineIndex * lineHeight,\n };\n }\n\n // Otherwise we gotta iterate through the range\n let top =\n headerRegion +\n (firstRenderedLineIndex === 0\n ? fileAnnotationHeight\n : this.renderRange.bufferBefore);\n for (\n let lineIndex = firstRenderedLineIndex;\n lineIndex <= lastRenderedLineIndex;\n lineIndex++\n ) {\n if (top >= localViewportTop) {\n return {\n lineNumber: lineIndex + 1,\n top,\n };\n }\n top += this.getLineHeight(lineIndex);\n }\n\n return undefined;\n }\n\n public getVirtualizedHeight(): number {\n return this.height;\n }\n\n public getAdvancedStickySpecs(\n windowSpecs?: RenderWindow\n ): StickySpecs | undefined {\n const file = this.getLayoutFile();\n if (this.top == null || file == 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(file, this.top, windowSpecs)\n : this.renderRange;\n if (renderRange == null) {\n return undefined;\n }\n const { bufferBefore, bufferAfter, totalLines } = renderRange;\n // Rendered items flow contiguously in the sticky container with no buffer\n // spacers, so a header-only item (totalLines === 0, none of its rows fall\n // inside the window) must report where its header actually sits in that\n // flow, which depends on which side of the window its content is on:\n // - content ABOVE the window (item starts above window.top): the header\n // sits at the item's bottom so the following item connects, so offset by\n // bufferAfter.\n // - content BELOW the window (item starts at/after window.top, e.g. a\n // trailing header peeking in at the bottom): the header renders at the\n // item's top with nothing after it, so no offset. Always adding\n // bufferAfter here made getStickyBounds over-measure the sticky\n // container for that trailing case.\n let headerOnlyOffset = 0;\n if (totalLines === 0) {\n const activeWindow = windowSpecs ?? this.virtualizer.getWindowSpecs();\n if (this.top < activeWindow.top) {\n headerOnlyOffset = bufferAfter;\n }\n }\n return {\n topOffset: this.top + bufferBefore + headerOnlyOffset,\n height: this.height - (bufferBefore + bufferAfter),\n };\n }\n\n override cleanUp(recycle = false): void {\n // The editor's own cleanUp has already cleared its ghost text rows without\n // asking for a layout pass. Mark the layout dirty so a pooled item drops the\n // folded rows on its next pass instead of keeping phantom height.\n const hadGhostTextRows = this.cache.ghostTextRows.size > 0;\n if (hadGhostTextRows) {\n this.layoutDirty = true;\n }\n const shouldRecomputeLayout =\n recycle &&\n this.isAdvancedMode() &&\n this.fileContainer != null &&\n (hadGhostTextRows ||\n !areFileTargetsEqual(this.getRenderedFile(), this.getLatestFile()));\n if (this.fileContainer != null && this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.disconnect(this.fileContainer);\n }\n if (!recycle) {\n this.resetLayoutCache();\n }\n this.pendingRender = undefined;\n this.isSetup = false;\n super.cleanUp(recycle);\n if (shouldRecomputeLayout) {\n this.virtualizer.instanceChanged(this, true);\n }\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\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(\n force = false,\n file: FileContents | undefined = this.getLayoutFile()\n ): 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 if (file == null) {\n this.layoutDirty = false;\n return;\n }\n this.applyGhostTextRows(\n this.editor?.__getGhostTextRows() ?? NO_GHOST_TEXT_ROWS\n );\n\n const { disableFileHeader = false, collapsed = false } = this.options;\n const { lineHeight } = this.metrics;\n const lineCount = this.fileRenderer.getLineCount(file);\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 this.height += this.cache.fileAnnotationHeight;\n\n if (this.hasUniformLineHeights()) {\n this.height += lineCount * lineHeight;\n } else {\n for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {\n this.addLayoutCheckpoint(lineIndex, this.height);\n this.height += this.getLineHeight(lineIndex, false);\n }\n }\n\n if (lineCount > 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 'VirtualizedFile.computeApproximateSize: computed height doesnt match',\n {\n name: file.name,\n elementHeight: rect.height,\n computedHeight: this.height,\n }\n );\n } else {\n console.log(\n 'VirtualizedFile.computeApproximateSize: computed height IS CORRECT'\n );\n }\n }\n this.layoutDirty = false;\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 (!this.enabled || this.file == null) {\n return;\n }\n const latestFile = this.getLatestFile();\n const nextRenderFile =\n latestFile == null\n ? undefined\n : this.fileRenderer.getFileForNextRender(latestFile);\n // A completed async highlight can change which file the next simple\n // virtualizer render will commit. CodeView refreshes this during layout.\n if (this.isSimpleMode()) {\n this.pendingRender = undefined;\n }\n this.forceRenderOverride = true;\n this.virtualizer.instanceChanged(\n this,\n !areFileTargetsEqual(this.getRenderedFile(), nextRenderFile)\n );\n }\n\n // The editor changed the ghost text rows it shows below lines. Ask the\n // virtualizer for a layout pass, which folds them in (see\n // applyGhostTextRows). Layout state only changes inside that pass.\n public syncGhostTextRows(): void {\n const codeView = this.getAdvancedVirtualizer();\n if (codeView != null) {\n codeView.capturePendingLayoutAnchor();\n this.layoutDirty = true;\n codeView.instanceChanged(this, true);\n } else {\n this.getSimpleVirtualizer()?.requestHeightReconcile(this);\n }\n }\n\n // normally triggered by the host when the document line count changes\n override applyDocumentChange(\n textDocument: TextDocument<'file', LAnnotation>,\n newLineAnnotations?: LineAnnotation<LAnnotation>[],\n shouldUpdateBuffer = false\n ): void {\n const { renderRange: previousRenderRange } = this;\n // Capture the scroll anchor before the synchronous document swap and\n // layout-cache wipe below; the host's next frame resolves it against the\n // new geometry so on-screen rows do not shift.\n this.getAdvancedVirtualizer()?.capturePendingLayoutAnchor();\n super.applyDocumentChange(textDocument, newLineAnnotations);\n this.getSimpleVirtualizer()?.markDOMDirty();\n this.resetLayoutCache(this.isSimpleMode(), false);\n\n const file = this.getRenderedFile();\n if (!this.isSimpleMode()) {\n this.computeApproximateSize(true);\n } else if (\n shouldUpdateBuffer &&\n previousRenderRange != null &&\n file != null\n ) {\n // Update the buffers caused by the line-count change to ensure the host\n // scrolls to the correct position before re-rendering.\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const renderRange = this.computeRenderRangeFromWindow(\n file,\n this.top ?? 0,\n windowSpecs\n );\n if (renderRange.bufferAfter !== previousRenderRange.bufferAfter) {\n this.updateBuffers(renderRange);\n }\n }\n\n this.forceRenderOverride = true;\n this.virtualizer.instanceChanged(this, true);\n }\n\n override render({\n fileContainer,\n file,\n forceRender = false,\n lineAnnotations,\n ...props\n }: FileRenderProps<LAnnotation>): boolean {\n const didFileChange = !areFileTargetsEqual(this.file, file);\n if (didFileChange) {\n this.updateExternalFile(file, lineAnnotations);\n this.cachedHeaderHTML = undefined;\n }\n const {\n pendingRenderFile,\n layoutFileChanged,\n renderedFileChanged,\n annotationsChanged,\n } = (() => {\n if (\n this.pendingRender != null &&\n this.pendingRender.latestFile === (this.getLatestFile(file) ?? file)\n ) {\n return {\n pendingRenderFile: this.pendingRender.file,\n layoutFileChanged: false,\n renderedFileChanged: false,\n annotationsChanged: this.syncLineAnnotations(lineAnnotations),\n };\n }\n return this.updatePendingRender(file, lineAnnotations);\n })();\n const { forceRenderOverride, isSetup } = this;\n this.forceRenderOverride = undefined;\n if (layoutFileChanged) {\n this.resetLayoutCache();\n }\n\n fileContainer = this.getOrCreateFileContainerNode(fileContainer);\n\n if (!isSetup) {\n this.computeApproximateSize(false, pendingRenderFile);\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 'VirtualizedFile.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 if (this.layoutDirty && this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.markDOMDirty();\n this.computeApproximateSize(false, pendingRenderFile);\n }\n }\n\n // A hidden live instance receiving a changed file falls through to the\n // full render below so the base's change detection (header cache, stored\n // file) still runs; the placeholder path only serves unchanged data.\n if (\n !this.isVisible &&\n this.isSimpleMode() &&\n (!didFileChange || !isSetup)\n ) {\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 pendingRenderFile,\n fileTop,\n windowSpecs\n );\n return super.render({\n file,\n fileContainer,\n renderRange,\n lineAnnotations,\n forceRender:\n (forceRenderOverride ?? forceRender) ||\n annotationsChanged ||\n renderedFileChanged ||\n didFileChange,\n ...props,\n });\n }\n\n protected override finalizeRender(): void {\n if (this.getRenderedFile() !== this.pendingRender?.file) {\n throw new Error(\n 'VirtualizedFile.render: rendered a different file than its prepared layout'\n );\n }\n this.pendingRender = undefined;\n // Renders can be driven from outside the virtualizer (host/React render\n // calls, async highlight completions), and the virtualizer only\n // auto-reconciles renders it initiated. Queue a measured-height\n // reconciliation for every applied content render so line deltas\n // (wrapped lines, annotation heights) survive layout resets.\n if (this.isSimpleMode()) {\n this.getSimpleVirtualizer()?.requestHeightReconcile(this);\n }\n }\n\n private updatePendingRender(\n nextFile: FileContents,\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined\n ) {\n const latestFile = this.getLatestFile(nextFile) ?? nextFile;\n const previousRenderedFile = this.getRenderedFile();\n const previousLayoutFile = this.pendingRender?.file ?? previousRenderedFile;\n const pendingRenderFile =\n this.fileRenderer.getFileForNextRender(latestFile);\n\n this.pendingRender = { latestFile, file: pendingRenderFile };\n\n return {\n pendingRenderFile,\n annotationsChanged: this.syncLineAnnotations(lineAnnotations),\n layoutFileChanged: !areFileTargetsEqual(\n previousLayoutFile,\n pendingRenderFile\n ),\n renderedFileChanged: !areFileTargetsEqual(\n previousRenderedFile,\n pendingRenderFile\n ),\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 // This WebKit dom manipulation scroll fix is not applicable in virtualized\n // environments, so we avoid the performance hit even on Webkit\n protected override shouldGuardRebuildScroll(): boolean {\n return false;\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 addLayoutCheckpoint(lineIndex: number, top: number): void {\n if (lineIndex % LAYOUT_CHECKPOINT_INTERVAL !== 0) {\n return;\n }\n this.cache.checkpoints.push({ lineIndex, top });\n }\n\n // Find the nearest sparse layout checkpoint at or before a raw file line.\n // Checkpoints store measured `top` offsets every few thousand lines, so a\n // binary search lets deep line-position lookups resume from that checkpoint\n // instead of replaying layout from the start of the file.\n private getLayoutCheckpointBeforeLineIndex(\n lineIndex: number\n ): FileLayoutCheckpoint | 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: FileLayoutCheckpoint | 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('VirtualizedFile: 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 files\n // only replay the nearby measured rows. When `hunkLineCount` is provided,\n // step backward to a hunk boundary so hooks that depend on grouped lines\n // still see a complete hunk.\n private getLayoutCheckpointBeforeTop(\n top: number,\n hunkLineCount?: number\n ): FileLayoutCheckpoint | 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('VirtualizedFile: 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('VirtualizedFile: invalid checkpoint index');\n }\n if (checkpoint.lineIndex % hunkLineCount === 0) {\n return checkpoint;\n }\n }\n\n return undefined;\n }\n\n private getVirtualizedTop(): number {\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 getAdvancedVirtualizer(): CodeView<LAnnotation, Caret> | undefined {\n return this.virtualizer.type === 'advanced' ? this.virtualizer : undefined;\n }\n\n private isResizeDebuggingEnabled(): boolean {\n return this.getSimpleVirtualizer()?.config.resizeDebugging ?? false;\n }\n\n private computeRenderRangeFromWindow(\n file: FileContents,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const { disableFileHeader = false } = this.options;\n const { hunkLineCount, lineHeight } = this.metrics;\n const lineCount = this.fileRenderer.getLineCount(file);\n const fileHeight = this.height;\n const headerRegion = getVirtualFileHeaderRegion(\n this.metrics,\n disableFileHeader\n );\n const paddingBottom =\n lineCount > 0 ? getVirtualFilePaddingBottom(this.metrics) : 0;\n const { fileAnnotationHeight } = this.cache;\n const codeRegionTop = headerRegion + fileAnnotationHeight;\n const codeRowsHeight = Math.max(\n 0,\n fileHeight - headerRegion - fileAnnotationHeight - paddingBottom\n );\n const hasFileAnnotations = includesFileAnnotations(\n this.getLatestAnnotations()\n );\n const fileAnnotationTop = fileTop + headerRegion;\n const measuredFileAnnotationVisible =\n fileAnnotationHeight > 0 &&\n hasFileAnnotations &&\n fileAnnotationTop < bottom &&\n fileAnnotationTop + fileAnnotationHeight > top;\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 // Small file, just render it all\n if (lineCount <= hunkLineCount) {\n return {\n startingLine: 0,\n totalLines: hunkLineCount,\n bufferBefore: 0,\n bufferAfter: 0,\n };\n }\n\n // Calculate totalLines based on viewport size\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 viewportCenter = (top + bottom) / 2;\n // Simple case: every line is one line height tall - pure math!\n if (this.hasUniformLineHeights()) {\n const sourceRowsTop = fileTop + codeRegionTop;\n const sourceRowsBottom = sourceRowsTop + codeRowsHeight;\n const sourceRowsVisible =\n sourceRowsTop < bottom && sourceRowsBottom > top;\n if (!measuredFileAnnotationVisible && !sourceRowsVisible) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n\n // Find which line is at viewport center\n const centerLine = Math.floor(\n measuredFileAnnotationVisible &&\n viewportCenter < fileTop + codeRegionTop\n ? 0\n : (viewportCenter - (fileTop + codeRegionTop)) / lineHeight\n );\n const centerHunk = Math.floor(centerLine / hunkLineCount);\n\n // Calculate ideal start centered around viewport\n const idealStartHunk = centerHunk - Math.floor(totalHunks / 2);\n const totalHunksInFile = Math.ceil(lineCount / hunkLineCount);\n const startingLine =\n Math.max(0, Math.min(idealStartHunk, totalHunksInFile)) * hunkLineCount;\n\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n const bufferBefore =\n startingLine === 0\n ? 0\n : fileAnnotationHeight + startingLine * lineHeight;\n const renderedLines = Math.min(\n clampedTotalLines,\n lineCount - startingLine\n );\n const bufferAfter = Math.max(\n 0,\n (lineCount - startingLine - renderedLines) * lineHeight\n );\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n\n // Complex case: need to account for line annotations or wrap overflow\n const overflowHunks = totalHunks;\n const hunkOffsets: number[] = [];\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 ?? codeRegionTop);\n let currentLine = checkpoint?.lineIndex ?? 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n const startingLineIndex = checkpoint?.lineIndex ?? 0;\n for (\n let lineIndex = startingLineIndex;\n lineIndex < lineCount;\n lineIndex++\n ) {\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n const currentHunk = Math.floor(currentLine / hunkLineCount);\n\n if (isAtHunkBoundary) {\n hunkOffsets[currentHunk] = absoluteLineTop - (fileTop + codeRegionTop);\n\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n break;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(lineIndex, false);\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 (absoluteLineTop + lineHeight > viewportCenter) {\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\n // No visible lines found\n if (firstVisibleHunk == null) {\n if (measuredFileAnnotationVisible) {\n firstVisibleHunk = 0;\n centerHunk = 0;\n } else {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - paddingBottom,\n };\n }\n }\n\n // Calculate balanced startingLine centered around the viewport center\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift\n // 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 codeBufferBefore = hunkOffsets[startHunk] ?? 0;\n const bufferBefore =\n startingLine === 0 ? 0 : fileAnnotationHeight + codeBufferBefore;\n\n // Calculate bufferAfter\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? codeRowsHeight - hunkOffsets[finalHunkIndex]\n : codeRowsHeight - (absoluteLineTop - fileTop - codeRegionTop);\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter: Math.max(0, bufferAfter),\n };\n }\n}\n\nfunction measureFileAnnotationHeight(content: HTMLElement): number | undefined {\n let height: number | undefined;\n for (const child of content.children) {\n if (!(child instanceof HTMLElement)) {\n continue;\n }\n if (child.dataset.lineAnnotation !== FILE_ANNOTATION_DOM_KEY) {\n continue;\n }\n height = Math.max(height ?? 0, child.getBoundingClientRect().height);\n }\n return height;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizedFileDiff.d.ts","names":[],"sources":["../../src/components/VirtualizedFileDiff.ts"],"mappings":";;;;;;;;KAwDK,4BAA4B,QAC/B,WAAW,YAAY;cA4DZ;cAKA,oBACX,yBACA,2BACQ,SAAS,aAAa;WACZ;WACF;EAET;EACA;UACC;UACA;UAWA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UAGA;EAER,YACE,SAAS,gBAAgB,aAAa,oBACtC,aAAa,cAAc,SAAS,aAAa,QACjD,UAAU,QAAQ,qBAClB,gBAAgB,mBAChB;EAOK,WACL,UAAU,QAAQ,qBAClB;EAWO,mBACP,iBAAiB,mBAAmB;UAO9B;YAcW,qCACjB,iBAAiB,mBAAmB;UAS9B;UAWA;UAsBA;UAOA;EAKC,WACP,SAAS,gBAAgB,aAAa;EAmC/B,aAAa,WAAW;UAUzB;UAwBA;UA6BA;EAkDD;EAmHA,WAAQ;EAYC;EAST,qBACL,UAAU,kBACV,aACA,QAAQ,4BACR,kBAAkB,mBAAmB;EA2FhC,gBACL,oBACA,OAAM;IACH;IAAa;;EAgIX,qBAAqB,cAAc;EAMnC,uBACL,2BACC;EA+GI;EAIA,uBACL,cAAc,eACb;EAyCM,QAAQ;EA2BR,aAAU,mBACA,WACN,qBAAmB;YA2BP,kBACvB,cAAc,kBACd,OAAO,4BACN;YAmCgB;EAeV,iBAAiB;;;;;;;;;EA+CnB;YAkBY;YASA;EAMZ,cAAc;EAcZ;EA6BF;EAYE,oBACP,cAAc,0BAA0B,cACxC,qBAAqB,mBAAmB,gBACxC;UA6CM;UA8CA;UAIA;UAgBA;UAqCA;EAwBC,SACP,eACA,UACA,aACA,oBACG,mBACF,oBAAoB;YAkIJ;UAiBX;EA2BD;YAIY;YAMA;UAIX;UAIA;UAIA;UASA;UAIA;UAIA;UAIA;UAIA;UAIA;UA+LA;UAiCA;UAuCA;UAuDA;UAkBA"}
1
+ {"version":3,"file":"VirtualizedFileDiff.d.ts","names":[],"sources":["../../src/components/VirtualizedFileDiff.ts"],"mappings":";;;;;;;;KAwDK,4BAA4B,QAC/B,WAAW,YAAY;cA4DZ;cAKA,oBACX,yBACA,2BACQ,SAAS,aAAa;WACZ;WACF;EAET;EACA;UACC;UACA;UAWA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UAKA;EAER,YACE,SAAS,gBAAgB,aAAa,oBACtC,aAAa,cAAc,SAAS,aAAa,QACjD,UAAU,QAAQ,qBAClB,gBAAgB,mBAChB;EAOK,WACL,UAAU,QAAQ,qBAClB;EAWO,mBACP,iBAAiB,mBAAmB;UAS9B;YAcW,qCACjB,iBAAiB,mBAAmB;UAS9B;UAWA;UAsBA;UAOA;EAKC,WACP,SAAS,gBAAgB,aAAa;EAmC/B,aAAa,WAAW;UAUzB;UAwBA;UA6BA;EAkDD;EA+HA,WAAQ;EAYC;EAST,qBACL,UAAU,kBACV,aACA,QAAQ,4BACR,kBAAkB,mBAAmB;EAuFhC,gBACL,oBACA,OAAM;IACH;IAAa;;EAgIX,qBAAqB,cAAc;EAMnC,uBACL,2BACC;EA+GI;EAIA,uBACL,cAAc,eACb;EAyCM,QAAQ;EA2BR,aAAU,mBACA,WACN,qBAAmB;YA2BP,kBACvB,cAAc,kBACd,OAAO,4BACN;YAmCgB;EAeV,iBAAiB;;;;;;;;;EA+CnB;YAkBY;YASA;EAMZ,cAAc;EAcZ;EA6BF;EAYE,oBACP,cAAc,0BAA0B,cACxC,qBAAqB,mBAAmB,gBACxC;UA6CM;UA8CA;UAIA;UAgBA;UAqCA;EAwBC,SACP,eACA,UACA,aACA,oBACG,mBACF,oBAAoB;YAiIJ;UAmBX;EA2BD;YAIY;YAMA;UAIX;UAIA;UAIA;UASA;UAIA;UAIA;UAIA;UAIA;UAIA;UA+LA;UAiCA;UAuCA;UAuDA;UAkBA"}
@@ -55,7 +55,7 @@ var VirtualizedFileDiff = class extends FileDiff {
55
55
  this.resetLayoutCache({ includeEstimatedHeights: true });
56
56
  }
57
57
  setLineAnnotations(lineAnnotations) {
58
- if (this.syncLineAnnotations(lineAnnotations)) this.resetLayoutCache({ includeEstimatedHeights: false });
58
+ if (this.syncLineAnnotations(lineAnnotations)) this.forceRenderOverride = true;
59
59
  }
60
60
  syncLineAnnotations(lineAnnotations) {
61
61
  if (lineAnnotations == null || !this.isNewAnnotations(lineAnnotations) || lineAnnotations.length === 0 && this.getLatestAnnotations().length === 0) return false;
@@ -64,7 +64,7 @@ var VirtualizedFileDiff = class extends FileDiff {
64
64
  }
65
65
  syncEditSessionAnnotationsFromEditor(lineAnnotations) {
66
66
  if (super.syncEditSessionAnnotationsFromEditor(lineAnnotations)) {
67
- this.resetLayoutCache({ includeEstimatedHeights: false });
67
+ this.forceRenderOverride = true;
68
68
  return true;
69
69
  }
70
70
  return false;
@@ -157,8 +157,8 @@ var VirtualizedFileDiff = class extends FileDiff {
157
157
  }
158
158
  reconcileHeights() {
159
159
  let hasHeightChange = false;
160
- const { options: { overflow = "scroll" }, cache: { ghostTextRowsByIndex }, metrics: { lineHeight } } = this;
161
- const fileDiff = this.getRenderedDiff();
160
+ const { options: { overflow = "scroll" }, metrics: { lineHeight } } = this;
161
+ const fileDiff = this.placeHolder != null ? this.getLayoutDiff() : this.getRenderedDiff();
162
162
  if (this.fileContainer == null || fileDiff == null) {
163
163
  if (this.height !== 0) hasHeightChange = true;
164
164
  this.height = 0;
@@ -166,18 +166,21 @@ var VirtualizedFileDiff = class extends FileDiff {
166
166
  }
167
167
  this.top = this.getVirtualizedTop();
168
168
  hasHeightChange = this.applyGhostTextRows(fileDiff, this.editor?.__getGhostTextRows() ?? NO_GHOST_TEXT_ROWS);
169
- const lineAnnotations = this.getLatestAnnotations();
170
- if (overflow === "scroll" && lineAnnotations.length === 0 && !this.isResizeDebuggingEnabled()) {
171
- if (hasHeightChange) this.computeApproximateSize(true);
169
+ const { ghostTextRowsByIndex } = this.cache;
170
+ const measureAllRows = overflow !== "scroll" || this.getLatestAnnotations().length > 0 || this.isResizeDebuggingEnabled();
171
+ if (this.placeHolder != null || !measureAllRows && this.cache.heightDeltas.size === 0 && this.cache.fileAnnotationHeight === 0) {
172
+ if (hasHeightChange) {
173
+ this.computeApproximateSize(true);
174
+ this.setPlaceholderHeight(this.height);
175
+ }
172
176
  return hasHeightChange;
173
177
  }
174
178
  const diffStyle = this.getDiffStyle();
175
179
  const codeGroups = diffStyle === "split" ? [this.codeDeletions, this.codeAdditions] : [this.codeUnified];
176
- const hasFileAnnotations = this.hasFileAnnotations(fileDiff);
177
- if (this.renderRange != null && hasFileAnnotations && shouldRenderFileAnnotations(this.renderRange)) {
180
+ if (this.renderRange != null && shouldRenderFileAnnotations(this.renderRange)) {
178
181
  const nextFileAnnotationHeight = measureFileAnnotationHeight(codeGroups) ?? 0;
179
182
  if (this.setFileAnnotationHeight(nextFileAnnotationHeight)) hasHeightChange = true;
180
- } else if (!hasFileAnnotations && this.setFileAnnotationHeight(0)) hasHeightChange = true;
183
+ }
181
184
  for (const codeGroup of codeGroups) {
182
185
  if (codeGroup == null) continue;
183
186
  const content = codeGroup.children[1];
@@ -190,6 +193,8 @@ var VirtualizedFileDiff = class extends FileDiff {
190
193
  const lineIndex = parseLineIndex(lineIndexAttr, diffStyle);
191
194
  const ghostRows = ghostTextRowsByIndex.get(lineIndex) ?? 0;
192
195
  if (skipsGhostRows && ghostRows > 0) continue;
196
+ const previousDelta = this.cache.heightDeltas.get(lineIndex) ?? 0;
197
+ if (!measureAllRows && previousDelta === ghostRows * lineHeight) continue;
193
198
  let measuredHeight = line.getBoundingClientRect().height + ghostRows * lineHeight;
194
199
  let hasMetadata = false;
195
200
  if (line.nextElementSibling instanceof HTMLElement && ("lineAnnotation" in line.nextElementSibling.dataset || "noNewline" in line.nextElementSibling.dataset)) {
@@ -197,7 +202,6 @@ var VirtualizedFileDiff = class extends FileDiff {
197
202
  measuredHeight += line.nextElementSibling.getBoundingClientRect().height;
198
203
  }
199
204
  const estimatedHeight = this.getEstimatedLineHeight(hasMetadata);
200
- const previousDelta = this.cache.heightDeltas.get(lineIndex) ?? 0;
201
205
  const nextDelta = measuredHeight - estimatedHeight;
202
206
  if (nextDelta === previousDelta) continue;
203
207
  hasHeightChange = true;
@@ -227,7 +231,7 @@ var VirtualizedFileDiff = class extends FileDiff {
227
231
  if (pendingHydratedDiff.expectedDiff === fileDiff) {
228
232
  Object.assign(fileDiff, pendingHydratedDiff.nextDiff);
229
233
  this.setHydratedState(pendingHydratedDiff.files);
230
- this.startHydratedEditSession(fileDiff);
234
+ this.installHydratedSessionDiff(fileDiff);
231
235
  this.forceRenderOverride = true;
232
236
  resetLayoutCache = true;
233
237
  resetEstimatedHeights = true;
@@ -244,7 +248,7 @@ var VirtualizedFileDiff = class extends FileDiff {
244
248
  const diffChanged = this.updateExternalDiff(fileDiff, lineAnnotations);
245
249
  const { pendingRenderDiff, layoutDiffChanged, renderedDiffChanged, annotationsChanged } = this.updatePendingRender(fileDiff, lineAnnotations);
246
250
  if (!this.forceRenderOverride && (diffChanged || renderedDiffChanged || annotationsChanged)) this.forceRenderOverride = true;
247
- if (reset?.resetDiffLayoutCache === true || layoutDiffChanged || annotationsChanged) resetLayoutCache = true;
251
+ if (reset?.resetDiffLayoutCache === true || layoutDiffChanged) resetLayoutCache = true;
248
252
  if (layoutDiffChanged || reset?.resetDiffLayoutCache === true && reset.includeEstimatedDiffHeights) resetEstimatedHeights = true;
249
253
  if (reset?.metrics != null) {
250
254
  this.metrics = computeVirtualFileMetrics(reset.metrics);
@@ -436,6 +440,7 @@ var VirtualizedFileDiff = class extends FileDiff {
436
440
  }
437
441
  expandHunk = (hunkIndex, direction, expansionLineCountOverride) => {
438
442
  if (this.fileDiff == null) return;
443
+ this.loadFilesIfNecessary();
439
444
  if (this.isAdvancedMode()) {
440
445
  this.pendingExpansions ??= [];
441
446
  this.pendingExpansions.push({
@@ -448,7 +453,6 @@ var VirtualizedFileDiff = class extends FileDiff {
448
453
  this.resetLayoutCache({ includeEstimatedHeights: true });
449
454
  this.computeApproximateSize();
450
455
  }
451
- this.loadFilesIfNecessary();
452
456
  this.forceRenderOverride = true;
453
457
  this.virtualizer.instanceChanged(this, true);
454
458
  };
@@ -457,7 +461,7 @@ var VirtualizedFileDiff = class extends FileDiff {
457
461
  if (this.isAdvancedMode()) {
458
462
  const nextDiff = hydratePartialDiff("clone", expectedDiff, files);
459
463
  await awaitWithTimeout(() => this.primeHighlightCache(nextDiff));
460
- if (!this.enabled || this.fileDiff !== expectedDiff) return;
464
+ if (this.fileDiff !== expectedDiff) return;
461
465
  this.pendingHydratedDiff = {
462
466
  expectedDiff,
463
467
  nextDiff,
@@ -466,9 +470,9 @@ var VirtualizedFileDiff = class extends FileDiff {
466
470
  } else {
467
471
  hydratePartialDiff("merge", expectedDiff, files);
468
472
  this.setHydratedState(files);
469
- if (!this.startHydratedEditSession(expectedDiff)) {
473
+ if (!this.installHydratedSessionDiff(expectedDiff)) {
470
474
  await awaitWithTimeout(() => this.primeHighlightCache(expectedDiff));
471
- if (!this.enabled || this.fileDiff !== expectedDiff) return;
475
+ if (this.fileDiff !== expectedDiff) return;
472
476
  }
473
477
  this.resetLayoutCache({ includeEstimatedHeights: true });
474
478
  this.computeApproximateSize();
@@ -667,11 +671,11 @@ var VirtualizedFileDiff = class extends FileDiff {
667
671
  pendingRenderDiff: this.pendingRender.diff,
668
672
  layoutDiffChanged: false,
669
673
  renderedDiffChanged: false,
670
- annotationsChanged: false
674
+ annotationsChanged: this.syncLineAnnotations(lineAnnotations)
671
675
  };
672
676
  return this.updatePendingRender(nextFileDiff, lineAnnotations);
673
677
  })();
674
- if (annotationsChanged || layoutDiffChanged) this.resetLayoutCache({ includeEstimatedHeights: layoutDiffChanged });
678
+ if (layoutDiffChanged) this.resetLayoutCache({ includeEstimatedHeights: true });
675
679
  if (!isSetup) {
676
680
  this.computeApproximateSize(false, pendingRenderDiff);
677
681
  const virtualizer = this.getSimpleVirtualizer();
@@ -685,7 +689,7 @@ var VirtualizedFileDiff = class extends FileDiff {
685
689
  this.isSetup = true;
686
690
  } else {
687
691
  this.top ??= this.getVirtualizedTop();
688
- if (layoutDiffChanged) {
692
+ if (this.layoutDirty && this.isSimpleMode()) {
689
693
  this.getSimpleVirtualizer()?.markDOMDirty();
690
694
  this.computeApproximateSize(false, pendingRenderDiff);
691
695
  }
@@ -696,7 +700,6 @@ var VirtualizedFileDiff = class extends FileDiff {
696
700
  this.additionFile = newFile;
697
701
  }
698
702
  if (targetChanged) this.clearReusableHeader();
699
- this.pendingRender = void 0;
700
703
  return this.renderPlaceholder(this.height);
701
704
  }
702
705
  const windowSpecs = this.virtualizer.getWindowSpecs();
@@ -713,7 +716,7 @@ var VirtualizedFileDiff = class extends FileDiff {
713
716
  });
714
717
  }
715
718
  finalizeRender() {
716
- if (this.getRenderedDiff() !== this.pendingRender?.diff) throw new Error("VirtualizedFileDiff.render: rendered a different diff than its prepared layout");
719
+ if (!areDiffTargetsEqual(this.getRenderedDiff(), this.pendingRender?.diff)) throw new Error("VirtualizedFileDiff.render: rendered a different diff than its prepared layout");
717
720
  this.pendingRender = void 0;
718
721
  if (this.isSimpleMode()) this.getSimpleVirtualizer()?.requestHeightReconcile(this);
719
722
  }