diff --git a/apps/diffshub/app/_components/CodeViewSidebar.tsx b/apps/diffshub/app/_components/CodeViewSidebar.tsx index 7a284c4a1..d2ff4b4fb 100644 --- a/apps/diffshub/app/_components/CodeViewSidebar.tsx +++ b/apps/diffshub/app/_components/CodeViewSidebar.tsx @@ -1,5 +1,6 @@ 'use client'; +import type { CodeViewHandle } from '@pierre/diffs/react'; import { IconComment, IconFileTree, @@ -28,6 +29,7 @@ import type { CodeViewFileTreeSource, CodeViewSavedCommentEntry, CodeViewSavedCommentItem, + CommentMetadata, } from './types'; import type { ThemeCycleControls } from './useThemeCycle'; import { WorkerPoolStatus } from './WorkerPoolStatus'; @@ -52,6 +54,7 @@ interface CodeViewSidebarProps { source: CodeViewFileTreeSource; streaming: boolean; themeCycle: ThemeCycleControls; + viewerRef: RefObject | null>; } export const CodeViewSidebar = memo(function CodeViewSidebar({ @@ -66,6 +69,7 @@ export const CodeViewSidebar = memo(function CodeViewSidebar({ source, streaming, themeCycle, + viewerRef, }: CodeViewSidebarProps) { const [activeTab, setActiveTab] = useState('files'); let totalCommentCount = 0; @@ -238,7 +242,7 @@ export const CodeViewSidebar = memo(function CodeViewSidebar({ toggleStatusPanel('systemMonitor')} - scrollRef={scrollRef} + viewerRef={viewerRef} themeCycle={themeCycle} /> diff --git a/apps/diffshub/app/_components/ReviewUI.tsx b/apps/diffshub/app/_components/ReviewUI.tsx index dce15054d..fc5370cdd 100644 --- a/apps/diffshub/app/_components/ReviewUI.tsx +++ b/apps/diffshub/app/_components/ReviewUI.tsx @@ -273,6 +273,7 @@ function ReviewUIInner({ domain, initialUrl, path }: ReviewUIProps) { source={treeSource} streaming={loadState === 'streaming'} themeCycle={themeCycle} + viewerRef={viewerRef} onSelectItem={handleSelectTreeItem} /> { private running: 0 | 1 | 2 = 0; private direction = 1; constructor( - private scrollRef: RefObject, + private viewerRef: RefObject | null>, private onStateChange?: (running: boolean) => unknown ) {} @@ -49,10 +50,17 @@ class AutoScrollTester { } render = () => { - if (this.running === 0 || this.scrollRef.current == null) { + const { current: viewerHandle } = this.viewerRef; + if (this.running === 0 || viewerHandle == null) { return; } - const { scrollHeight, scrollTop, clientHeight } = this.scrollRef.current; + const viewer = viewerHandle.getInstance(); + if (viewer == null) { + return; + } + const scrollHeight = viewer.getScrollHeight(); + const scrollTop = viewer.getScrollTop(); + const clientHeight = viewer.getHeight(); // The first scroll tick should always attempt to scroll if (this.running === 1) { @@ -68,8 +76,9 @@ class AutoScrollTester { this.stop(); return; } - this.scrollRef.current.scrollTo({ - top: + viewerHandle.scrollTo({ + type: 'position', + position: scrollTop + clientHeight * 2 * this.direction + Math.random() * DEFAULT_CODE_VIEW_FILE_METRICS.lineHeight, @@ -94,15 +103,15 @@ class AutoScrollTester { interface WorkerPoolStatusProps { expanded: boolean; onToggle(): void; - scrollRef: RefObject; themeCycle: ThemeCycleControls; + viewerRef: RefObject | null>; } export const WorkerPoolStatus = memo(function WorkerPoolStatus({ expanded, onToggle, - scrollRef, themeCycle, + viewerRef, }: WorkerPoolStatusProps) { const pool = useWorkerPool(); const [stats, setStats] = useState(undefined); @@ -127,8 +136,8 @@ export const WorkerPoolStatus = memo(function WorkerPoolStatus({ expanded={expanded} onToggle={onToggle} stats={stats} - scrollRef={scrollRef} themeCycle={themeCycle} + viewerRef={viewerRef} /> ) ); @@ -164,8 +173,8 @@ interface StatsDisplayProps { expanded: boolean; onToggle(): void; stats: WorkerStats; - scrollRef: RefObject; themeCycle: ThemeCycleControls; + viewerRef: RefObject | null>; } // Map worker pool status to a single icon component + color so the legend row @@ -207,12 +216,12 @@ function StatsDisplay({ expanded, onToggle, stats, - scrollRef, themeCycle, + viewerRef, }: StatsDisplayProps) { const [isBrrt, setIsBrrt] = useState(false); const [scrollTester] = useState( - () => new AutoScrollTester(scrollRef, setIsBrrt) + () => new AutoScrollTester(viewerRef, setIsBrrt) ); // Mirror the inline (F3) hint with an actual keybinding so the label diff --git a/packages/diffs/src/components/CodeView.ts b/packages/diffs/src/components/CodeView.ts index d8e1b297a..311e29c03 100644 --- a/packages/diffs/src/components/CodeView.ts +++ b/packages/diffs/src/components/CodeView.ts @@ -1,5 +1,4 @@ import { - CORE_CSS_ATTRIBUTE, DEFAULT_CODE_VIEW_FILE_METRICS, DEFAULT_CODE_VIEW_LAYOUT, DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, @@ -7,8 +6,6 @@ import { DEFAULT_THEMES, DIFFS_DEVELOPMENT_BUILD, DIFFS_TAG_NAME, - THEME_CSS_ATTRIBUTE, - UNSAFE_CSS_ATTRIBUTE, } from '../constants'; import type { SelectionWriteOptions } from '../managers/InteractionManager'; import { @@ -39,7 +36,6 @@ import { areOptionsEqual } from '../utils/areOptionsEqual'; import { areSelectionsEqual } from '../utils/areSelectionsEqual'; import { areThemesEqual } from '../utils/areThemesEqual'; import { createWindowFromScrollPosition } from '../utils/createWindowFromScrollPosition'; -import { isStyleNode } from '../utils/isStyleNode'; import { prefersReducedMotion } from '../utils/prefersReducedMotion'; import { roundToDevicePixel } from '../utils/roundToDevicePixel'; import type { WorkerPoolManager } from '../worker'; @@ -978,10 +974,12 @@ export class CodeView { this.promotePendingPooledElements(); let element = this.elementPool.pop(); while (element != null && !this.isElementPoolGenerationCurrent(element)) { + this.discardPooledElement(element); element = this.elementPool.pop(); } element ??= document.createElement(DIFFS_TAG_NAME); this.markElementPoolGenerationCurrent(element); + element.style.removeProperty('display'); return element; } @@ -990,6 +988,9 @@ export class CodeView { if (element != null && this.renderedItemOwnsFocus(element)) { this.shouldFixContainerFocus = true; } + if (element != null) { + element.style.display = 'none'; + } item.instance.cleanUp(true); item.element = undefined; @@ -997,8 +998,6 @@ export class CodeView { return; } - element.remove(); - this.cleanElement(element); this.queueElementForPool(element); } @@ -1018,30 +1017,9 @@ export class CodeView { } } - // Strip item-specific DOM while keeping the expensive shared shell assets - // that are valid for every item in this CodeView until shared options - // change. - private cleanElement(element: HTMLElement): void { - const { shadowRoot } = element; - if (shadowRoot != null) { - for (const child of Array.from(shadowRoot.children)) { - if (!isPooledShadowChild(child)) { - child.remove(); - } - } - } - - if (!this.isContainerManaged) { - element.replaceChildren(); - } - } - private queueElementForPool(element: HTMLElement): void { - const poolLimit = this.getElementPoolLimit(); - if ( - !this.isElementPoolGenerationCurrent(element) || - this.getElementPoolSize() >= poolLimit - ) { + if (!this.isElementPoolGenerationCurrent(element)) { + this.discardPooledElement(element); return; } @@ -1059,23 +1037,51 @@ export class CodeView { const { pendingElementPool: pendingElements } = this; this.pendingElementPool = []; - const poolLimit = this.getElementPoolLimit(); for (const element of pendingElements) { - if ( - this.isElementPoolGenerationCurrent(element) && - this.isElementClean(element) && - this.elementPool.length < poolLimit - ) { + if (!this.isElementPoolGenerationCurrent(element)) { + this.discardPooledElement(element); + } else if (this.isElementClean(element)) { this.elementPool.push(element); - } else if ( - this.isElementPoolGenerationCurrent(element) && - this.getElementPoolSize() < poolLimit - ) { + } else { this.pendingElementPool.push(element); } } } + private trimElementPoolToLimit(): void { + let overflow = this.getElementPoolSize() - this.getElementPoolLimit(); + if (overflow <= 0) { + return; + } + + const pendingDiscardCount = Math.min( + overflow, + this.pendingElementPool.length + ); + const pendingDiscarded = this.pendingElementPool.splice( + 0, + pendingDiscardCount + ); + overflow -= pendingDiscarded.length; + for (const element of pendingDiscarded) { + this.discardPooledElement(element); + } + + if (overflow <= 0) { + return; + } + + const pooledDiscarded = this.elementPool.splice(0, overflow); + for (const element of pooledDiscarded) { + this.discardPooledElement(element); + } + } + + private discardPooledElement(element: HTMLElement): void { + this.elementPoolTracker.delete(element); + element.remove(); + } + private isElementClean(element: HTMLElement): boolean { return element.childNodes.length === 0; } @@ -1085,6 +1091,12 @@ export class CodeView { } private clearElementPool(): void { + for (const element of this.elementPool) { + this.discardPooledElement(element); + } + for (const element of this.pendingElementPool) { + this.discardPooledElement(element); + } this.elementPool.length = 0; this.pendingElementPool.length = 0; } @@ -2676,6 +2688,7 @@ export class CodeView { this.reconcileRenderedItems(updatedItems); this.syncContainerHeight(); this.updateStickyPositioning(); + this.trimElementPoolToLimit(); // Now that the dom has been flushed and we've computed our updated // item/line metrics, we should attempt to resolve any scroll anchors and @@ -3409,18 +3422,6 @@ function hasCodeViewDiffEstimateOptionChanged( ); } -function isPooledShadowChild(child: Element): boolean { - if (child instanceof SVGElement) { - return true; - } - return ( - isStyleNode(child) && - (child.hasAttribute(CORE_CSS_ATTRIBUTE) || - child.hasAttribute(THEME_CSS_ATTRIBUTE) || - child.hasAttribute(UNSAFE_CSS_ATTRIBUTE)) - ); -} - function formatSelectedLineRange(range: SelectedLineRange): string { const start = formatSelectedLinePoint(range.start, range.side); const end = formatSelectedLinePoint(range.end, range.endSide ?? range.side); diff --git a/packages/diffs/src/components/File.ts b/packages/diffs/src/components/File.ts index 5bcbe78cd..4c3f9b012 100644 --- a/packages/diffs/src/components/File.ts +++ b/packages/diffs/src/components/File.ts @@ -282,10 +282,19 @@ export class File { const { overflow = 'scroll' } = this.options; this.interactionManager.setup(this.pre); - this.resizeManager.setup(this.pre, overflow === 'wrap'); + this.resizeManager.setup(this.pre, { + disableAnnotations: overflow === 'wrap', + columnVariables: this.shouldApplyColumnVariables(overflow) + ? 'apply' + : 'measure', + }); this.managersDirty = false; } + protected shouldApplyColumnVariables(overflow: 'scroll' | 'wrap'): boolean { + return overflow === 'scroll' && this.lineAnnotations.length > 0; + } + public cleanUp(recycle = false): void { this.emitPostRender(true); this.resizeManager.cleanUp(); @@ -1326,6 +1335,26 @@ export class File { for (const element of shadowRoot.children) { if (element instanceof SVGElement) { this.spriteSVG ??= element; + } else if (element instanceof HTMLPreElement) { + this.pre ??= element; + this.code = undefined; + this.appliedPreAttributes = undefined; + } else if ( + element instanceof HTMLElement && + 'diffsHeader' in element.dataset + ) { + this.headerElement ??= element; + this.lastRenderedHeaderHTML = undefined; + } else if ( + element instanceof HTMLElement && + element.dataset.virtualizerBuffer === 'before' + ) { + this.bufferBefore ??= element; + } else if ( + element instanceof HTMLElement && + element.dataset.virtualizerBuffer === 'after' + ) { + this.bufferAfter ??= element; } else if ( isStyleNode(element) && element.hasAttribute(THEME_CSS_ATTRIBUTE) diff --git a/packages/diffs/src/components/FileDiff.ts b/packages/diffs/src/components/FileDiff.ts index cf03eefec..7597cd2b3 100644 --- a/packages/diffs/src/components/FileDiff.ts +++ b/packages/diffs/src/components/FileDiff.ts @@ -464,7 +464,12 @@ export class FileDiff { const { diffStyle = 'split', overflow = 'scroll' } = this.options; this.interactionManager.setup(this.pre); - this.resizeManager.setup(this.pre, overflow === 'wrap'); + this.resizeManager.setup(this.pre, { + disableAnnotations: overflow === 'wrap', + columnVariables: this.shouldApplyColumnVariables(overflow) + ? 'apply' + : 'measure', + }); if (overflow === 'scroll' && diffStyle === 'split') { this.scrollSyncManager.setup( this.pre, @@ -477,6 +482,17 @@ export class FileDiff { this.managersDirty = false; } + protected shouldApplyColumnVariables(overflow: 'scroll' | 'wrap'): boolean { + if (typeof this.options.hunkSeparators === 'function') { + return true; + } + return ( + overflow === 'scroll' && + (this.lineAnnotations.length > 0 || + this.pre?.hasAttribute('data-has-merge-conflict') === true) + ); + } + public cleanUp(recycle: boolean = false): void { this.emitPostRender(true); this.resizeManager.cleanUp(); @@ -1226,6 +1242,28 @@ export class FileDiff { for (const element of shadowRoot.children) { if (element instanceof SVGElement) { this.spriteSVG ??= element; + } else if (element instanceof HTMLPreElement) { + this.pre ??= element; + this.codeUnified = undefined; + this.codeDeletions = undefined; + this.codeAdditions = undefined; + this.appliedPreAttributes = undefined; + } else if ( + element instanceof HTMLElement && + 'diffsHeader' in element.dataset + ) { + this.headerElement ??= element; + this.lastRenderedHeaderHTML = undefined; + } else if ( + element instanceof HTMLElement && + element.dataset.virtualizerBuffer === 'before' + ) { + this.bufferBefore ??= element; + } else if ( + element instanceof HTMLElement && + element.dataset.virtualizerBuffer === 'after' + ) { + this.bufferAfter ??= element; } else if ( isStyleNode(element) && element.hasAttribute(THEME_CSS_ATTRIBUTE) diff --git a/packages/diffs/src/components/VirtualizedFileDiff.ts b/packages/diffs/src/components/VirtualizedFileDiff.ts index d916083d8..e3a0dad90 100644 --- a/packages/diffs/src/components/VirtualizedFileDiff.ts +++ b/packages/diffs/src/components/VirtualizedFileDiff.ts @@ -67,7 +67,7 @@ interface ResetLayoutCacheOptions { includeEstimatedHeights?: boolean; } -const LAYOUT_CHECKPOINT_INTERVAL = 5_000; +export const VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL = 3_000; let instanceId = -1; @@ -966,7 +966,7 @@ export class VirtualizedFileDiff< lineIndex: startLineIndex + offset, top: checkpointTop, }); - nextCheckpoint += LAYOUT_CHECKPOINT_INTERVAL; + nextCheckpoint += VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL; } top += @@ -1495,8 +1495,9 @@ function lowerBound(values: number[], target: number): number { function getNextCheckpointIndex(renderedLineIndex: number): number { return ( - Math.ceil(renderedLineIndex / LAYOUT_CHECKPOINT_INTERVAL) * - LAYOUT_CHECKPOINT_INTERVAL + Math.ceil( + renderedLineIndex / VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL + ) * VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL ); } diff --git a/packages/diffs/src/managers/ResizeManager.ts b/packages/diffs/src/managers/ResizeManager.ts index 74e4900e6..d205ca5b4 100644 --- a/packages/diffs/src/managers/ResizeManager.ts +++ b/packages/diffs/src/managers/ResizeManager.ts @@ -6,8 +6,20 @@ interface CodeColumnUpdate { measuredNumberInlineSize?: number; } +interface CodeColumnVariableChanges { + codeWidthChanged: boolean; + numberWidthChanged: boolean; +} + type CodeUpdateMap = Map; +export type ResizeManagerColumnVariableMode = 'apply' | 'measure'; + +export interface ResizeManagerSetupOptions { + disableAnnotations: boolean; + columnVariables?: ResizeManagerColumnVariableMode; +} + interface AnnotationSetup { child1: HTMLElement; child2: HTMLElement; @@ -55,8 +67,12 @@ export class ResizeManager { ObservedAnnotationNodes | ObservedGridNodes >(); - setup(pre: HTMLPreElement, disableAnnotations: boolean): void { + setup( + pre: HTMLPreElement, + { disableAnnotations, columnVariables = 'apply' }: ResizeManagerSetupOptions + ): void { const annotationUpdates = new Set(); + const applyColumnVariables = columnVariables === 'apply'; let columnCount = 0; const observedNodes = new Map(this.observedNodes); this.observedNodes.clear(); @@ -109,6 +125,7 @@ export class ResizeManager { } else { item.numberWidth = 0; } + syncColumnVariableMode(item, applyColumnVariables); } else { item = { type: 'code', @@ -116,6 +133,7 @@ export class ResizeManager { numberElement, codeWidth: 'auto', numberWidth: 0, + applyColumnVariables, }; this.observedNodes.set(codeElement, item); this.observe(codeElement); @@ -368,32 +386,11 @@ export class ResizeManager { item.codeWidth = nextCodeWidth; item.numberWidth = nextNumberWidth; - if (codeWidthChanged) { - item.codeElement.style.setProperty( - '--diffs-column-width', - `${typeof nextCodeWidth === 'number' ? `${nextCodeWidth}px` : 'auto'}` - ); - } - - if (numberWidthChanged) { - item.codeElement.style.setProperty( - '--diffs-column-number-width', - `${nextNumberWidth === 0 ? 'auto' : `${nextNumberWidth}px`}` - ); - } - - if ( - codeWidthChanged || - (numberWidthChanged && nextCodeWidth !== 'auto') - ) { - const targetWidth = - typeof nextCodeWidth === 'number' - ? Math.max(nextCodeWidth - nextNumberWidth, 0) - : 0; - item.codeElement.style.setProperty( - '--diffs-column-content-width', - `${targetWidth > 0 ? `${targetWidth}px` : 'auto'}` - ); + if (item.applyColumnVariables) { + applyCodeColumnVariables(item, { + codeWidthChanged, + numberWidthChanged, + }); } } }; @@ -422,11 +419,63 @@ function resolveNumberWidth(inlineSize: number): number { return Math.max(Math.ceil(inlineSize), 0); } +function syncColumnVariableMode( + item: ObservedGridNodes, + applyColumnVariables: boolean +): void { + if (item.applyColumnVariables === applyColumnVariables) { + return; + } + + item.applyColumnVariables = applyColumnVariables; + if (applyColumnVariables) { + applyCodeColumnVariables(item, { + codeWidthChanged: true, + numberWidthChanged: true, + }); + } else { + removeCodeColumnVariables(item); + } +} + +function applyCodeColumnVariables( + item: ObservedGridNodes, + { codeWidthChanged, numberWidthChanged }: CodeColumnVariableChanges +): void { + const { codeElement, codeWidth, numberWidth } = item; + if (codeWidthChanged) { + codeElement.style.setProperty( + '--diffs-column-width', + `${typeof codeWidth === 'number' ? `${codeWidth}px` : 'auto'}` + ); + } + + if (numberWidthChanged) { + codeElement.style.setProperty( + '--diffs-column-number-width', + `${numberWidth === 0 ? 'auto' : `${numberWidth}px`}` + ); + } + + if (codeWidthChanged || (numberWidthChanged && codeWidth !== 'auto')) { + const targetWidth = + typeof codeWidth === 'number' ? Math.max(codeWidth - numberWidth, 0) : 0; + codeElement.style.setProperty( + '--diffs-column-content-width', + `${targetWidth > 0 ? `${targetWidth}px` : 'auto'}` + ); + } +} + +function removeCodeColumnVariables(item: ObservedGridNodes): void { + item.codeElement.style.removeProperty('--diffs-column-content-width'); + item.codeElement.style.removeProperty('--diffs-column-number-width'); + item.codeElement.style.removeProperty('--diffs-column-width'); +} + function cleanupStaleCodeItem(item: ObservedGridNodes): void { if (item.codeElement.isConnected) { - item.codeElement.style.removeProperty('--diffs-column-content-width'); - item.codeElement.style.removeProperty('--diffs-column-number-width'); - item.codeElement.style.removeProperty('--diffs-column-width'); + removeCodeColumnVariables(item); } } diff --git a/packages/diffs/src/types.ts b/packages/diffs/src/types.ts index c7d8f3f71..69486d31c 100644 --- a/packages/diffs/src/types.ts +++ b/packages/diffs/src/types.ts @@ -647,6 +647,7 @@ export interface ObservedGridNodes { numberElement: HTMLElement | null; codeWidth: number | 'auto'; numberWidth: number; + applyColumnVariables: boolean; } export type CodeColumnType = 'unified' | 'additions' | 'deletions'; diff --git a/packages/diffs/src/worker/WorkerPoolManager.ts b/packages/diffs/src/worker/WorkerPoolManager.ts index 16f3db8f6..a75d514a6 100644 --- a/packages/diffs/src/worker/WorkerPoolManager.ts +++ b/packages/diffs/src/worker/WorkerPoolManager.ts @@ -61,6 +61,7 @@ import type { } from './types'; const IGNORE_RESPONSE = Symbol('IGNORE_RESPONSE'); +const DISABLE_HIGHLIGHTING = true; class WorkerPoolTerminatedError extends Error { constructor() { @@ -559,6 +560,7 @@ export class WorkerPoolManager { // attempt to highlight. This should be mostly never hit, but it's just an // extra level of safety if ( + DISABLE_HIGHLIGHTING || isFilePlainText(file) || (cachedResult != null && areFileRenderOptionsEqual( @@ -583,6 +585,7 @@ export class WorkerPoolManager { const cachedResult = this.getFileResultCache(file); const highlightKey = this.getFileHighlightKey(file); if ( + DISABLE_HIGHLIGHTING || highlightKey == null || isFilePlainText(file) || (cachedResult != null && @@ -628,6 +631,7 @@ export class WorkerPoolManager { // attempt to highlight. This should be mostly never hit, but it's just an // extra level of safety if ( + DISABLE_HIGHLIGHTING || isDiffPlainText(diff) || (cachedResult != null && areDiffRenderOptionsEqual( @@ -652,6 +656,7 @@ export class WorkerPoolManager { const cachedResult = this.getDiffResultCache(diff); const highlightKey = this.getDiffHighlightKey(diff); if ( + DISABLE_HIGHLIGHTING || highlightKey == null || isDiffPlainText(diff) || (cachedResult != null && diff --git a/packages/diffs/test/virtualizedFileDiffEstimatedHeights.test.ts b/packages/diffs/test/virtualizedFileDiffEstimatedHeights.test.ts index aef724fe2..f13c40a42 100644 --- a/packages/diffs/test/virtualizedFileDiffEstimatedHeights.test.ts +++ b/packages/diffs/test/virtualizedFileDiffEstimatedHeights.test.ts @@ -1,6 +1,9 @@ import { describe, expect, test } from 'bun:test'; -import { VirtualizedFileDiff } from '../src/components/VirtualizedFileDiff'; +import { + VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL, + VirtualizedFileDiff, +} from '../src/components/VirtualizedFileDiff'; import { DEFAULT_CODE_VIEW_FILE_METRICS } from '../src/constants'; import type { FileDiffMetadata, @@ -10,10 +13,6 @@ import type { import { iterateOverDiff } from '../src/utils/iterateOverDiff'; import { parseDiffFromFile } from '../src/utils/parseDiffFromFile'; -// Mirrors LAYOUT_CHECKPOINT_INTERVAL in src/components/VirtualizedFileDiff.ts: -// the source emits one layout checkpoint per this many diff rows. -const LAYOUT_CHECKPOINT_INTERVAL = 5_000; - const metrics: VirtualFileMetrics = { ...DEFAULT_CODE_VIEW_FILE_METRICS, hunkLineCount: 2, @@ -435,7 +434,9 @@ describe('VirtualizedFileDiff estimated height cache', () => { }); expect(inspect(instance).cache.totalLines).toBe(lineCount); expect(inspect(instance).cache.checkpoints.length).toBe( - Math.floor((lineCount - 1) / LAYOUT_CHECKPOINT_INTERVAL) + 1 + Math.floor( + (lineCount - 1) / VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL + ) + 1 ); }); });