@pierre/diffs 1.1.0-beta.16 → 1.1.0-beta.17
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.
- package/dist/components/AdvancedVirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/AdvancedVirtualizedFileDiff.js +2 -7
- package/dist/components/AdvancedVirtualizedFileDiff.js.map +1 -1
- package/dist/components/File.d.ts +14 -2
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +89 -23
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +15 -3
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +101 -23
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/VirtualizedFile.js +4 -2
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +4 -2
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.js +2 -1
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/constants.d.ts +3 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +8 -1
- package/dist/constants.js.map +1 -1
- package/dist/highlighter/shared_highlighter.js +12 -4
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +5 -4
- package/dist/managers/MouseEventManager.d.ts +20 -5
- package/dist/managers/MouseEventManager.d.ts.map +1 -1
- package/dist/managers/MouseEventManager.js +91 -25
- package/dist/managers/MouseEventManager.js.map +1 -1
- package/dist/react/File.d.ts +2 -0
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +3 -1
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +2 -0
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +3 -1
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +2 -0
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +3 -1
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +2 -0
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +3 -1
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/constants.d.ts +2 -2
- package/dist/react/constants.d.ts.map +1 -1
- package/dist/react/constants.js +2 -2
- package/dist/react/constants.js.map +1 -1
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +2 -2
- package/dist/react/types.d.ts +10 -0
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.d.ts +4 -0
- package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +17 -7
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.d.ts +4 -0
- package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
- package/dist/react/utils/renderFileChildren.js +13 -7
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +3 -2
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.js +1 -1
- package/dist/sprite.d.ts +2 -2
- package/dist/sprite.d.ts.map +1 -1
- package/dist/sprite.js +3 -0
- package/dist/sprite.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/style.js +1 -1
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/createFileHeaderElement.js +5 -2
- package/dist/utils/createFileHeaderElement.js.map +1 -1
- package/dist/utils/createGutterUtilityContentNode.d.ts +5 -0
- package/dist/utils/createGutterUtilityContentNode.d.ts.map +1 -0
- package/dist/utils/createGutterUtilityContentNode.js +15 -0
- package/dist/utils/createGutterUtilityContentNode.js.map +1 -0
- package/dist/utils/createGutterUtilityElement.d.ts +7 -0
- package/dist/utils/createGutterUtilityElement.d.ts.map +1 -0
- package/dist/utils/createGutterUtilityElement.js +20 -0
- package/dist/utils/createGutterUtilityElement.js.map +1 -0
- package/dist/utils/hast_utils.d.ts +1 -1
- package/dist/utils/hast_utils.d.ts.map +1 -1
- package/dist/utils/hast_utils.js.map +1 -1
- package/dist/worker/worker-portable.js +7 -0
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js.map +1 -1
- package/package.json +2 -1
- package/dist/themes/pierre-dark.js +0 -1328
- package/dist/themes/pierre-dark.js.map +0 -1
- package/dist/themes/pierre-light.js +0 -1328
- package/dist/themes/pierre-light.js.map +0 -1
- package/dist/utils/createHoverContentNode.d.ts +0 -5
- package/dist/utils/createHoverContentNode.d.ts.map +0 -1
- package/dist/utils/createHoverContentNode.js +0 -15
- package/dist/utils/createHoverContentNode.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileDiff.js","names":["options: FileDiffOptions<LAnnotation>","workerManager?: WorkerPoolManager | undefined","targetUnifiedIndex: number | undefined","targetSplitIndex: number | undefined","error: unknown","codeElements: HTMLElement[]","preProperties: PrePropertiesConfig"],"sources":["../../src/components/FileDiff.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport {\n DEFAULT_THEMES,\n DIFFS_TAG_NAME,\n HEADER_METADATA_SLOT_ID,\n UNSAFE_CSS_ATTRIBUTE,\n} from '../constants';\nimport {\n type GetLineIndexUtility,\n LineSelectionManager,\n type LineSelectionOptions,\n pluckLineSelectionOptions,\n type SelectedLineRange,\n} from '../managers/LineSelectionManager';\nimport {\n type GetHoveredLineResult,\n MouseEventManager,\n type MouseEventManagerBaseOptions,\n pluckMouseEventOptions,\n} from '../managers/MouseEventManager';\nimport { ResizeManager } from '../managers/ResizeManager';\nimport { ScrollSyncManager } from '../managers/ScrollSyncManager';\nimport {\n DiffHunksRenderer,\n type HunksRenderResult,\n} from '../renderers/DiffHunksRenderer';\nimport { SVGSpriteSheet } from '../sprite';\nimport type {\n BaseDiffOptions,\n DiffLineAnnotation,\n ExpansionDirections,\n FileContents,\n FileDiffMetadata,\n HunkData,\n HunkSeparators,\n PrePropertiesConfig,\n RenderHeaderMetadataCallback,\n RenderRange,\n SelectionSide,\n ThemeTypes,\n} from '../types';\nimport { areDiffLineAnnotationsEqual } from '../utils/areDiffLineAnnotationsEqual';\nimport { areFilesEqual } from '../utils/areFilesEqual';\nimport { areHunkDataEqual } from '../utils/areHunkDataEqual';\nimport { arePrePropertiesEqual } from '../utils/arePrePropertiesEqual';\nimport { areRenderRangesEqual } from '../utils/areRenderRangesEqual';\nimport { createAnnotationWrapperNode } from '../utils/createAnnotationWrapperNode';\nimport { createHoverContentNode } from '../utils/createHoverContentNode';\nimport { createUnsafeCSSStyleNode } from '../utils/createUnsafeCSSStyleNode';\nimport { wrapUnsafeCSS } from '../utils/cssWrappers';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getOrCreateCodeNode } from '../utils/getOrCreateCodeNode';\nimport { parseDiffFromFile } from '../utils/parseDiffFromFile';\nimport { prerenderHTMLIfNecessary } from '../utils/prerenderHTMLIfNecessary';\nimport { setPreNodeProperties } from '../utils/setWrapperNodeProps';\nimport type { WorkerPoolManager } from '../worker';\nimport { DiffsContainerLoaded } from './web-components';\n\nexport interface FileDiffRenderProps<LAnnotation> {\n fileDiff?: FileDiffMetadata;\n oldFile?: FileContents;\n newFile?: FileContents;\n forceRender?: boolean;\n fileContainer?: HTMLElement;\n containerWrapper?: HTMLElement;\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[];\n renderRange?: RenderRange;\n}\n\nexport interface FileDiffHydrationProps<LAnnotation> extends Omit<\n FileDiffRenderProps<LAnnotation>,\n 'fileContainer'\n> {\n fileContainer: HTMLElement;\n prerenderedHTML?: string;\n}\n\nexport interface FileDiffOptions<LAnnotation>\n extends\n Omit<BaseDiffOptions, 'hunkSeparators'>,\n MouseEventManagerBaseOptions<'diff'>,\n LineSelectionOptions {\n hunkSeparators?:\n | Exclude<HunkSeparators, 'custom'> /**\n * @deprecated Custom hunk separator functions are deprecated and will be\n * removed in a future version.\n */\n | ((\n hunk: HunkData,\n instance: FileDiff<LAnnotation>\n ) => HTMLElement | DocumentFragment);\n disableFileHeader?: boolean;\n renderHeaderMetadata?: RenderHeaderMetadataCallback;\n /**\n * When true, errors during rendering are rethrown instead of being caught\n * and displayed in the DOM. Useful for testing or when you want to handle\n * errors yourself.\n */\n disableErrorHandling?: boolean;\n renderAnnotation?(\n annotation: DiffLineAnnotation<LAnnotation>\n ): HTMLElement | undefined;\n renderHoverUtility?(\n getHoveredRow: () => GetHoveredLineResult<'diff'> | undefined\n ): HTMLElement | null;\n}\n\ninterface AnnotationElementCache<LAnnotation> {\n element: HTMLElement;\n annotation: DiffLineAnnotation<LAnnotation>;\n}\n\ninterface CustomHunkElementCache {\n element: HTMLElement;\n hunkData: HunkData;\n}\n\ninterface ColumnElements {\n gutter: HTMLElement;\n content: HTMLElement;\n}\n\ninterface TrimColumnsToOverlapProps {\n columns:\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements;\n diffStyle: 'split' | 'unified';\n overlapEnd: number;\n overlapStart: number;\n previousStart: number;\n trimEnd: number;\n trimStart: number;\n}\n\ninterface ApplyPartialRenderProps {\n previousRenderRange: RenderRange | undefined;\n renderRange: RenderRange | undefined;\n}\n\nlet instanceId = -1;\n\nexport class FileDiff<LAnnotation = undefined> {\n // NOTE(amadeus): We sorta need this to ensure the web-component file is\n // properly loaded\n static LoadedCustomComponent: boolean = DiffsContainerLoaded;\n\n readonly __id: string = `file-diff:${++instanceId}`;\n\n protected fileContainer: HTMLElement | undefined;\n protected spriteSVG: SVGElement | undefined;\n protected pre: HTMLPreElement | undefined;\n protected codeUnified: HTMLElement | undefined;\n protected codeDeletions: HTMLElement | undefined;\n protected codeAdditions: HTMLElement | undefined;\n protected bufferBefore: HTMLElement | undefined;\n protected bufferAfter: HTMLElement | undefined;\n protected unsafeCSSStyle: HTMLStyleElement | undefined;\n protected hoverContent: HTMLElement | undefined;\n\n protected headerElement: HTMLElement | undefined;\n protected headerMetadata: HTMLElement | undefined;\n protected separatorCache: Map<string, CustomHunkElementCache> = new Map();\n protected errorWrapper: HTMLElement | undefined;\n protected placeHolder: HTMLElement | undefined;\n\n protected hunksRenderer: DiffHunksRenderer<LAnnotation>;\n protected resizeManager: ResizeManager;\n protected scrollSyncManager: ScrollSyncManager;\n protected mouseEventManager: MouseEventManager<'diff'>;\n protected lineSelectionManager: LineSelectionManager;\n\n protected annotationCache: Map<string, AnnotationElementCache<LAnnotation>> =\n new Map();\n protected lineAnnotations: DiffLineAnnotation<LAnnotation>[] = [];\n\n protected deletionFile: FileContents | undefined;\n protected additionFile: FileContents | undefined;\n protected fileDiff: FileDiffMetadata | undefined;\n protected renderRange: RenderRange | undefined;\n protected appliedPreAttributes: PrePropertiesConfig | undefined;\n protected lastRenderedHeaderHTML: string | undefined;\n protected lastRowCount: number | undefined;\n\n protected enabled = true;\n\n constructor(\n public options: FileDiffOptions<LAnnotation> = { theme: DEFAULT_THEMES },\n protected workerManager?: WorkerPoolManager | undefined,\n protected isContainerManaged = false\n ) {\n this.hunksRenderer = new DiffHunksRenderer(\n {\n ...options,\n hunkSeparators:\n typeof options.hunkSeparators === 'function'\n ? 'custom'\n : options.hunkSeparators,\n },\n this.handleHighlightRender,\n this.workerManager\n );\n this.resizeManager = new ResizeManager();\n this.scrollSyncManager = new ScrollSyncManager();\n this.mouseEventManager = new MouseEventManager(\n 'diff',\n pluckMouseEventOptions(\n options,\n typeof options.hunkSeparators === 'function' ||\n (options.hunkSeparators ?? 'line-info') === 'line-info' ||\n options.hunkSeparators === 'line-info-basic'\n ? this.handleExpandHunk\n : undefined\n )\n );\n this.lineSelectionManager = new LineSelectionManager(\n pluckLineSelectionOptions(options, this.getLineIndex)\n );\n this.workerManager?.subscribeToThemeChanges(this);\n this.enabled = true;\n }\n\n private handleHighlightRender = (): void => {\n this.rerender();\n };\n\n public getLineIndex: GetLineIndexUtility = (\n lineNumber: number,\n side: SelectionSide = 'additions'\n ) => {\n if (this.fileDiff == null) {\n return undefined;\n }\n const lastHunk = this.fileDiff.hunks.at(-1);\n let targetUnifiedIndex: number | undefined;\n let targetSplitIndex: number | undefined;\n hunkIterator: for (const hunk of this.fileDiff.hunks) {\n let currentLineNumber =\n side === 'deletions' ? hunk.deletionStart : hunk.additionStart;\n const hunkCount =\n side === 'deletions' ? hunk.deletionCount : hunk.additionCount;\n let splitIndex = hunk.splitLineStart;\n let unifiedIndex = hunk.unifiedLineStart;\n\n // If we've selected a line between or before a hunk,\n // we should grab its index here\n if (lineNumber < currentLineNumber) {\n const difference = currentLineNumber - lineNumber;\n targetUnifiedIndex = Math.max(unifiedIndex - difference, 0);\n targetSplitIndex = Math.max(splitIndex - difference, 0);\n break hunkIterator;\n }\n\n // For AI Review: should this be > or >= for the startLine + count\n // Basically if our line number is not within this range, lets continue\n // onwards\n if (lineNumber >= currentLineNumber + hunkCount) {\n if (hunk === lastHunk) {\n const difference = lineNumber - (currentLineNumber + hunkCount);\n targetUnifiedIndex =\n unifiedIndex + hunk.unifiedLineCount + difference;\n targetSplitIndex = splitIndex + hunk.splitLineCount + difference;\n break hunkIterator;\n }\n continue;\n }\n\n for (const content of hunk.hunkContent) {\n if (content.type === 'context') {\n if (lineNumber < currentLineNumber + content.lines) {\n const difference = lineNumber - currentLineNumber;\n targetSplitIndex = splitIndex + difference;\n targetUnifiedIndex = unifiedIndex + difference;\n break hunkIterator;\n } else {\n currentLineNumber += content.lines;\n splitIndex += content.lines;\n unifiedIndex += content.lines;\n }\n } else {\n const sideCount =\n side === 'deletions' ? content.deletions : content.additions;\n if (lineNumber < currentLineNumber + sideCount) {\n const indexDifference = lineNumber - currentLineNumber;\n targetUnifiedIndex =\n unifiedIndex +\n (side === 'additions' ? content.deletions : 0) +\n indexDifference;\n targetSplitIndex = splitIndex + indexDifference;\n\n break hunkIterator;\n } else {\n currentLineNumber += sideCount;\n splitIndex += Math.max(content.deletions, content.additions);\n unifiedIndex += content.deletions + content.additions;\n }\n }\n }\n\n break hunkIterator;\n }\n\n if (targetUnifiedIndex == null || targetSplitIndex == null) {\n return undefined;\n }\n return [targetUnifiedIndex, targetSplitIndex];\n };\n\n // FIXME(amadeus): This is a bit of a looming issue that I'll need to resolve:\n // * Do we publicly allow merging of options or do we have individualized setters?\n // * When setting new options, we need to figure out what settings require a\n // re-render and which can just be applied more elegantly\n // * There's also an issue of options that live here on the File class and\n // those that live on the Hunk class, and it's a bit of an issue with passing\n // settings down and mirroring them (not great...)\n public setOptions(options: FileDiffOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n this.options = options;\n this.hunksRenderer.setOptions({\n ...this.options,\n hunkSeparators:\n typeof options.hunkSeparators === 'function'\n ? 'custom'\n : options.hunkSeparators,\n });\n this.mouseEventManager.setOptions(\n pluckMouseEventOptions(\n options,\n typeof options.hunkSeparators === 'function' ||\n (options.hunkSeparators ?? 'line-info') === 'line-info' ||\n options.hunkSeparators === 'line-info-basic'\n ? this.handleExpandHunk\n : undefined\n )\n );\n this.lineSelectionManager.setOptions(\n pluckLineSelectionOptions(options, this.getLineIndex)\n );\n }\n\n private mergeOptions(options: Partial<FileDiffOptions<LAnnotation>>): void {\n this.options = { ...this.options, ...options };\n }\n\n public setThemeType(themeType: ThemeTypes): void {\n if ((this.options.themeType ?? 'system') === themeType) {\n return;\n }\n this.mergeOptions({ themeType });\n this.hunksRenderer.setThemeType(themeType);\n\n if (this.headerElement != null) {\n if (themeType === 'system') {\n delete this.headerElement.dataset.themeType;\n } else {\n this.headerElement.dataset.themeType = themeType;\n }\n }\n\n // Update pre element theme mode\n if (this.pre != null) {\n switch (themeType) {\n case 'system':\n delete this.pre.dataset.themeType;\n break;\n case 'light':\n case 'dark':\n this.pre.dataset.themeType = themeType;\n break;\n }\n }\n }\n\n public getHoveredLine = (): GetHoveredLineResult<'diff'> | undefined => {\n return this.mouseEventManager.getHoveredLine();\n };\n\n public setLineAnnotations(\n lineAnnotations: DiffLineAnnotation<LAnnotation>[]\n ): void {\n this.lineAnnotations = lineAnnotations;\n }\n\n private canPartiallyRender(\n forceRender: boolean,\n annotationsChanged: boolean,\n didContentChange: boolean\n ): boolean {\n if (\n forceRender ||\n annotationsChanged ||\n didContentChange ||\n typeof this.options.hunkSeparators === 'function'\n ) {\n return false;\n }\n return true;\n }\n\n public setSelectedLines(range: SelectedLineRange | null): void {\n this.lineSelectionManager.setSelection(range);\n }\n\n public cleanUp(recycle: boolean = false): void {\n this.resizeManager.cleanUp();\n this.mouseEventManager.cleanUp();\n this.scrollSyncManager.cleanUp();\n this.lineSelectionManager.cleanUp();\n this.workerManager?.unsubscribeToThemeChanges(this);\n this.renderRange = undefined;\n\n // Clean up the elements\n if (!this.isContainerManaged) {\n this.fileContainer?.parentNode?.removeChild(this.fileContainer);\n }\n if (this.fileContainer?.shadowRoot != null) {\n // Manually help garbage collection\n this.fileContainer.shadowRoot.innerHTML = '';\n }\n this.fileContainer = undefined;\n // Manually help garbage collection\n if (this.pre != null) {\n this.pre.innerHTML = '';\n this.pre = undefined;\n }\n this.codeUnified = undefined;\n this.codeDeletions = undefined;\n this.codeAdditions = undefined;\n this.bufferBefore = undefined;\n this.bufferAfter = undefined;\n this.appliedPreAttributes = undefined;\n this.headerElement = undefined;\n this.lastRenderedHeaderHTML = undefined;\n this.errorWrapper = undefined;\n this.spriteSVG = undefined;\n this.lastRowCount = undefined;\n\n if (recycle) {\n this.hunksRenderer.recycle();\n } else {\n this.hunksRenderer.cleanUp();\n this.workerManager = undefined;\n // Clean up the data\n this.fileDiff = undefined;\n this.deletionFile = undefined;\n this.additionFile = undefined;\n }\n\n this.enabled = false;\n }\n\n public virtualizedSetup(): void {\n this.enabled = true;\n this.workerManager?.subscribeToThemeChanges(this);\n }\n\n public hydrate(props: FileDiffHydrationProps<LAnnotation>): void {\n const { overflow = 'scroll', diffStyle = 'split' } = this.options;\n const { fileContainer, prerenderedHTML } = props;\n prerenderHTMLIfNecessary(fileContainer, prerenderedHTML);\n for (const element of fileContainer.shadowRoot?.children ?? []) {\n if (element instanceof SVGElement) {\n this.spriteSVG = element;\n continue;\n }\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n if (element instanceof HTMLPreElement) {\n this.pre = element;\n for (const code of element.children) {\n if (\n !(code instanceof HTMLElement) ||\n code.tagName.toLowerCase() !== 'code'\n ) {\n continue;\n }\n if ('deletions' in code.dataset) {\n this.codeDeletions = code;\n }\n if ('additions' in code.dataset) {\n this.codeAdditions = code;\n }\n if ('unified' in code.dataset) {\n this.codeUnified = code;\n }\n }\n continue;\n }\n if ('diffsHeader' in element.dataset) {\n this.headerElement = element;\n continue;\n }\n if (\n element instanceof HTMLStyleElement &&\n element.hasAttribute(UNSAFE_CSS_ATTRIBUTE)\n ) {\n this.unsafeCSSStyle = element;\n continue;\n }\n }\n if (this.pre != null) {\n this.syncCodeNodesFromPre(this.pre);\n }\n // If we have no pre tag, then we should render\n if (this.pre == null) {\n this.render(props);\n }\n // Otherwise orchestrate our setup\n else {\n const { lineAnnotations, oldFile, newFile, fileDiff } = props;\n this.fileContainer = fileContainer;\n delete this.pre.dataset.dehydrated;\n\n this.lineAnnotations = lineAnnotations ?? this.lineAnnotations;\n this.additionFile = newFile;\n this.deletionFile = oldFile;\n this.fileDiff =\n fileDiff ??\n (oldFile != null && newFile != null\n ? parseDiffFromFile(oldFile, newFile)\n : undefined);\n\n this.hunksRenderer.hydrate(this.fileDiff);\n // FIXME(amadeus): not sure how to handle this yet...\n // this.renderSeparators();\n this.renderAnnotations();\n this.renderHoverUtility();\n this.injectUnsafeCSS();\n this.mouseEventManager.setup(this.pre);\n this.lineSelectionManager.setup(this.pre);\n this.resizeManager.setup(this.pre, overflow === 'wrap');\n if (overflow === 'scroll' && diffStyle === 'split') {\n this.scrollSyncManager.setup(\n this.pre,\n this.codeDeletions,\n this.codeAdditions\n );\n }\n }\n }\n\n public rerender(): void {\n if (\n !this.enabled ||\n (this.fileDiff == null &&\n this.additionFile == null &&\n this.deletionFile == null)\n ) {\n return;\n }\n this.render({\n oldFile: this.deletionFile,\n newFile: this.additionFile,\n fileDiff: this.fileDiff,\n forceRender: true,\n renderRange: this.renderRange,\n });\n }\n\n public handleExpandHunk = (\n hunkIndex: number,\n direction: ExpansionDirections\n ): void => {\n this.expandHunk(hunkIndex, direction);\n };\n\n public expandHunk(hunkIndex: number, direction: ExpansionDirections): void {\n this.hunksRenderer.expandHunk(hunkIndex, direction);\n this.rerender();\n }\n\n public render({\n oldFile,\n newFile,\n fileDiff,\n forceRender = false,\n lineAnnotations,\n fileContainer,\n containerWrapper,\n renderRange,\n }: FileDiffRenderProps<LAnnotation>): boolean {\n if (!this.enabled) {\n // NOTE(amadeus): May need to be a silent failure? Making it loud for now\n // to better understand it\n throw new Error(\n 'FileDiff.render: attempting to call render after cleaned up'\n );\n }\n const filesDidChange =\n oldFile != null &&\n newFile != null &&\n (!areFilesEqual(oldFile, this.deletionFile) ||\n !areFilesEqual(newFile, this.additionFile));\n let diffDidChange = fileDiff != null && fileDiff !== this.fileDiff;\n const annotationsChanged =\n lineAnnotations != null &&\n (lineAnnotations.length > 0 || this.lineAnnotations.length > 0)\n ? lineAnnotations !== this.lineAnnotations\n : false;\n\n if (\n areRenderRangesEqual(renderRange, this.renderRange) &&\n !forceRender &&\n !annotationsChanged &&\n // If using the fileDiff API, lets check to see if they are equal to\n // avoid doing work\n ((fileDiff != null && fileDiff === this.fileDiff) ||\n // If using the oldFile/newFile API then lets check to see if they are\n // equal\n (fileDiff == null && !filesDidChange))\n ) {\n return false;\n }\n\n const { renderRange: previousRenderRange } = this;\n this.renderRange = renderRange;\n this.deletionFile = oldFile;\n this.additionFile = newFile;\n\n if (fileDiff != null) {\n this.fileDiff = fileDiff;\n } else if (oldFile != null && newFile != null && filesDidChange) {\n diffDidChange = true;\n this.fileDiff = parseDiffFromFile(oldFile, newFile);\n }\n\n if (lineAnnotations != null) {\n this.setLineAnnotations(lineAnnotations);\n }\n if (this.fileDiff == null) {\n return false;\n }\n this.hunksRenderer.setOptions({\n ...this.options,\n hunkSeparators:\n typeof this.options.hunkSeparators === 'function'\n ? 'custom'\n : this.options.hunkSeparators,\n });\n\n this.hunksRenderer.setLineAnnotations(this.lineAnnotations);\n\n const {\n diffStyle = 'split',\n disableErrorHandling = false,\n disableFileHeader = false,\n overflow = 'scroll',\n } = this.options;\n\n if (disableFileHeader) {\n // Remove existing header from DOM\n if (this.headerElement != null) {\n this.headerElement.parentNode?.removeChild(this.headerElement);\n this.headerElement = undefined;\n this.lastRenderedHeaderHTML = undefined;\n }\n }\n fileContainer = this.getOrCreateFileContainer(\n fileContainer,\n containerWrapper\n );\n\n try {\n const pre = this.getOrCreatePreNode(fileContainer);\n\n // Attempt to partially render\n const didPartiallyRender =\n this.canPartiallyRender(\n forceRender,\n annotationsChanged,\n filesDidChange || diffDidChange\n ) && this.applyPartialRender({ previousRenderRange, renderRange });\n\n // If we were unable to partially render, perform a full render\n if (!didPartiallyRender) {\n const hunksResult = this.hunksRenderer.renderDiff(\n this.fileDiff,\n renderRange\n );\n if (hunksResult == null) {\n // FIXME(amadeus): I don't think we actually need this check, as\n // DiffHunksRenderer should probably take care of it for us?\n if (this.workerManager?.isInitialized() === false) {\n void this.workerManager.initialize().then(() => this.rerender());\n }\n return false;\n }\n\n if (hunksResult.headerElement != null) {\n this.applyHeaderToDOM(hunksResult.headerElement, fileContainer);\n }\n if (\n hunksResult.additionsContentAST != null ||\n hunksResult.deletionsContentAST != null ||\n hunksResult.unifiedContentAST != null\n ) {\n this.applyHunksToDOM(pre, hunksResult);\n } else if (this.pre != null) {\n this.pre.parentNode?.removeChild(this.pre);\n this.pre = undefined;\n }\n this.renderSeparators(hunksResult.hunkData);\n }\n\n this.applyBuffers(pre, renderRange);\n this.injectUnsafeCSS();\n this.renderAnnotations();\n this.renderHoverUtility();\n\n this.mouseEventManager.setup(pre);\n this.lineSelectionManager.setup(pre);\n this.resizeManager.setup(pre, overflow === 'wrap');\n if (overflow === 'scroll' && diffStyle === 'split') {\n this.scrollSyncManager.setup(\n pre,\n this.codeDeletions,\n this.codeAdditions\n );\n } else {\n this.scrollSyncManager.cleanUp();\n }\n } catch (error: unknown) {\n if (disableErrorHandling) {\n throw error;\n }\n console.error(error);\n if (error instanceof Error) {\n this.applyErrorToDOM(error, fileContainer);\n }\n }\n return true;\n }\n\n public renderPlaceholder(height: number): boolean {\n if (this.fileContainer == null) {\n return false;\n }\n this.cleanChildNodes();\n\n if (this.placeHolder == null) {\n const shadowRoot =\n this.fileContainer.shadowRoot ??\n this.fileContainer.attachShadow({ mode: 'open' });\n this.placeHolder = document.createElement('div');\n this.placeHolder.dataset.placeholder = '';\n shadowRoot.appendChild(this.placeHolder);\n }\n this.placeHolder.style.setProperty('height', `${height}px`);\n return true;\n }\n\n private cleanChildNodes() {\n this.resizeManager.cleanUp();\n this.scrollSyncManager.cleanUp();\n this.mouseEventManager.cleanUp();\n this.lineSelectionManager.cleanUp();\n\n this.bufferAfter?.remove();\n this.bufferBefore?.remove();\n this.codeAdditions?.remove();\n this.codeDeletions?.remove();\n this.codeUnified?.remove();\n this.errorWrapper?.remove();\n this.headerElement?.remove();\n this.hoverContent?.remove();\n this.pre?.remove();\n this.spriteSVG?.remove();\n this.unsafeCSSStyle?.remove();\n\n this.bufferAfter = undefined;\n this.bufferBefore = undefined;\n this.codeAdditions = undefined;\n this.codeDeletions = undefined;\n this.codeUnified = undefined;\n this.errorWrapper = undefined;\n this.headerElement = undefined;\n this.hoverContent = undefined;\n this.pre = undefined;\n this.spriteSVG = undefined;\n this.unsafeCSSStyle = undefined;\n\n this.lastRenderedHeaderHTML = undefined;\n this.lastRowCount = undefined;\n }\n\n private renderSeparators(hunkData: HunkData[]): void {\n const { hunkSeparators } = this.options;\n if (\n this.isContainerManaged ||\n this.fileContainer == null ||\n typeof hunkSeparators !== 'function'\n ) {\n for (const { element } of this.separatorCache.values()) {\n element.parentNode?.removeChild(element);\n }\n this.separatorCache.clear();\n return;\n }\n const staleSeparators = new Map(this.separatorCache);\n for (const hunk of hunkData) {\n const id = hunk.slotName;\n let cache = this.separatorCache.get(id);\n if (cache == null || !areHunkDataEqual(hunk, cache.hunkData)) {\n cache?.element.parentNode?.removeChild(cache.element);\n const element = document.createElement('div');\n element.style.display = 'contents';\n element.slot = hunk.slotName;\n element.appendChild(hunkSeparators(hunk, this));\n this.fileContainer.appendChild(element);\n cache = { element, hunkData: hunk };\n this.separatorCache.set(id, cache);\n }\n staleSeparators.delete(id);\n }\n for (const [id, { element }] of staleSeparators.entries()) {\n this.separatorCache.delete(id);\n element.parentNode?.removeChild(element);\n }\n }\n\n private renderAnnotations(): void {\n if (this.isContainerManaged || this.fileContainer == null) {\n for (const { element } of this.annotationCache.values()) {\n element.parentNode?.removeChild(element);\n }\n this.annotationCache.clear();\n return;\n }\n const staleAnnotations = new Map(this.annotationCache);\n const { renderAnnotation } = this.options;\n if (renderAnnotation != null && this.lineAnnotations.length > 0) {\n for (const [index, annotation] of this.lineAnnotations.entries()) {\n const id = `${index}-${getLineAnnotationName(annotation)}`;\n let cache = this.annotationCache.get(id);\n if (\n cache == null ||\n !areDiffLineAnnotationsEqual(annotation, cache.annotation)\n ) {\n cache?.element.parentElement?.removeChild(cache.element);\n const content = renderAnnotation(annotation);\n // If we can't render anything, then we should not render anything\n // and clear the annotation cache if necessary.\n if (content == null) {\n continue;\n }\n cache = {\n element: createAnnotationWrapperNode(\n getLineAnnotationName(annotation)\n ),\n annotation,\n };\n cache.element.appendChild(content);\n this.fileContainer.appendChild(cache.element);\n this.annotationCache.set(id, cache);\n }\n staleAnnotations.delete(id);\n }\n }\n for (const [id, { element }] of staleAnnotations.entries()) {\n this.annotationCache.delete(id);\n element.parentNode?.removeChild(element);\n }\n }\n\n private renderHoverUtility() {\n const { renderHoverUtility } = this.options;\n if (this.fileContainer == null || renderHoverUtility == null) {\n return;\n }\n const element = renderHoverUtility(this.mouseEventManager.getHoveredLine);\n if (element != null && this.hoverContent != null) {\n return;\n } else if (element == null) {\n this.hoverContent?.parentNode?.removeChild(this.hoverContent);\n this.hoverContent = undefined;\n return;\n }\n this.hoverContent = createHoverContentNode();\n this.hoverContent.appendChild(element);\n this.fileContainer.appendChild(this.hoverContent);\n }\n\n protected getOrCreateFileContainer(\n fileContainer?: HTMLElement,\n parentNode?: HTMLElement\n ): HTMLElement {\n const previousContainer = this.fileContainer;\n this.fileContainer =\n fileContainer ??\n this.fileContainer ??\n document.createElement(DIFFS_TAG_NAME);\n // NOTE(amadeus): If the container changes, we should reset the rendered\n // HTML\n if (previousContainer != null && previousContainer !== this.fileContainer) {\n this.lastRenderedHeaderHTML = undefined;\n this.headerElement = undefined;\n }\n if (parentNode != null && this.fileContainer.parentNode !== parentNode) {\n parentNode.appendChild(this.fileContainer);\n }\n if (this.spriteSVG == null) {\n const fragment = document.createElement('div');\n fragment.innerHTML = SVGSpriteSheet;\n const firstChild = fragment.firstChild;\n if (firstChild instanceof SVGElement) {\n this.spriteSVG = firstChild;\n this.fileContainer.shadowRoot?.appendChild(this.spriteSVG);\n }\n }\n return this.fileContainer;\n }\n\n protected getFileContainer(): HTMLElement | undefined {\n return this.fileContainer;\n }\n\n private getOrCreatePreNode(container: HTMLElement): HTMLPreElement {\n const shadowRoot =\n container.shadowRoot ?? container.attachShadow({ mode: 'open' });\n // If we haven't created a pre element yet, lets go ahead and do that\n if (this.pre == null) {\n this.pre = document.createElement('pre');\n this.appliedPreAttributes = undefined;\n this.codeUnified = undefined;\n this.codeDeletions = undefined;\n this.codeAdditions = undefined;\n shadowRoot.appendChild(this.pre);\n }\n // If we have a new parent container for the pre element, lets go ahead and\n // move it into the new container\n else if (this.pre.parentNode !== shadowRoot) {\n shadowRoot.appendChild(this.pre);\n this.appliedPreAttributes = undefined;\n }\n\n this.placeHolder?.remove();\n this.placeHolder = undefined;\n\n return this.pre;\n }\n\n private syncCodeNodesFromPre(pre: HTMLPreElement): void {\n this.codeUnified = undefined;\n this.codeDeletions = undefined;\n this.codeAdditions = undefined;\n for (const child of Array.from(pre.children)) {\n if (!(child instanceof HTMLElement)) {\n continue;\n }\n if ('unified' in child.dataset) {\n this.codeUnified = child;\n } else if ('deletions' in child.dataset) {\n this.codeDeletions = child;\n } else if ('additions' in child.dataset) {\n this.codeAdditions = child;\n }\n }\n }\n\n private applyHeaderToDOM(\n headerAST: HASTElement,\n container: HTMLElement\n ): void {\n this.cleanupErrorWrapper();\n this.placeHolder?.remove();\n this.placeHolder = undefined;\n const headerHTML = toHtml(headerAST);\n if (headerHTML !== this.lastRenderedHeaderHTML) {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = headerHTML;\n const newHeader = tempDiv.firstElementChild;\n if (!(newHeader instanceof HTMLElement)) {\n return;\n }\n if (this.headerElement != null) {\n container.shadowRoot?.replaceChild(newHeader, this.headerElement);\n } else {\n container.shadowRoot?.prepend(newHeader);\n }\n this.headerElement = newHeader;\n this.lastRenderedHeaderHTML = headerHTML;\n }\n\n if (this.isContainerManaged) return;\n\n const { renderHeaderMetadata } = this.options;\n if (this.headerMetadata != null) {\n this.headerMetadata.parentNode?.removeChild(this.headerMetadata);\n }\n const content =\n renderHeaderMetadata?.({\n deletionFile: this.deletionFile,\n additionFile: this.additionFile,\n fileDiff: this.fileDiff,\n }) ?? undefined;\n if (content != null) {\n this.headerMetadata = document.createElement('div');\n this.headerMetadata.slot = HEADER_METADATA_SLOT_ID;\n if (content instanceof Element) {\n this.headerMetadata.appendChild(content);\n } else {\n this.headerMetadata.innerText = `${content}`;\n }\n container.appendChild(this.headerMetadata);\n }\n }\n\n private injectUnsafeCSS(): void {\n if (this.fileContainer?.shadowRoot == null) {\n return;\n }\n const { unsafeCSS } = this.options;\n\n if (unsafeCSS == null || unsafeCSS === '') {\n return;\n }\n\n // Create or update the style element\n if (this.unsafeCSSStyle == null) {\n this.unsafeCSSStyle = createUnsafeCSSStyleNode();\n this.fileContainer.shadowRoot.appendChild(this.unsafeCSSStyle);\n }\n // Wrap in @layer unsafe to match SSR behavior\n this.unsafeCSSStyle.innerText = wrapUnsafeCSS(unsafeCSS);\n }\n\n private applyHunksToDOM(\n pre: HTMLPreElement,\n result: HunksRenderResult\n ): void {\n const { overflow = 'scroll' } = this.options;\n const containerSize =\n (this.options.hunkSeparators ?? 'line-info') === 'line-info';\n const rowSpan = overflow === 'wrap' ? result.rowCount : undefined;\n this.cleanupErrorWrapper();\n this.applyPreNodeAttributes(pre, result);\n\n let shouldReplace = false;\n // Create code elements and insert HTML content\n const codeElements: HTMLElement[] = [];\n const unifiedAST = this.hunksRenderer.renderCodeAST('unified', result);\n const deletionsAST = this.hunksRenderer.renderCodeAST('deletions', result);\n const additionsAST = this.hunksRenderer.renderCodeAST('additions', result);\n if (unifiedAST != null) {\n shouldReplace =\n this.codeUnified == null ||\n this.codeAdditions != null ||\n this.codeDeletions != null;\n\n // Clean up addition/deletion elements if necessary\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n\n this.codeUnified = getOrCreateCodeNode({\n code: this.codeUnified,\n columnType: 'unified',\n rowSpan,\n containerSize,\n });\n this.codeUnified.innerHTML =\n this.hunksRenderer.renderPartialHTML(unifiedAST);\n codeElements.push(this.codeUnified);\n } else if (deletionsAST != null || additionsAST != null) {\n if (deletionsAST != null) {\n shouldReplace = this.codeDeletions == null || this.codeUnified != null;\n\n // Clean up unified column if necessary\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n\n this.codeDeletions = getOrCreateCodeNode({\n code: this.codeDeletions,\n columnType: 'deletions',\n rowSpan,\n containerSize,\n });\n this.codeDeletions.innerHTML =\n this.hunksRenderer.renderPartialHTML(deletionsAST);\n codeElements.push(this.codeDeletions);\n } else {\n // If we have no deletion column, lets clean it up if it exists\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n }\n\n if (additionsAST != null) {\n shouldReplace =\n shouldReplace ||\n this.codeAdditions == null ||\n this.codeUnified != null;\n\n // Clean up unified column if necessary\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n\n this.codeAdditions = getOrCreateCodeNode({\n code: this.codeAdditions,\n columnType: 'additions',\n rowSpan,\n containerSize,\n });\n this.codeAdditions.innerHTML =\n this.hunksRenderer.renderPartialHTML(additionsAST);\n codeElements.push(this.codeAdditions);\n } else {\n // If we have no addition column, lets clean it up if it exists\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n }\n } else {\n // if we get in here, there's no content to render, so lets just clean\n // everything up\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n }\n\n if (codeElements.length === 0) {\n pre.textContent = '';\n } else if (shouldReplace) {\n pre.replaceChildren(...codeElements);\n }\n\n this.lastRowCount = result.rowCount;\n }\n\n private applyPartialRender({\n previousRenderRange,\n renderRange,\n }: ApplyPartialRenderProps): boolean {\n const {\n pre,\n codeUnified,\n codeAdditions,\n codeDeletions,\n options: { diffStyle = 'split' },\n } = this;\n if (\n pre == null ||\n // We must have a current and previous render range to do a partial render\n previousRenderRange == null ||\n renderRange == null ||\n // Neither render range may be infinite\n !Number.isFinite(previousRenderRange.totalLines) ||\n !Number.isFinite(renderRange.totalLines) ||\n this.lastRowCount == null\n ) {\n return false;\n }\n const codeElements = this.getCodeColumns(\n diffStyle,\n codeUnified,\n codeDeletions,\n codeAdditions\n );\n if (codeElements == null) {\n return false;\n }\n\n const previousStart = previousRenderRange.startingLine;\n const nextStart = renderRange.startingLine;\n const previousEnd = previousStart + previousRenderRange.totalLines;\n const nextEnd = nextStart + renderRange.totalLines;\n\n const overlapStart = Math.max(previousStart, nextStart);\n const overlapEnd = Math.min(previousEnd, nextEnd);\n if (overlapEnd <= overlapStart) {\n return false;\n }\n\n const trimStart = Math.max(0, overlapStart - previousStart);\n const trimEnd = Math.max(0, previousEnd - overlapEnd);\n\n const trimResult = this.trimColumns({\n columns: codeElements,\n trimStart,\n trimEnd,\n previousStart,\n overlapStart,\n overlapEnd,\n diffStyle,\n });\n if (trimResult < 0) {\n throw new Error('applyPartialRender: failed to trim to overlap');\n }\n\n if (this.lastRowCount < trimResult) {\n throw new Error('applyPartialRender: trimmed beyond DOM row count');\n }\n\n let rowCount = this.lastRowCount - trimResult;\n const renderChunk = (\n startingLine: number,\n totalLines: number\n ): HunksRenderResult | undefined => {\n if (totalLines <= 0 || this.fileDiff == null) {\n return undefined;\n }\n return this.hunksRenderer.renderDiff(this.fileDiff, {\n startingLine,\n totalLines,\n bufferBefore: 0,\n bufferAfter: 0,\n });\n };\n\n const prependResult = renderChunk(\n nextStart,\n Math.max(overlapStart - nextStart, 0)\n );\n if (prependResult == null && nextStart < overlapStart) {\n return false;\n }\n\n const appendResult = renderChunk(\n overlapEnd,\n Math.max(nextEnd - overlapEnd, 0)\n );\n if (appendResult == null && nextEnd > overlapEnd) {\n return false;\n }\n\n const applyChunk = (\n result: HunksRenderResult | undefined,\n insertPosition: 'afterbegin' | 'beforeend'\n ) => {\n if (result == null) {\n return;\n }\n if (diffStyle === 'unified' && !Array.isArray(codeElements)) {\n this.insertPartialHTML(diffStyle, codeElements, result, insertPosition);\n } else if (diffStyle === 'split' && Array.isArray(codeElements)) {\n this.insertPartialHTML(diffStyle, codeElements, result, insertPosition);\n } else {\n throw new Error(\n 'FileDiff.applyPartialRender.applyChunk: invalid chunk application'\n );\n }\n rowCount += result.rowCount;\n };\n\n this.cleanupErrorWrapper();\n applyChunk(prependResult, 'afterbegin');\n applyChunk(appendResult, 'beforeend');\n\n if (this.lastRowCount !== rowCount) {\n this.applyRowSpan(diffStyle, codeElements, rowCount);\n this.lastRowCount = rowCount;\n }\n\n return true;\n }\n\n private insertPartialHTML(\n diffStyle: 'unified',\n columns: ColumnElements,\n result: HunksRenderResult,\n insertPosition: 'afterbegin' | 'beforeend'\n ): void;\n private insertPartialHTML(\n diffStyle: 'split',\n columns: [ColumnElements | undefined, ColumnElements | undefined],\n result: HunksRenderResult,\n insertPosition: 'afterbegin' | 'beforeend'\n ): void;\n private insertPartialHTML(\n diffStyle: 'split' | 'unified',\n columns:\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements,\n result: HunksRenderResult,\n insertPosition: 'afterbegin' | 'beforeend'\n ): void {\n if (diffStyle === 'unified' && !Array.isArray(columns)) {\n const unifiedAST = this.hunksRenderer.renderCodeAST('unified', result);\n this.renderPartialColumn(columns, unifiedAST, insertPosition);\n } else if (diffStyle === 'split' && Array.isArray(columns)) {\n const deletionsAST = this.hunksRenderer.renderCodeAST(\n 'deletions',\n result\n );\n const additionsAST = this.hunksRenderer.renderCodeAST(\n 'additions',\n result\n );\n this.renderPartialColumn(columns[0], deletionsAST, insertPosition);\n this.renderPartialColumn(columns[1], additionsAST, insertPosition);\n } else {\n throw new Error(\n 'FileDiff.insertPartialHTML: Invalid argument composition'\n );\n }\n }\n\n private renderPartialColumn(\n column: ColumnElements | undefined,\n ast: ElementContent[] | undefined,\n insertPosition: 'afterbegin' | 'beforeend'\n ) {\n if (column == null || ast == null) {\n return;\n }\n const gutterChildren = getElementChildren(ast[0]);\n const contentChildren = getElementChildren(ast[1]);\n if (gutterChildren == null || contentChildren == null) {\n throw new Error('FileDiff.insertPartialHTML: Unexpected AST structure');\n }\n const firstHASTElement = contentChildren.at(0);\n if (\n insertPosition === 'beforeend' &&\n firstHASTElement?.type === 'element' &&\n typeof firstHASTElement.properties['data-buffer-size'] === 'number'\n ) {\n this.mergeBuffersIfNecessary(\n firstHASTElement.properties['data-buffer-size'],\n column.content.children[column.content.children.length - 1],\n column.gutter.children[column.gutter.children.length - 1],\n gutterChildren,\n contentChildren,\n true\n );\n }\n const lastHASTElement = contentChildren.at(-1);\n if (\n insertPosition === 'afterbegin' &&\n lastHASTElement?.type === 'element' &&\n typeof lastHASTElement.properties['data-buffer-size'] === 'number'\n ) {\n this.mergeBuffersIfNecessary(\n lastHASTElement.properties['data-buffer-size'],\n column.content.children[0],\n column.gutter.children[0],\n gutterChildren,\n contentChildren,\n false\n );\n }\n\n column.gutter.insertAdjacentHTML(\n insertPosition,\n this.hunksRenderer.renderPartialHTML(gutterChildren)\n );\n column.content.insertAdjacentHTML(\n insertPosition,\n this.hunksRenderer.renderPartialHTML(contentChildren)\n );\n }\n\n private mergeBuffersIfNecessary(\n adjustmentSize: number,\n contentElement: Element,\n gutterElement: Element,\n gutterChildren: ElementContent[],\n contentChildren: ElementContent[],\n fromStart: boolean\n ) {\n if (\n !(contentElement instanceof HTMLElement) ||\n !(gutterElement instanceof HTMLElement)\n ) {\n return;\n }\n const currentSize = this.getBufferSize(contentElement.dataset);\n if (currentSize == null) {\n return;\n }\n if (fromStart) {\n gutterChildren.shift();\n contentChildren.shift();\n } else {\n gutterChildren.pop();\n contentChildren.pop();\n }\n this.updateBufferSize(contentElement, currentSize + adjustmentSize);\n this.updateBufferSize(gutterElement, currentSize + adjustmentSize);\n }\n\n private applyRowSpan(\n diffStyle: 'split' | 'unified',\n columns:\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements,\n rowCount: number\n ): void {\n const applySpan = (column: ColumnElements | undefined) => {\n if (column == null) {\n return;\n }\n column.gutter.style.setProperty('grid-row', `span ${rowCount}`);\n column.content.style.setProperty('grid-row', `span ${rowCount}`);\n };\n if (diffStyle === 'unified' && !Array.isArray(columns)) {\n applySpan(columns);\n } else if (diffStyle === 'split' && Array.isArray(columns)) {\n applySpan(columns[0]);\n applySpan(columns[1]);\n } else {\n throw new Error('dun fuuuuked up');\n }\n }\n\n private trimColumnRows(\n columns: ColumnElements | undefined,\n preTrimCount: number,\n postTrimStart: number\n ): number {\n let visibleLineIndex = 0;\n let rowCount = 0;\n let rowIndex = 0;\n let pendingMetadataTrim = false;\n const hasPostTrim = postTrimStart >= 0;\n\n if (columns == null) {\n return 0;\n }\n const contentChildren = Array.from(columns.content.children);\n const gutterChildren = Array.from(columns.gutter.children);\n if (contentChildren.length !== gutterChildren.length) {\n throw new Error('FileDiff.trimColumnRows: columns do not match');\n }\n\n while (rowIndex < contentChildren.length) {\n if (preTrimCount <= 0 && !hasPostTrim && !pendingMetadataTrim) {\n break;\n }\n const gutterElement = gutterChildren[rowIndex];\n const contentElement = contentChildren[rowIndex];\n rowIndex++;\n\n if (\n !(gutterElement instanceof HTMLElement) ||\n !(contentElement instanceof HTMLElement)\n ) {\n console.error({ gutterElement, contentElement });\n throw new Error('FileDiff.trimColumnRows: invalid row elements');\n }\n\n if (pendingMetadataTrim) {\n pendingMetadataTrim = false;\n if (\n (gutterElement.dataset.gutterBuffer === 'annotation' &&\n 'lineAnnotation' in contentElement.dataset) ||\n (gutterElement.dataset.gutterBuffer === 'metadata' &&\n 'noNewline' in contentElement.dataset)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n continue;\n }\n }\n\n // If we found a line element, lets trim it if necessary\n if (\n 'lineIndex' in gutterElement.dataset &&\n 'lineIndex' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n if (preTrimCount > 0) {\n preTrimCount--;\n if (preTrimCount === 0) {\n pendingMetadataTrim = true;\n }\n }\n rowCount++;\n }\n visibleLineIndex++;\n continue;\n }\n\n // Separators should be removed, but don't count towards line indices\n if (\n 'separator' in gutterElement.dataset &&\n 'separator' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n }\n continue;\n }\n\n // Annotations should be removed, but don't count towards line indices\n if (\n gutterElement.dataset.gutterBuffer === 'annotation' &&\n 'lineAnnotation' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n }\n continue;\n }\n\n if (\n gutterElement.dataset.gutterBuffer === 'metadata' &&\n 'noNewline' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n }\n continue;\n }\n\n if (\n gutterElement.dataset.gutterBuffer === 'buffer' &&\n 'contentBuffer' in contentElement.dataset\n ) {\n const totalRows = this.getBufferSize(contentElement.dataset);\n if (totalRows == null) {\n throw new Error('FileDiff.trimColumnRows: invalid element');\n }\n if (preTrimCount > 0) {\n const rowsToRemove = Math.min(preTrimCount, totalRows);\n const newSize = totalRows - rowsToRemove;\n if (newSize > 0) {\n this.updateBufferSize(gutterElement, newSize);\n this.updateBufferSize(contentElement, newSize);\n rowCount += rowsToRemove;\n } else {\n gutterElement.remove();\n contentElement.remove();\n rowCount += totalRows;\n }\n preTrimCount -= rowsToRemove;\n }\n // If we are in a post clip era...\n else if (hasPostTrim) {\n const bufferStart = visibleLineIndex;\n const bufferEnd = visibleLineIndex + totalRows - 1;\n if (postTrimStart <= bufferStart) {\n gutterElement.remove();\n contentElement.remove();\n rowCount += totalRows;\n } else if (postTrimStart <= bufferEnd) {\n const rowsToRemove = bufferEnd - postTrimStart + 1;\n const newSize = totalRows - rowsToRemove;\n this.updateBufferSize(gutterElement, newSize);\n this.updateBufferSize(contentElement, newSize);\n rowCount += rowsToRemove;\n }\n }\n visibleLineIndex += totalRows;\n continue;\n }\n\n console.error({ gutterElement, contentElement });\n throw new Error('FileDiff.trimColumnRows: unknown row elements');\n }\n\n return rowCount;\n }\n\n private trimColumns({\n columns,\n diffStyle,\n overlapEnd,\n overlapStart,\n previousStart,\n trimEnd,\n trimStart,\n // NOTE(amadeus): If we return -1 it means something went wrong\n // with the trim...\n // oxlint-disable-next-line no-redundant-type-constituents\n }: TrimColumnsToOverlapProps): number | -1 {\n const preTrimCount = Math.max(0, overlapStart - previousStart);\n const postTrimStart = overlapEnd - previousStart;\n if (postTrimStart < 0) {\n throw new Error('FileDiff.trimColumns: overlap ends before previous');\n }\n const shouldTrimStart = trimStart > 0;\n const shouldTrimEnd = trimEnd > 0;\n if (!shouldTrimStart && !shouldTrimEnd) {\n return 0;\n }\n const effectivePreTrimCount = shouldTrimStart ? preTrimCount : 0;\n const effectivePostTrimStart = shouldTrimEnd ? postTrimStart : -1;\n\n if (diffStyle === 'unified' && !Array.isArray(columns)) {\n const removedRows = this.trimColumnRows(\n columns,\n effectivePreTrimCount,\n effectivePostTrimStart\n );\n return removedRows;\n } else if (diffStyle === 'split' && Array.isArray(columns)) {\n const deletionsTrim = this.trimColumnRows(\n columns[0],\n effectivePreTrimCount,\n effectivePostTrimStart\n );\n const additionsTrim = this.trimColumnRows(\n columns[1],\n effectivePreTrimCount,\n effectivePostTrimStart\n );\n // We should avoid the trim validation if we are split but\n // there's only one side\n if (\n columns[0] != null &&\n columns[1] != null &&\n deletionsTrim !== additionsTrim\n ) {\n throw new Error('FileDiff.trimColumns: split columns out of sync');\n }\n return columns[0] != null ? deletionsTrim : additionsTrim;\n } else {\n console.error({ diffStyle, columns });\n throw new Error('FileDiff.trimColumns: Invalid columns for diffType');\n }\n }\n\n private getBufferSize(properties: DOMStringMap): number | undefined {\n const parsed = Number.parseInt(properties?.bufferSize ?? '', 10);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n\n private updateBufferSize(element: HTMLElement, size: number): void {\n element.dataset.bufferSize = `${size}`;\n element.style.setProperty('grid-row', `span ${size}`);\n element.style.setProperty('min-height', `calc(${size} * 1lh)`);\n }\n\n private getCodeColumns(\n diffStyle: 'split' | 'unified',\n codeUnified: HTMLElement | undefined,\n codeDeletions: HTMLElement | undefined,\n codeAdditions: HTMLElement | undefined\n ):\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements\n | undefined {\n function getColumns(\n code: HTMLElement | undefined\n ): ColumnElements | undefined {\n if (code == null) {\n return undefined;\n }\n const gutter = code.children[0];\n const content = code.children[1];\n if (\n !(gutter instanceof HTMLElement) ||\n !(content instanceof HTMLElement) ||\n gutter.dataset.gutter == null ||\n content.dataset.content == null\n ) {\n return undefined;\n }\n return { gutter, content };\n }\n\n if (diffStyle === 'unified') {\n return getColumns(codeUnified);\n } else {\n const deletions = getColumns(codeDeletions);\n const additions = getColumns(codeAdditions);\n return deletions != null || additions != null\n ? [deletions, additions]\n : undefined;\n }\n }\n\n private applyBuffers(\n pre: HTMLPreElement,\n renderRange: RenderRange | undefined\n ) {\n const { disableVirtualizationBuffers = false } = this.options;\n if (disableVirtualizationBuffers || renderRange == null) {\n if (this.bufferBefore != null) {\n this.bufferBefore.parentNode?.removeChild(this.bufferBefore);\n this.bufferBefore = undefined;\n }\n if (this.bufferAfter != null) {\n this.bufferAfter.parentNode?.removeChild(this.bufferAfter);\n this.bufferAfter = undefined;\n }\n return;\n }\n // NOTE(amadeus): A very hacky pass at buffers outside the pre elements...\n // i may need to improve this...\n if (renderRange.bufferBefore > 0) {\n if (this.bufferBefore == null) {\n this.bufferBefore = document.createElement('div');\n this.bufferBefore.dataset.virtualizerBuffer = 'before';\n pre.before(this.bufferBefore);\n }\n this.bufferBefore.style.setProperty(\n 'height',\n `${renderRange.bufferBefore}px`\n );\n this.bufferBefore.style.setProperty('contain', 'strict');\n } else if (this.bufferBefore != null) {\n this.bufferBefore.parentNode?.removeChild(this.bufferBefore);\n this.bufferBefore = undefined;\n }\n\n if (renderRange.bufferAfter > 0) {\n if (this.bufferAfter == null) {\n this.bufferAfter = document.createElement('div');\n this.bufferAfter.dataset.virtualizerBuffer = 'after';\n pre.after(this.bufferAfter);\n }\n this.bufferAfter.style.setProperty(\n 'height',\n `${renderRange.bufferAfter}px`\n );\n this.bufferAfter.style.setProperty('contain', 'strict');\n } else if (this.bufferAfter != null) {\n this.bufferAfter.parentNode?.removeChild(this.bufferAfter);\n this.bufferAfter = undefined;\n }\n }\n\n private applyPreNodeAttributes(\n pre: HTMLPreElement,\n {\n themeStyles,\n baseThemeType,\n additionsContentAST,\n deletionsContentAST,\n totalLines,\n }: HunksRenderResult\n ): void {\n const {\n diffIndicators = 'bars',\n disableBackground = false,\n disableLineNumbers = false,\n overflow = 'scroll',\n themeType = 'system',\n diffStyle = 'split',\n } = this.options;\n const preProperties: PrePropertiesConfig = {\n type: 'diff',\n diffIndicators,\n disableBackground,\n disableLineNumbers,\n overflow,\n split:\n diffStyle === 'unified'\n ? false\n : additionsContentAST != null && deletionsContentAST != null,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n totalLines,\n };\n if (arePrePropertiesEqual(preProperties, this.appliedPreAttributes)) {\n return;\n }\n setPreNodeProperties(pre, preProperties);\n this.appliedPreAttributes = preProperties;\n }\n\n private applyErrorToDOM(error: Error, container: HTMLElement) {\n this.cleanupErrorWrapper();\n const pre = this.getOrCreatePreNode(container);\n pre.innerHTML = '';\n pre.parentNode?.removeChild(pre);\n this.pre = undefined;\n this.appliedPreAttributes = undefined;\n const shadowRoot =\n container.shadowRoot ?? container.attachShadow({ mode: 'open' });\n this.errorWrapper ??= document.createElement('div');\n this.errorWrapper.dataset.errorWrapper = '';\n this.errorWrapper.innerHTML = '';\n shadowRoot.appendChild(this.errorWrapper);\n const errorMessage = document.createElement('div');\n errorMessage.dataset.errorMessage = '';\n errorMessage.innerText = error.message;\n this.errorWrapper.appendChild(errorMessage);\n const errorStack = document.createElement('pre');\n errorStack.dataset.errorStack = '';\n errorStack.innerText = error.stack ?? 'No Error Stack';\n this.errorWrapper.appendChild(errorStack);\n }\n\n private cleanupErrorWrapper() {\n this.errorWrapper?.parentNode?.removeChild(this.errorWrapper);\n this.errorWrapper = undefined;\n }\n}\n\nfunction getElementChildren(\n node: ElementContent | undefined\n): ElementContent[] | undefined {\n if (node == null || node.type !== 'element') {\n return undefined;\n }\n return node.children ?? [];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileDiff.js","names":["options: FileDiffOptions<LAnnotation>","workerManager?: WorkerPoolManager | undefined","targetUnifiedIndex: number | undefined","targetSplitIndex: number | undefined","error: unknown","codeElements: HTMLElement[]","preProperties: PrePropertiesConfig"],"sources":["../../src/components/FileDiff.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport {\n DEFAULT_THEMES,\n DIFFS_TAG_NAME,\n EMPTY_RENDER_RANGE,\n HEADER_METADATA_SLOT_ID,\n HEADER_PREFIX_SLOT_ID,\n UNSAFE_CSS_ATTRIBUTE,\n} from '../constants';\nimport {\n type GetLineIndexUtility,\n LineSelectionManager,\n type LineSelectionOptions,\n pluckLineSelectionOptions,\n type SelectedLineRange,\n} from '../managers/LineSelectionManager';\nimport {\n type GetHoveredLineResult,\n MouseEventManager,\n type MouseEventManagerBaseOptions,\n pluckMouseEventOptions,\n} from '../managers/MouseEventManager';\nimport { ResizeManager } from '../managers/ResizeManager';\nimport { ScrollSyncManager } from '../managers/ScrollSyncManager';\nimport {\n DiffHunksRenderer,\n type HunksRenderResult,\n} from '../renderers/DiffHunksRenderer';\nimport { SVGSpriteSheet } from '../sprite';\nimport type {\n BaseDiffOptions,\n DiffLineAnnotation,\n ExpansionDirections,\n FileContents,\n FileDiffMetadata,\n HunkData,\n HunkSeparators,\n PrePropertiesConfig,\n RenderHeaderMetadataCallback,\n RenderHeaderPrefixCallback,\n RenderRange,\n SelectionSide,\n ThemeTypes,\n} from '../types';\nimport { areDiffLineAnnotationsEqual } from '../utils/areDiffLineAnnotationsEqual';\nimport { areFilesEqual } from '../utils/areFilesEqual';\nimport { areHunkDataEqual } from '../utils/areHunkDataEqual';\nimport { arePrePropertiesEqual } from '../utils/arePrePropertiesEqual';\nimport { areRenderRangesEqual } from '../utils/areRenderRangesEqual';\nimport { createAnnotationWrapperNode } from '../utils/createAnnotationWrapperNode';\nimport { createGutterUtilityContentNode } from '../utils/createGutterUtilityContentNode';\nimport { createUnsafeCSSStyleNode } from '../utils/createUnsafeCSSStyleNode';\nimport { wrapUnsafeCSS } from '../utils/cssWrappers';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getOrCreateCodeNode } from '../utils/getOrCreateCodeNode';\nimport { parseDiffFromFile } from '../utils/parseDiffFromFile';\nimport { prerenderHTMLIfNecessary } from '../utils/prerenderHTMLIfNecessary';\nimport { setPreNodeProperties } from '../utils/setWrapperNodeProps';\nimport type { WorkerPoolManager } from '../worker';\nimport { DiffsContainerLoaded } from './web-components';\n\nexport interface FileDiffRenderProps<LAnnotation> {\n fileDiff?: FileDiffMetadata;\n oldFile?: FileContents;\n newFile?: FileContents;\n forceRender?: boolean;\n fileContainer?: HTMLElement;\n containerWrapper?: HTMLElement;\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[];\n renderRange?: RenderRange;\n}\n\nexport interface FileDiffHydrationProps<LAnnotation> extends Omit<\n FileDiffRenderProps<LAnnotation>,\n 'fileContainer'\n> {\n fileContainer: HTMLElement;\n prerenderedHTML?: string;\n}\n\nexport interface FileDiffOptions<LAnnotation>\n extends\n Omit<BaseDiffOptions, 'hunkSeparators'>,\n MouseEventManagerBaseOptions<'diff'>,\n LineSelectionOptions {\n hunkSeparators?:\n | Exclude<HunkSeparators, 'custom'> /**\n * @deprecated Custom hunk separator functions are deprecated and will be\n * removed in a future version.\n */\n | ((\n hunk: HunkData,\n instance: FileDiff<LAnnotation>\n ) => HTMLElement | DocumentFragment);\n disableFileHeader?: boolean;\n /**\n * @deprecated Use `enableGutterUtility` instead.\n */\n enableHoverUtility?: boolean;\n renderHeaderPrefix?: RenderHeaderPrefixCallback;\n renderHeaderMetadata?: RenderHeaderMetadataCallback;\n /**\n * When true, errors during rendering are rethrown instead of being caught\n * and displayed in the DOM. Useful for testing or when you want to handle\n * errors yourself.\n */\n disableErrorHandling?: boolean;\n renderAnnotation?(\n annotation: DiffLineAnnotation<LAnnotation>\n ): HTMLElement | undefined;\n renderGutterUtility?(\n getHoveredRow: () => GetHoveredLineResult<'diff'> | undefined\n ): HTMLElement | null;\n /**\n * @deprecated Use `renderGutterUtility` instead.\n */\n renderHoverUtility?(\n getHoveredRow: () => GetHoveredLineResult<'diff'> | undefined\n ): HTMLElement | null;\n}\n\ninterface AnnotationElementCache<LAnnotation> {\n element: HTMLElement;\n annotation: DiffLineAnnotation<LAnnotation>;\n}\n\ninterface CustomHunkElementCache {\n element: HTMLElement;\n hunkData: HunkData;\n}\n\ninterface ColumnElements {\n gutter: HTMLElement;\n content: HTMLElement;\n}\n\ninterface TrimColumnsToOverlapProps {\n columns:\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements;\n diffStyle: 'split' | 'unified';\n overlapEnd: number;\n overlapStart: number;\n previousStart: number;\n trimEnd: number;\n trimStart: number;\n}\n\ninterface ApplyPartialRenderProps {\n previousRenderRange: RenderRange | undefined;\n renderRange: RenderRange | undefined;\n}\n\nlet instanceId = -1;\n\nexport class FileDiff<LAnnotation = undefined> {\n // NOTE(amadeus): We sorta need this to ensure the web-component file is\n // properly loaded\n static LoadedCustomComponent: boolean = DiffsContainerLoaded;\n\n readonly __id: string = `file-diff:${++instanceId}`;\n\n protected fileContainer: HTMLElement | undefined;\n protected spriteSVG: SVGElement | undefined;\n protected pre: HTMLPreElement | undefined;\n protected codeUnified: HTMLElement | undefined;\n protected codeDeletions: HTMLElement | undefined;\n protected codeAdditions: HTMLElement | undefined;\n protected bufferBefore: HTMLElement | undefined;\n protected bufferAfter: HTMLElement | undefined;\n protected unsafeCSSStyle: HTMLStyleElement | undefined;\n protected gutterUtilityContent: HTMLElement | undefined;\n\n protected headerElement: HTMLElement | undefined;\n protected headerPrefix: HTMLElement | undefined;\n protected headerMetadata: HTMLElement | undefined;\n protected separatorCache: Map<string, CustomHunkElementCache> = new Map();\n protected errorWrapper: HTMLElement | undefined;\n protected placeHolder: HTMLElement | undefined;\n\n protected hunksRenderer: DiffHunksRenderer<LAnnotation>;\n protected resizeManager: ResizeManager;\n protected scrollSyncManager: ScrollSyncManager;\n protected mouseEventManager: MouseEventManager<'diff'>;\n protected lineSelectionManager: LineSelectionManager;\n\n protected annotationCache: Map<string, AnnotationElementCache<LAnnotation>> =\n new Map();\n protected lineAnnotations: DiffLineAnnotation<LAnnotation>[] = [];\n\n protected deletionFile: FileContents | undefined;\n protected additionFile: FileContents | undefined;\n protected fileDiff: FileDiffMetadata | undefined;\n protected renderRange: RenderRange | undefined;\n protected appliedPreAttributes: PrePropertiesConfig | undefined;\n protected lastRenderedHeaderHTML: string | undefined;\n protected lastRowCount: number | undefined;\n\n protected enabled = true;\n\n constructor(\n public options: FileDiffOptions<LAnnotation> = { theme: DEFAULT_THEMES },\n protected workerManager?: WorkerPoolManager | undefined,\n protected isContainerManaged = false\n ) {\n this.hunksRenderer = new DiffHunksRenderer(\n {\n ...options,\n hunkSeparators:\n typeof options.hunkSeparators === 'function'\n ? 'custom'\n : options.hunkSeparators,\n },\n this.handleHighlightRender,\n this.workerManager\n );\n this.resizeManager = new ResizeManager();\n this.scrollSyncManager = new ScrollSyncManager();\n this.mouseEventManager = new MouseEventManager(\n 'diff',\n pluckMouseEventOptions(\n options,\n typeof options.hunkSeparators === 'function' ||\n (options.hunkSeparators ?? 'line-info') === 'line-info' ||\n options.hunkSeparators === 'line-info-basic'\n ? this.handleExpandHunk\n : undefined\n )\n );\n this.lineSelectionManager = new LineSelectionManager(\n pluckLineSelectionOptions(options, this.getLineIndex)\n );\n this.workerManager?.subscribeToThemeChanges(this);\n this.enabled = true;\n }\n\n private handleHighlightRender = (): void => {\n this.rerender();\n };\n\n public getLineIndex: GetLineIndexUtility = (\n lineNumber: number,\n side: SelectionSide = 'additions'\n ) => {\n if (this.fileDiff == null) {\n return undefined;\n }\n const lastHunk = this.fileDiff.hunks.at(-1);\n let targetUnifiedIndex: number | undefined;\n let targetSplitIndex: number | undefined;\n hunkIterator: for (const hunk of this.fileDiff.hunks) {\n let currentLineNumber =\n side === 'deletions' ? hunk.deletionStart : hunk.additionStart;\n const hunkCount =\n side === 'deletions' ? hunk.deletionCount : hunk.additionCount;\n let splitIndex = hunk.splitLineStart;\n let unifiedIndex = hunk.unifiedLineStart;\n\n // If we've selected a line between or before a hunk,\n // we should grab its index here\n if (lineNumber < currentLineNumber) {\n const difference = currentLineNumber - lineNumber;\n targetUnifiedIndex = Math.max(unifiedIndex - difference, 0);\n targetSplitIndex = Math.max(splitIndex - difference, 0);\n break hunkIterator;\n }\n\n // For AI Review: should this be > or >= for the startLine + count\n // Basically if our line number is not within this range, lets continue\n // onwards\n if (lineNumber >= currentLineNumber + hunkCount) {\n if (hunk === lastHunk) {\n const difference = lineNumber - (currentLineNumber + hunkCount);\n targetUnifiedIndex =\n unifiedIndex + hunk.unifiedLineCount + difference;\n targetSplitIndex = splitIndex + hunk.splitLineCount + difference;\n break hunkIterator;\n }\n continue;\n }\n\n for (const content of hunk.hunkContent) {\n if (content.type === 'context') {\n if (lineNumber < currentLineNumber + content.lines) {\n const difference = lineNumber - currentLineNumber;\n targetSplitIndex = splitIndex + difference;\n targetUnifiedIndex = unifiedIndex + difference;\n break hunkIterator;\n } else {\n currentLineNumber += content.lines;\n splitIndex += content.lines;\n unifiedIndex += content.lines;\n }\n } else {\n const sideCount =\n side === 'deletions' ? content.deletions : content.additions;\n if (lineNumber < currentLineNumber + sideCount) {\n const indexDifference = lineNumber - currentLineNumber;\n targetUnifiedIndex =\n unifiedIndex +\n (side === 'additions' ? content.deletions : 0) +\n indexDifference;\n targetSplitIndex = splitIndex + indexDifference;\n\n break hunkIterator;\n } else {\n currentLineNumber += sideCount;\n splitIndex += Math.max(content.deletions, content.additions);\n unifiedIndex += content.deletions + content.additions;\n }\n }\n }\n\n break hunkIterator;\n }\n\n if (targetUnifiedIndex == null || targetSplitIndex == null) {\n return undefined;\n }\n return [targetUnifiedIndex, targetSplitIndex];\n };\n\n // FIXME(amadeus): This is a bit of a looming issue that I'll need to resolve:\n // * Do we publicly allow merging of options or do we have individualized setters?\n // * When setting new options, we need to figure out what settings require a\n // re-render and which can just be applied more elegantly\n // * There's also an issue of options that live here on the File class and\n // those that live on the Hunk class, and it's a bit of an issue with passing\n // settings down and mirroring them (not great...)\n public setOptions(options: FileDiffOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n this.options = options;\n this.hunksRenderer.setOptions({\n ...this.options,\n hunkSeparators:\n typeof options.hunkSeparators === 'function'\n ? 'custom'\n : options.hunkSeparators,\n });\n this.mouseEventManager.setOptions(\n pluckMouseEventOptions(\n options,\n typeof options.hunkSeparators === 'function' ||\n (options.hunkSeparators ?? 'line-info') === 'line-info' ||\n options.hunkSeparators === 'line-info-basic'\n ? this.handleExpandHunk\n : undefined\n )\n );\n this.lineSelectionManager.setOptions(\n pluckLineSelectionOptions(options, this.getLineIndex)\n );\n }\n\n private mergeOptions(options: Partial<FileDiffOptions<LAnnotation>>): void {\n this.options = { ...this.options, ...options };\n }\n\n public setThemeType(themeType: ThemeTypes): void {\n if ((this.options.themeType ?? 'system') === themeType) {\n return;\n }\n this.mergeOptions({ themeType });\n this.hunksRenderer.setThemeType(themeType);\n\n if (this.headerElement != null) {\n if (themeType === 'system') {\n delete this.headerElement.dataset.themeType;\n } else {\n this.headerElement.dataset.themeType = themeType;\n }\n }\n\n // Update pre element theme mode\n if (this.pre != null) {\n switch (themeType) {\n case 'system':\n delete this.pre.dataset.themeType;\n break;\n case 'light':\n case 'dark':\n this.pre.dataset.themeType = themeType;\n break;\n }\n }\n }\n\n public getHoveredLine = (): GetHoveredLineResult<'diff'> | undefined => {\n return this.mouseEventManager.getHoveredLine();\n };\n\n public setLineAnnotations(\n lineAnnotations: DiffLineAnnotation<LAnnotation>[]\n ): void {\n this.lineAnnotations = lineAnnotations;\n }\n\n private canPartiallyRender(\n forceRender: boolean,\n annotationsChanged: boolean,\n didContentChange: boolean\n ): boolean {\n if (\n forceRender ||\n annotationsChanged ||\n didContentChange ||\n typeof this.options.hunkSeparators === 'function'\n ) {\n return false;\n }\n return true;\n }\n\n public setSelectedLines(range: SelectedLineRange | null): void {\n this.lineSelectionManager.setSelection(range);\n }\n\n public cleanUp(recycle: boolean = false): void {\n this.resizeManager.cleanUp();\n this.mouseEventManager.cleanUp();\n this.scrollSyncManager.cleanUp();\n this.lineSelectionManager.cleanUp();\n this.workerManager?.unsubscribeToThemeChanges(this);\n this.renderRange = undefined;\n\n // Clean up the elements\n if (!this.isContainerManaged) {\n this.fileContainer?.parentNode?.removeChild(this.fileContainer);\n }\n if (this.fileContainer?.shadowRoot != null) {\n // Manually help garbage collection\n this.fileContainer.shadowRoot.innerHTML = '';\n }\n this.fileContainer = undefined;\n // Manually help garbage collection\n if (this.pre != null) {\n this.pre.innerHTML = '';\n this.pre = undefined;\n }\n this.codeUnified = undefined;\n this.codeDeletions = undefined;\n this.codeAdditions = undefined;\n this.bufferBefore = undefined;\n this.bufferAfter = undefined;\n this.appliedPreAttributes = undefined;\n this.headerElement = undefined;\n this.headerPrefix = undefined;\n this.headerMetadata = undefined;\n this.lastRenderedHeaderHTML = undefined;\n this.errorWrapper = undefined;\n this.spriteSVG = undefined;\n this.lastRowCount = undefined;\n\n if (recycle) {\n this.hunksRenderer.recycle();\n } else {\n this.hunksRenderer.cleanUp();\n this.workerManager = undefined;\n // Clean up the data\n this.fileDiff = undefined;\n this.deletionFile = undefined;\n this.additionFile = undefined;\n }\n\n this.enabled = false;\n }\n\n public virtualizedSetup(): void {\n this.enabled = true;\n this.workerManager?.subscribeToThemeChanges(this);\n }\n\n public hydrate(props: FileDiffHydrationProps<LAnnotation>): void {\n const { overflow = 'scroll', diffStyle = 'split' } = this.options;\n const { fileContainer, prerenderedHTML } = props;\n prerenderHTMLIfNecessary(fileContainer, prerenderedHTML);\n for (const element of fileContainer.shadowRoot?.children ?? []) {\n if (element instanceof SVGElement) {\n this.spriteSVG = element;\n continue;\n }\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n if (element instanceof HTMLPreElement) {\n this.pre = element;\n for (const code of element.children) {\n if (\n !(code instanceof HTMLElement) ||\n code.tagName.toLowerCase() !== 'code'\n ) {\n continue;\n }\n if ('deletions' in code.dataset) {\n this.codeDeletions = code;\n }\n if ('additions' in code.dataset) {\n this.codeAdditions = code;\n }\n if ('unified' in code.dataset) {\n this.codeUnified = code;\n }\n }\n continue;\n }\n if ('diffsHeader' in element.dataset) {\n this.headerElement = element;\n continue;\n }\n if (\n element instanceof HTMLStyleElement &&\n element.hasAttribute(UNSAFE_CSS_ATTRIBUTE)\n ) {\n this.unsafeCSSStyle = element;\n continue;\n }\n }\n if (this.pre != null) {\n this.syncCodeNodesFromPre(this.pre);\n }\n // If we have no pre tag, then we should render\n if (this.pre == null) {\n this.render(props);\n }\n // Otherwise orchestrate our setup\n else {\n const { lineAnnotations, oldFile, newFile, fileDiff } = props;\n this.fileContainer = fileContainer;\n delete this.pre.dataset.dehydrated;\n\n this.lineAnnotations = lineAnnotations ?? this.lineAnnotations;\n this.additionFile = newFile;\n this.deletionFile = oldFile;\n this.fileDiff =\n fileDiff ??\n (oldFile != null && newFile != null\n ? parseDiffFromFile(oldFile, newFile)\n : undefined);\n\n this.hunksRenderer.hydrate(this.fileDiff);\n // FIXME(amadeus): not sure how to handle this yet...\n // this.renderSeparators();\n this.renderAnnotations();\n this.renderGutterUtility();\n this.injectUnsafeCSS();\n this.mouseEventManager.setup(this.pre);\n this.lineSelectionManager.setup(this.pre);\n this.resizeManager.setup(this.pre, overflow === 'wrap');\n if (overflow === 'scroll' && diffStyle === 'split') {\n this.scrollSyncManager.setup(\n this.pre,\n this.codeDeletions,\n this.codeAdditions\n );\n }\n }\n }\n\n public rerender(): void {\n if (\n !this.enabled ||\n (this.fileDiff == null &&\n this.additionFile == null &&\n this.deletionFile == null)\n ) {\n return;\n }\n this.render({\n oldFile: this.deletionFile,\n newFile: this.additionFile,\n fileDiff: this.fileDiff,\n forceRender: true,\n renderRange: this.renderRange,\n });\n }\n\n public handleExpandHunk = (\n hunkIndex: number,\n direction: ExpansionDirections\n ): void => {\n this.expandHunk(hunkIndex, direction);\n };\n\n public expandHunk(hunkIndex: number, direction: ExpansionDirections): void {\n this.hunksRenderer.expandHunk(hunkIndex, direction);\n this.rerender();\n }\n\n public render({\n oldFile,\n newFile,\n fileDiff,\n forceRender = false,\n lineAnnotations,\n fileContainer,\n containerWrapper,\n renderRange,\n }: FileDiffRenderProps<LAnnotation>): boolean {\n if (!this.enabled) {\n // NOTE(amadeus): May need to be a silent failure? Making it loud for now\n // to better understand it\n throw new Error(\n 'FileDiff.render: attempting to call render after cleaned up'\n );\n }\n const { collapsed = false } = this.options;\n const nextRenderRange = collapsed ? undefined : renderRange;\n const filesDidChange =\n oldFile != null &&\n newFile != null &&\n (!areFilesEqual(oldFile, this.deletionFile) ||\n !areFilesEqual(newFile, this.additionFile));\n let diffDidChange = fileDiff != null && fileDiff !== this.fileDiff;\n const annotationsChanged =\n lineAnnotations != null &&\n (lineAnnotations.length > 0 || this.lineAnnotations.length > 0)\n ? lineAnnotations !== this.lineAnnotations\n : false;\n\n if (\n !collapsed &&\n areRenderRangesEqual(nextRenderRange, this.renderRange) &&\n !forceRender &&\n !annotationsChanged &&\n // If using the fileDiff API, lets check to see if they are equal to\n // avoid doing work\n ((fileDiff != null && fileDiff === this.fileDiff) ||\n // If using the oldFile/newFile API then lets check to see if they are\n // equal\n (fileDiff == null && !filesDidChange))\n ) {\n return false;\n }\n\n const { renderRange: previousRenderRange } = this;\n this.renderRange = nextRenderRange;\n this.deletionFile = oldFile;\n this.additionFile = newFile;\n\n if (fileDiff != null) {\n this.fileDiff = fileDiff;\n } else if (oldFile != null && newFile != null && filesDidChange) {\n diffDidChange = true;\n this.fileDiff = parseDiffFromFile(oldFile, newFile);\n }\n\n if (lineAnnotations != null) {\n this.setLineAnnotations(lineAnnotations);\n }\n if (this.fileDiff == null) {\n return false;\n }\n this.hunksRenderer.setOptions({\n ...this.options,\n hunkSeparators:\n typeof this.options.hunkSeparators === 'function'\n ? 'custom'\n : this.options.hunkSeparators,\n });\n\n this.hunksRenderer.setLineAnnotations(this.lineAnnotations);\n\n const {\n diffStyle = 'split',\n disableErrorHandling = false,\n disableFileHeader = false,\n overflow = 'scroll',\n } = this.options;\n\n if (disableFileHeader) {\n // Remove existing header from DOM\n if (this.headerElement != null) {\n this.headerElement.parentNode?.removeChild(this.headerElement);\n this.headerElement = undefined;\n this.lastRenderedHeaderHTML = undefined;\n }\n if (this.headerPrefix != null) {\n this.headerPrefix.parentNode?.removeChild(this.headerPrefix);\n this.headerPrefix = undefined;\n }\n if (this.headerMetadata != null) {\n this.headerMetadata.parentNode?.removeChild(this.headerMetadata);\n this.headerMetadata = undefined;\n }\n }\n fileContainer = this.getOrCreateFileContainer(\n fileContainer,\n containerWrapper\n );\n\n if (collapsed) {\n this.removeRenderedCode();\n this.clearAuxiliaryNodes();\n\n try {\n const hunksResult = this.hunksRenderer.renderDiff(\n this.fileDiff,\n EMPTY_RENDER_RANGE\n );\n if (hunksResult?.headerElement != null) {\n this.applyHeaderToDOM(hunksResult.headerElement, fileContainer);\n }\n this.renderSeparators([]);\n this.injectUnsafeCSS();\n } catch (error: unknown) {\n if (disableErrorHandling) {\n throw error;\n }\n console.error(error);\n if (error instanceof Error) {\n this.applyErrorToDOM(error, fileContainer);\n }\n }\n return true;\n }\n\n try {\n const pre = this.getOrCreatePreNode(fileContainer);\n\n // Attempt to partially render\n const didPartiallyRender =\n this.canPartiallyRender(\n forceRender,\n annotationsChanged,\n filesDidChange || diffDidChange\n ) &&\n this.applyPartialRender({\n previousRenderRange,\n renderRange: nextRenderRange,\n });\n\n // If we were unable to partially render, perform a full render\n if (!didPartiallyRender) {\n const hunksResult = this.hunksRenderer.renderDiff(\n this.fileDiff,\n nextRenderRange\n );\n if (hunksResult == null) {\n // FIXME(amadeus): I don't think we actually need this check, as\n // DiffHunksRenderer should probably take care of it for us?\n if (this.workerManager?.isInitialized() === false) {\n void this.workerManager.initialize().then(() => this.rerender());\n }\n return false;\n }\n\n if (hunksResult.headerElement != null) {\n this.applyHeaderToDOM(hunksResult.headerElement, fileContainer);\n }\n if (\n hunksResult.additionsContentAST != null ||\n hunksResult.deletionsContentAST != null ||\n hunksResult.unifiedContentAST != null\n ) {\n this.applyHunksToDOM(pre, hunksResult);\n } else if (this.pre != null) {\n this.pre.parentNode?.removeChild(this.pre);\n this.pre = undefined;\n }\n this.renderSeparators(hunksResult.hunkData);\n }\n\n this.applyBuffers(pre, nextRenderRange);\n this.injectUnsafeCSS();\n this.renderAnnotations();\n this.renderGutterUtility();\n\n this.mouseEventManager.setup(pre);\n this.lineSelectionManager.setup(pre);\n this.resizeManager.setup(pre, overflow === 'wrap');\n if (overflow === 'scroll' && diffStyle === 'split') {\n this.scrollSyncManager.setup(\n pre,\n this.codeDeletions,\n this.codeAdditions\n );\n } else {\n this.scrollSyncManager.cleanUp();\n }\n } catch (error: unknown) {\n if (disableErrorHandling) {\n throw error;\n }\n console.error(error);\n if (error instanceof Error) {\n this.applyErrorToDOM(error, fileContainer);\n }\n }\n return true;\n }\n\n private removeRenderedCode(): void {\n this.resizeManager.cleanUp();\n this.scrollSyncManager.cleanUp();\n this.mouseEventManager.cleanUp();\n this.lineSelectionManager.cleanUp();\n\n this.bufferBefore?.remove();\n this.bufferBefore = undefined;\n this.bufferAfter?.remove();\n this.bufferAfter = undefined;\n\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n\n this.pre?.remove();\n this.pre = undefined;\n\n this.appliedPreAttributes = undefined;\n this.lastRowCount = undefined;\n }\n\n private clearAuxiliaryNodes(): void {\n for (const { element } of this.separatorCache.values()) {\n element.parentNode?.removeChild(element);\n }\n this.separatorCache.clear();\n\n for (const { element } of this.annotationCache.values()) {\n element.parentNode?.removeChild(element);\n }\n this.annotationCache.clear();\n\n this.gutterUtilityContent?.remove();\n this.gutterUtilityContent = undefined;\n }\n\n public renderPlaceholder(height: number): boolean {\n if (this.fileContainer == null) {\n return false;\n }\n this.cleanChildNodes();\n\n if (this.placeHolder == null) {\n const shadowRoot =\n this.fileContainer.shadowRoot ??\n this.fileContainer.attachShadow({ mode: 'open' });\n this.placeHolder = document.createElement('div');\n this.placeHolder.dataset.placeholder = '';\n shadowRoot.appendChild(this.placeHolder);\n }\n this.placeHolder.style.setProperty('height', `${height}px`);\n return true;\n }\n\n private cleanChildNodes() {\n this.resizeManager.cleanUp();\n this.scrollSyncManager.cleanUp();\n this.mouseEventManager.cleanUp();\n this.lineSelectionManager.cleanUp();\n\n this.bufferAfter?.remove();\n this.bufferBefore?.remove();\n this.codeAdditions?.remove();\n this.codeDeletions?.remove();\n this.codeUnified?.remove();\n this.errorWrapper?.remove();\n this.headerElement?.remove();\n this.gutterUtilityContent?.remove();\n this.headerPrefix?.remove();\n this.headerMetadata?.remove();\n this.pre?.remove();\n this.spriteSVG?.remove();\n this.unsafeCSSStyle?.remove();\n\n this.bufferAfter = undefined;\n this.bufferBefore = undefined;\n this.codeAdditions = undefined;\n this.codeDeletions = undefined;\n this.codeUnified = undefined;\n this.errorWrapper = undefined;\n this.headerElement = undefined;\n this.gutterUtilityContent = undefined;\n this.headerPrefix = undefined;\n this.headerMetadata = undefined;\n this.pre = undefined;\n this.spriteSVG = undefined;\n this.unsafeCSSStyle = undefined;\n\n this.lastRenderedHeaderHTML = undefined;\n this.lastRowCount = undefined;\n }\n\n private renderSeparators(hunkData: HunkData[]): void {\n const { hunkSeparators } = this.options;\n if (\n this.isContainerManaged ||\n this.fileContainer == null ||\n typeof hunkSeparators !== 'function'\n ) {\n for (const { element } of this.separatorCache.values()) {\n element.parentNode?.removeChild(element);\n }\n this.separatorCache.clear();\n return;\n }\n const staleSeparators = new Map(this.separatorCache);\n for (const hunk of hunkData) {\n const id = hunk.slotName;\n let cache = this.separatorCache.get(id);\n if (cache == null || !areHunkDataEqual(hunk, cache.hunkData)) {\n cache?.element.parentNode?.removeChild(cache.element);\n const element = document.createElement('div');\n element.style.display = 'contents';\n element.slot = hunk.slotName;\n element.appendChild(hunkSeparators(hunk, this));\n this.fileContainer.appendChild(element);\n cache = { element, hunkData: hunk };\n this.separatorCache.set(id, cache);\n }\n staleSeparators.delete(id);\n }\n for (const [id, { element }] of staleSeparators.entries()) {\n this.separatorCache.delete(id);\n element.parentNode?.removeChild(element);\n }\n }\n\n private renderAnnotations(): void {\n if (this.isContainerManaged || this.fileContainer == null) {\n for (const { element } of this.annotationCache.values()) {\n element.parentNode?.removeChild(element);\n }\n this.annotationCache.clear();\n return;\n }\n const staleAnnotations = new Map(this.annotationCache);\n const { renderAnnotation } = this.options;\n if (renderAnnotation != null && this.lineAnnotations.length > 0) {\n for (const [index, annotation] of this.lineAnnotations.entries()) {\n const id = `${index}-${getLineAnnotationName(annotation)}`;\n let cache = this.annotationCache.get(id);\n if (\n cache == null ||\n !areDiffLineAnnotationsEqual(annotation, cache.annotation)\n ) {\n cache?.element.parentElement?.removeChild(cache.element);\n const content = renderAnnotation(annotation);\n // If we can't render anything, then we should not render anything\n // and clear the annotation cache if necessary.\n if (content == null) {\n continue;\n }\n cache = {\n element: createAnnotationWrapperNode(\n getLineAnnotationName(annotation)\n ),\n annotation,\n };\n cache.element.appendChild(content);\n this.fileContainer.appendChild(cache.element);\n this.annotationCache.set(id, cache);\n }\n staleAnnotations.delete(id);\n }\n }\n for (const [id, { element }] of staleAnnotations.entries()) {\n this.annotationCache.delete(id);\n element.parentNode?.removeChild(element);\n }\n }\n\n private renderGutterUtility() {\n const renderGutterUtility =\n this.options.renderGutterUtility ?? this.options.renderHoverUtility;\n if (this.fileContainer == null || renderGutterUtility == null) {\n this.gutterUtilityContent?.remove();\n this.gutterUtilityContent = undefined;\n return;\n }\n const element = renderGutterUtility(this.mouseEventManager.getHoveredLine);\n if (element != null && this.gutterUtilityContent != null) {\n return;\n } else if (element == null) {\n this.gutterUtilityContent?.parentNode?.removeChild(\n this.gutterUtilityContent\n );\n this.gutterUtilityContent = undefined;\n return;\n }\n const gutterUtilityContent = createGutterUtilityContentNode();\n gutterUtilityContent.appendChild(element);\n this.fileContainer.appendChild(gutterUtilityContent);\n this.gutterUtilityContent = gutterUtilityContent;\n }\n\n protected getOrCreateFileContainer(\n fileContainer?: HTMLElement,\n parentNode?: HTMLElement\n ): HTMLElement {\n const previousContainer = this.fileContainer;\n this.fileContainer =\n fileContainer ??\n this.fileContainer ??\n document.createElement(DIFFS_TAG_NAME);\n // NOTE(amadeus): If the container changes, we should reset the rendered\n // HTML\n if (previousContainer != null && previousContainer !== this.fileContainer) {\n this.lastRenderedHeaderHTML = undefined;\n this.headerElement = undefined;\n }\n if (parentNode != null && this.fileContainer.parentNode !== parentNode) {\n parentNode.appendChild(this.fileContainer);\n }\n if (this.spriteSVG == null) {\n const fragment = document.createElement('div');\n fragment.innerHTML = SVGSpriteSheet;\n const firstChild = fragment.firstChild;\n if (firstChild instanceof SVGElement) {\n this.spriteSVG = firstChild;\n this.fileContainer.shadowRoot?.appendChild(this.spriteSVG);\n }\n }\n return this.fileContainer;\n }\n\n protected getFileContainer(): HTMLElement | undefined {\n return this.fileContainer;\n }\n\n private getOrCreatePreNode(container: HTMLElement): HTMLPreElement {\n const shadowRoot =\n container.shadowRoot ?? container.attachShadow({ mode: 'open' });\n // If we haven't created a pre element yet, lets go ahead and do that\n if (this.pre == null) {\n this.pre = document.createElement('pre');\n this.appliedPreAttributes = undefined;\n this.codeUnified = undefined;\n this.codeDeletions = undefined;\n this.codeAdditions = undefined;\n shadowRoot.appendChild(this.pre);\n }\n // If we have a new parent container for the pre element, lets go ahead and\n // move it into the new container\n else if (this.pre.parentNode !== shadowRoot) {\n shadowRoot.appendChild(this.pre);\n this.appliedPreAttributes = undefined;\n }\n\n this.placeHolder?.remove();\n this.placeHolder = undefined;\n\n return this.pre;\n }\n\n private syncCodeNodesFromPre(pre: HTMLPreElement): void {\n this.codeUnified = undefined;\n this.codeDeletions = undefined;\n this.codeAdditions = undefined;\n for (const child of Array.from(pre.children)) {\n if (!(child instanceof HTMLElement)) {\n continue;\n }\n if ('unified' in child.dataset) {\n this.codeUnified = child;\n } else if ('deletions' in child.dataset) {\n this.codeDeletions = child;\n } else if ('additions' in child.dataset) {\n this.codeAdditions = child;\n }\n }\n }\n\n private applyHeaderToDOM(\n headerAST: HASTElement,\n container: HTMLElement\n ): void {\n this.cleanupErrorWrapper();\n this.placeHolder?.remove();\n this.placeHolder = undefined;\n const headerHTML = toHtml(headerAST);\n if (headerHTML !== this.lastRenderedHeaderHTML) {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = headerHTML;\n const newHeader = tempDiv.firstElementChild;\n if (!(newHeader instanceof HTMLElement)) {\n return;\n }\n if (this.headerElement != null) {\n container.shadowRoot?.replaceChild(newHeader, this.headerElement);\n } else {\n container.shadowRoot?.prepend(newHeader);\n }\n this.headerElement = newHeader;\n this.lastRenderedHeaderHTML = headerHTML;\n }\n\n if (this.isContainerManaged) return;\n\n const { renderHeaderPrefix, renderHeaderMetadata } = this.options;\n if (this.headerPrefix != null) {\n this.headerPrefix.parentNode?.removeChild(this.headerPrefix);\n }\n if (this.headerMetadata != null) {\n this.headerMetadata.parentNode?.removeChild(this.headerMetadata);\n }\n const prefix =\n renderHeaderPrefix?.({\n deletionFile: this.deletionFile,\n additionFile: this.additionFile,\n fileDiff: this.fileDiff,\n }) ?? undefined;\n const content =\n renderHeaderMetadata?.({\n deletionFile: this.deletionFile,\n additionFile: this.additionFile,\n fileDiff: this.fileDiff,\n }) ?? undefined;\n if (prefix != null) {\n this.headerPrefix = document.createElement('div');\n this.headerPrefix.slot = HEADER_PREFIX_SLOT_ID;\n if (prefix instanceof Element) {\n this.headerPrefix.appendChild(prefix);\n } else {\n this.headerPrefix.innerText = `${prefix}`;\n }\n container.appendChild(this.headerPrefix);\n }\n if (content != null) {\n this.headerMetadata = document.createElement('div');\n this.headerMetadata.slot = HEADER_METADATA_SLOT_ID;\n if (content instanceof Element) {\n this.headerMetadata.appendChild(content);\n } else {\n this.headerMetadata.innerText = `${content}`;\n }\n container.appendChild(this.headerMetadata);\n }\n }\n\n private injectUnsafeCSS(): void {\n if (this.fileContainer?.shadowRoot == null) {\n return;\n }\n const { unsafeCSS } = this.options;\n\n if (unsafeCSS == null || unsafeCSS === '') {\n return;\n }\n\n // Create or update the style element\n if (this.unsafeCSSStyle == null) {\n this.unsafeCSSStyle = createUnsafeCSSStyleNode();\n this.fileContainer.shadowRoot.appendChild(this.unsafeCSSStyle);\n }\n // Wrap in @layer unsafe to match SSR behavior\n this.unsafeCSSStyle.innerText = wrapUnsafeCSS(unsafeCSS);\n }\n\n private applyHunksToDOM(\n pre: HTMLPreElement,\n result: HunksRenderResult\n ): void {\n const { overflow = 'scroll' } = this.options;\n const containerSize =\n (this.options.hunkSeparators ?? 'line-info') === 'line-info';\n const rowSpan = overflow === 'wrap' ? result.rowCount : undefined;\n this.cleanupErrorWrapper();\n this.applyPreNodeAttributes(pre, result);\n\n let shouldReplace = false;\n // Create code elements and insert HTML content\n const codeElements: HTMLElement[] = [];\n const unifiedAST = this.hunksRenderer.renderCodeAST('unified', result);\n const deletionsAST = this.hunksRenderer.renderCodeAST('deletions', result);\n const additionsAST = this.hunksRenderer.renderCodeAST('additions', result);\n if (unifiedAST != null) {\n shouldReplace =\n this.codeUnified == null ||\n this.codeAdditions != null ||\n this.codeDeletions != null;\n\n // Clean up addition/deletion elements if necessary\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n\n this.codeUnified = getOrCreateCodeNode({\n code: this.codeUnified,\n columnType: 'unified',\n rowSpan,\n containerSize,\n });\n this.codeUnified.innerHTML =\n this.hunksRenderer.renderPartialHTML(unifiedAST);\n codeElements.push(this.codeUnified);\n } else if (deletionsAST != null || additionsAST != null) {\n if (deletionsAST != null) {\n shouldReplace = this.codeDeletions == null || this.codeUnified != null;\n\n // Clean up unified column if necessary\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n\n this.codeDeletions = getOrCreateCodeNode({\n code: this.codeDeletions,\n columnType: 'deletions',\n rowSpan,\n containerSize,\n });\n this.codeDeletions.innerHTML =\n this.hunksRenderer.renderPartialHTML(deletionsAST);\n codeElements.push(this.codeDeletions);\n } else {\n // If we have no deletion column, lets clean it up if it exists\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n }\n\n if (additionsAST != null) {\n shouldReplace =\n shouldReplace ||\n this.codeAdditions == null ||\n this.codeUnified != null;\n\n // Clean up unified column if necessary\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n\n this.codeAdditions = getOrCreateCodeNode({\n code: this.codeAdditions,\n columnType: 'additions',\n rowSpan,\n containerSize,\n });\n this.codeAdditions.innerHTML =\n this.hunksRenderer.renderPartialHTML(additionsAST);\n codeElements.push(this.codeAdditions);\n } else {\n // If we have no addition column, lets clean it up if it exists\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n }\n } else {\n // if we get in here, there's no content to render, so lets just clean\n // everything up\n this.codeUnified?.remove();\n this.codeUnified = undefined;\n this.codeDeletions?.remove();\n this.codeDeletions = undefined;\n this.codeAdditions?.remove();\n this.codeAdditions = undefined;\n }\n\n if (codeElements.length === 0) {\n pre.textContent = '';\n } else if (shouldReplace) {\n pre.replaceChildren(...codeElements);\n }\n\n this.lastRowCount = result.rowCount;\n }\n\n private applyPartialRender({\n previousRenderRange,\n renderRange,\n }: ApplyPartialRenderProps): boolean {\n const {\n pre,\n codeUnified,\n codeAdditions,\n codeDeletions,\n options: { diffStyle = 'split' },\n } = this;\n if (\n pre == null ||\n // We must have a current and previous render range to do a partial render\n previousRenderRange == null ||\n renderRange == null ||\n // Neither render range may be infinite\n !Number.isFinite(previousRenderRange.totalLines) ||\n !Number.isFinite(renderRange.totalLines) ||\n this.lastRowCount == null\n ) {\n return false;\n }\n const codeElements = this.getCodeColumns(\n diffStyle,\n codeUnified,\n codeDeletions,\n codeAdditions\n );\n if (codeElements == null) {\n return false;\n }\n\n const previousStart = previousRenderRange.startingLine;\n const nextStart = renderRange.startingLine;\n const previousEnd = previousStart + previousRenderRange.totalLines;\n const nextEnd = nextStart + renderRange.totalLines;\n\n const overlapStart = Math.max(previousStart, nextStart);\n const overlapEnd = Math.min(previousEnd, nextEnd);\n if (overlapEnd <= overlapStart) {\n return false;\n }\n\n const trimStart = Math.max(0, overlapStart - previousStart);\n const trimEnd = Math.max(0, previousEnd - overlapEnd);\n\n const trimResult = this.trimColumns({\n columns: codeElements,\n trimStart,\n trimEnd,\n previousStart,\n overlapStart,\n overlapEnd,\n diffStyle,\n });\n if (trimResult < 0) {\n throw new Error('applyPartialRender: failed to trim to overlap');\n }\n\n if (this.lastRowCount < trimResult) {\n throw new Error('applyPartialRender: trimmed beyond DOM row count');\n }\n\n let rowCount = this.lastRowCount - trimResult;\n const renderChunk = (\n startingLine: number,\n totalLines: number\n ): HunksRenderResult | undefined => {\n if (totalLines <= 0 || this.fileDiff == null) {\n return undefined;\n }\n return this.hunksRenderer.renderDiff(this.fileDiff, {\n startingLine,\n totalLines,\n bufferBefore: 0,\n bufferAfter: 0,\n });\n };\n\n const prependResult = renderChunk(\n nextStart,\n Math.max(overlapStart - nextStart, 0)\n );\n if (prependResult == null && nextStart < overlapStart) {\n return false;\n }\n\n const appendResult = renderChunk(\n overlapEnd,\n Math.max(nextEnd - overlapEnd, 0)\n );\n if (appendResult == null && nextEnd > overlapEnd) {\n return false;\n }\n\n const applyChunk = (\n result: HunksRenderResult | undefined,\n insertPosition: 'afterbegin' | 'beforeend'\n ) => {\n if (result == null) {\n return;\n }\n if (diffStyle === 'unified' && !Array.isArray(codeElements)) {\n this.insertPartialHTML(diffStyle, codeElements, result, insertPosition);\n } else if (diffStyle === 'split' && Array.isArray(codeElements)) {\n this.insertPartialHTML(diffStyle, codeElements, result, insertPosition);\n } else {\n throw new Error(\n 'FileDiff.applyPartialRender.applyChunk: invalid chunk application'\n );\n }\n rowCount += result.rowCount;\n };\n\n this.cleanupErrorWrapper();\n applyChunk(prependResult, 'afterbegin');\n applyChunk(appendResult, 'beforeend');\n\n if (this.lastRowCount !== rowCount) {\n this.applyRowSpan(diffStyle, codeElements, rowCount);\n this.lastRowCount = rowCount;\n }\n\n return true;\n }\n\n private insertPartialHTML(\n diffStyle: 'unified',\n columns: ColumnElements,\n result: HunksRenderResult,\n insertPosition: 'afterbegin' | 'beforeend'\n ): void;\n private insertPartialHTML(\n diffStyle: 'split',\n columns: [ColumnElements | undefined, ColumnElements | undefined],\n result: HunksRenderResult,\n insertPosition: 'afterbegin' | 'beforeend'\n ): void;\n private insertPartialHTML(\n diffStyle: 'split' | 'unified',\n columns:\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements,\n result: HunksRenderResult,\n insertPosition: 'afterbegin' | 'beforeend'\n ): void {\n if (diffStyle === 'unified' && !Array.isArray(columns)) {\n const unifiedAST = this.hunksRenderer.renderCodeAST('unified', result);\n this.renderPartialColumn(columns, unifiedAST, insertPosition);\n } else if (diffStyle === 'split' && Array.isArray(columns)) {\n const deletionsAST = this.hunksRenderer.renderCodeAST(\n 'deletions',\n result\n );\n const additionsAST = this.hunksRenderer.renderCodeAST(\n 'additions',\n result\n );\n this.renderPartialColumn(columns[0], deletionsAST, insertPosition);\n this.renderPartialColumn(columns[1], additionsAST, insertPosition);\n } else {\n throw new Error(\n 'FileDiff.insertPartialHTML: Invalid argument composition'\n );\n }\n }\n\n private renderPartialColumn(\n column: ColumnElements | undefined,\n ast: ElementContent[] | undefined,\n insertPosition: 'afterbegin' | 'beforeend'\n ) {\n if (column == null || ast == null) {\n return;\n }\n const gutterChildren = getElementChildren(ast[0]);\n const contentChildren = getElementChildren(ast[1]);\n if (gutterChildren == null || contentChildren == null) {\n throw new Error('FileDiff.insertPartialHTML: Unexpected AST structure');\n }\n const firstHASTElement = contentChildren.at(0);\n if (\n insertPosition === 'beforeend' &&\n firstHASTElement?.type === 'element' &&\n typeof firstHASTElement.properties['data-buffer-size'] === 'number'\n ) {\n this.mergeBuffersIfNecessary(\n firstHASTElement.properties['data-buffer-size'],\n column.content.children[column.content.children.length - 1],\n column.gutter.children[column.gutter.children.length - 1],\n gutterChildren,\n contentChildren,\n true\n );\n }\n const lastHASTElement = contentChildren.at(-1);\n if (\n insertPosition === 'afterbegin' &&\n lastHASTElement?.type === 'element' &&\n typeof lastHASTElement.properties['data-buffer-size'] === 'number'\n ) {\n this.mergeBuffersIfNecessary(\n lastHASTElement.properties['data-buffer-size'],\n column.content.children[0],\n column.gutter.children[0],\n gutterChildren,\n contentChildren,\n false\n );\n }\n\n column.gutter.insertAdjacentHTML(\n insertPosition,\n this.hunksRenderer.renderPartialHTML(gutterChildren)\n );\n column.content.insertAdjacentHTML(\n insertPosition,\n this.hunksRenderer.renderPartialHTML(contentChildren)\n );\n }\n\n private mergeBuffersIfNecessary(\n adjustmentSize: number,\n contentElement: Element,\n gutterElement: Element,\n gutterChildren: ElementContent[],\n contentChildren: ElementContent[],\n fromStart: boolean\n ) {\n if (\n !(contentElement instanceof HTMLElement) ||\n !(gutterElement instanceof HTMLElement)\n ) {\n return;\n }\n const currentSize = this.getBufferSize(contentElement.dataset);\n if (currentSize == null) {\n return;\n }\n if (fromStart) {\n gutterChildren.shift();\n contentChildren.shift();\n } else {\n gutterChildren.pop();\n contentChildren.pop();\n }\n this.updateBufferSize(contentElement, currentSize + adjustmentSize);\n this.updateBufferSize(gutterElement, currentSize + adjustmentSize);\n }\n\n private applyRowSpan(\n diffStyle: 'split' | 'unified',\n columns:\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements,\n rowCount: number\n ): void {\n const applySpan = (column: ColumnElements | undefined) => {\n if (column == null) {\n return;\n }\n column.gutter.style.setProperty('grid-row', `span ${rowCount}`);\n column.content.style.setProperty('grid-row', `span ${rowCount}`);\n };\n if (diffStyle === 'unified' && !Array.isArray(columns)) {\n applySpan(columns);\n } else if (diffStyle === 'split' && Array.isArray(columns)) {\n applySpan(columns[0]);\n applySpan(columns[1]);\n } else {\n throw new Error('dun fuuuuked up');\n }\n }\n\n private trimColumnRows(\n columns: ColumnElements | undefined,\n preTrimCount: number,\n postTrimStart: number\n ): number {\n let visibleLineIndex = 0;\n let rowCount = 0;\n let rowIndex = 0;\n let pendingMetadataTrim = false;\n const hasPostTrim = postTrimStart >= 0;\n\n if (columns == null) {\n return 0;\n }\n const contentChildren = Array.from(columns.content.children);\n const gutterChildren = Array.from(columns.gutter.children);\n if (contentChildren.length !== gutterChildren.length) {\n throw new Error('FileDiff.trimColumnRows: columns do not match');\n }\n\n while (rowIndex < contentChildren.length) {\n if (preTrimCount <= 0 && !hasPostTrim && !pendingMetadataTrim) {\n break;\n }\n const gutterElement = gutterChildren[rowIndex];\n const contentElement = contentChildren[rowIndex];\n rowIndex++;\n\n if (\n !(gutterElement instanceof HTMLElement) ||\n !(contentElement instanceof HTMLElement)\n ) {\n console.error({ gutterElement, contentElement });\n throw new Error('FileDiff.trimColumnRows: invalid row elements');\n }\n\n if (pendingMetadataTrim) {\n pendingMetadataTrim = false;\n if (\n (gutterElement.dataset.gutterBuffer === 'annotation' &&\n 'lineAnnotation' in contentElement.dataset) ||\n (gutterElement.dataset.gutterBuffer === 'metadata' &&\n 'noNewline' in contentElement.dataset)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n continue;\n }\n }\n\n // If we found a line element, lets trim it if necessary\n if (\n 'lineIndex' in gutterElement.dataset &&\n 'lineIndex' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n if (preTrimCount > 0) {\n preTrimCount--;\n if (preTrimCount === 0) {\n pendingMetadataTrim = true;\n }\n }\n rowCount++;\n }\n visibleLineIndex++;\n continue;\n }\n\n // Separators should be removed, but don't count towards line indices\n if (\n 'separator' in gutterElement.dataset &&\n 'separator' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n }\n continue;\n }\n\n // Annotations should be removed, but don't count towards line indices\n if (\n gutterElement.dataset.gutterBuffer === 'annotation' &&\n 'lineAnnotation' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n }\n continue;\n }\n\n if (\n gutterElement.dataset.gutterBuffer === 'metadata' &&\n 'noNewline' in contentElement.dataset\n ) {\n if (\n preTrimCount > 0 ||\n (hasPostTrim && visibleLineIndex >= postTrimStart)\n ) {\n gutterElement.remove();\n contentElement.remove();\n rowCount++;\n }\n continue;\n }\n\n if (\n gutterElement.dataset.gutterBuffer === 'buffer' &&\n 'contentBuffer' in contentElement.dataset\n ) {\n const totalRows = this.getBufferSize(contentElement.dataset);\n if (totalRows == null) {\n throw new Error('FileDiff.trimColumnRows: invalid element');\n }\n if (preTrimCount > 0) {\n const rowsToRemove = Math.min(preTrimCount, totalRows);\n const newSize = totalRows - rowsToRemove;\n if (newSize > 0) {\n this.updateBufferSize(gutterElement, newSize);\n this.updateBufferSize(contentElement, newSize);\n rowCount += rowsToRemove;\n } else {\n gutterElement.remove();\n contentElement.remove();\n rowCount += totalRows;\n }\n preTrimCount -= rowsToRemove;\n }\n // If we are in a post clip era...\n else if (hasPostTrim) {\n const bufferStart = visibleLineIndex;\n const bufferEnd = visibleLineIndex + totalRows - 1;\n if (postTrimStart <= bufferStart) {\n gutterElement.remove();\n contentElement.remove();\n rowCount += totalRows;\n } else if (postTrimStart <= bufferEnd) {\n const rowsToRemove = bufferEnd - postTrimStart + 1;\n const newSize = totalRows - rowsToRemove;\n this.updateBufferSize(gutterElement, newSize);\n this.updateBufferSize(contentElement, newSize);\n rowCount += rowsToRemove;\n }\n }\n visibleLineIndex += totalRows;\n continue;\n }\n\n console.error({ gutterElement, contentElement });\n throw new Error('FileDiff.trimColumnRows: unknown row elements');\n }\n\n return rowCount;\n }\n\n private trimColumns({\n columns,\n diffStyle,\n overlapEnd,\n overlapStart,\n previousStart,\n trimEnd,\n trimStart,\n // NOTE(amadeus): If we return -1 it means something went wrong\n // with the trim...\n // oxlint-disable-next-line no-redundant-type-constituents\n }: TrimColumnsToOverlapProps): number | -1 {\n const preTrimCount = Math.max(0, overlapStart - previousStart);\n const postTrimStart = overlapEnd - previousStart;\n if (postTrimStart < 0) {\n throw new Error('FileDiff.trimColumns: overlap ends before previous');\n }\n const shouldTrimStart = trimStart > 0;\n const shouldTrimEnd = trimEnd > 0;\n if (!shouldTrimStart && !shouldTrimEnd) {\n return 0;\n }\n const effectivePreTrimCount = shouldTrimStart ? preTrimCount : 0;\n const effectivePostTrimStart = shouldTrimEnd ? postTrimStart : -1;\n\n if (diffStyle === 'unified' && !Array.isArray(columns)) {\n const removedRows = this.trimColumnRows(\n columns,\n effectivePreTrimCount,\n effectivePostTrimStart\n );\n return removedRows;\n } else if (diffStyle === 'split' && Array.isArray(columns)) {\n const deletionsTrim = this.trimColumnRows(\n columns[0],\n effectivePreTrimCount,\n effectivePostTrimStart\n );\n const additionsTrim = this.trimColumnRows(\n columns[1],\n effectivePreTrimCount,\n effectivePostTrimStart\n );\n // We should avoid the trim validation if we are split but\n // there's only one side\n if (\n columns[0] != null &&\n columns[1] != null &&\n deletionsTrim !== additionsTrim\n ) {\n throw new Error('FileDiff.trimColumns: split columns out of sync');\n }\n return columns[0] != null ? deletionsTrim : additionsTrim;\n } else {\n console.error({ diffStyle, columns });\n throw new Error('FileDiff.trimColumns: Invalid columns for diffType');\n }\n }\n\n private getBufferSize(properties: DOMStringMap): number | undefined {\n const parsed = Number.parseInt(properties?.bufferSize ?? '', 10);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n\n private updateBufferSize(element: HTMLElement, size: number): void {\n element.dataset.bufferSize = `${size}`;\n element.style.setProperty('grid-row', `span ${size}`);\n element.style.setProperty('min-height', `calc(${size} * 1lh)`);\n }\n\n private getCodeColumns(\n diffStyle: 'split' | 'unified',\n codeUnified: HTMLElement | undefined,\n codeDeletions: HTMLElement | undefined,\n codeAdditions: HTMLElement | undefined\n ):\n | [ColumnElements | undefined, ColumnElements | undefined]\n | ColumnElements\n | undefined {\n function getColumns(\n code: HTMLElement | undefined\n ): ColumnElements | undefined {\n if (code == null) {\n return undefined;\n }\n const gutter = code.children[0];\n const content = code.children[1];\n if (\n !(gutter instanceof HTMLElement) ||\n !(content instanceof HTMLElement) ||\n gutter.dataset.gutter == null ||\n content.dataset.content == null\n ) {\n return undefined;\n }\n return { gutter, content };\n }\n\n if (diffStyle === 'unified') {\n return getColumns(codeUnified);\n } else {\n const deletions = getColumns(codeDeletions);\n const additions = getColumns(codeAdditions);\n return deletions != null || additions != null\n ? [deletions, additions]\n : undefined;\n }\n }\n\n private applyBuffers(\n pre: HTMLPreElement,\n renderRange: RenderRange | undefined\n ) {\n const { disableVirtualizationBuffers = false } = this.options;\n if (disableVirtualizationBuffers || renderRange == null) {\n if (this.bufferBefore != null) {\n this.bufferBefore.parentNode?.removeChild(this.bufferBefore);\n this.bufferBefore = undefined;\n }\n if (this.bufferAfter != null) {\n this.bufferAfter.parentNode?.removeChild(this.bufferAfter);\n this.bufferAfter = undefined;\n }\n return;\n }\n // NOTE(amadeus): A very hacky pass at buffers outside the pre elements...\n // i may need to improve this...\n if (renderRange.bufferBefore > 0) {\n if (this.bufferBefore == null) {\n this.bufferBefore = document.createElement('div');\n this.bufferBefore.dataset.virtualizerBuffer = 'before';\n pre.before(this.bufferBefore);\n }\n this.bufferBefore.style.setProperty(\n 'height',\n `${renderRange.bufferBefore}px`\n );\n this.bufferBefore.style.setProperty('contain', 'strict');\n } else if (this.bufferBefore != null) {\n this.bufferBefore.parentNode?.removeChild(this.bufferBefore);\n this.bufferBefore = undefined;\n }\n\n if (renderRange.bufferAfter > 0) {\n if (this.bufferAfter == null) {\n this.bufferAfter = document.createElement('div');\n this.bufferAfter.dataset.virtualizerBuffer = 'after';\n pre.after(this.bufferAfter);\n }\n this.bufferAfter.style.setProperty(\n 'height',\n `${renderRange.bufferAfter}px`\n );\n this.bufferAfter.style.setProperty('contain', 'strict');\n } else if (this.bufferAfter != null) {\n this.bufferAfter.parentNode?.removeChild(this.bufferAfter);\n this.bufferAfter = undefined;\n }\n }\n\n private applyPreNodeAttributes(\n pre: HTMLPreElement,\n {\n themeStyles,\n baseThemeType,\n additionsContentAST,\n deletionsContentAST,\n totalLines,\n }: HunksRenderResult\n ): void {\n const {\n diffIndicators = 'bars',\n disableBackground = false,\n disableLineNumbers = false,\n overflow = 'scroll',\n themeType = 'system',\n diffStyle = 'split',\n } = this.options;\n const preProperties: PrePropertiesConfig = {\n type: 'diff',\n diffIndicators,\n disableBackground,\n disableLineNumbers,\n overflow,\n split:\n diffStyle === 'unified'\n ? false\n : additionsContentAST != null && deletionsContentAST != null,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n totalLines,\n };\n if (arePrePropertiesEqual(preProperties, this.appliedPreAttributes)) {\n return;\n }\n setPreNodeProperties(pre, preProperties);\n this.appliedPreAttributes = preProperties;\n }\n\n private applyErrorToDOM(error: Error, container: HTMLElement) {\n this.cleanupErrorWrapper();\n const pre = this.getOrCreatePreNode(container);\n pre.innerHTML = '';\n pre.parentNode?.removeChild(pre);\n this.pre = undefined;\n this.appliedPreAttributes = undefined;\n const shadowRoot =\n container.shadowRoot ?? container.attachShadow({ mode: 'open' });\n this.errorWrapper ??= document.createElement('div');\n this.errorWrapper.dataset.errorWrapper = '';\n this.errorWrapper.innerHTML = '';\n shadowRoot.appendChild(this.errorWrapper);\n const errorMessage = document.createElement('div');\n errorMessage.dataset.errorMessage = '';\n errorMessage.innerText = error.message;\n this.errorWrapper.appendChild(errorMessage);\n const errorStack = document.createElement('pre');\n errorStack.dataset.errorStack = '';\n errorStack.innerText = error.stack ?? 'No Error Stack';\n this.errorWrapper.appendChild(errorStack);\n }\n\n private cleanupErrorWrapper() {\n this.errorWrapper?.parentNode?.removeChild(this.errorWrapper);\n this.errorWrapper = undefined;\n }\n}\n\nfunction getElementChildren(\n node: ElementContent | undefined\n): ElementContent[] | undefined {\n if (node == null || node.type !== 'element') {\n return undefined;\n }\n return node.children ?? [];\n}\n"],"mappings":"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"}
|
|
@@ -24,8 +24,9 @@ var VirtualizedFile = class extends File {
|
|
|
24
24
|
setOptions(options) {
|
|
25
25
|
if (options == null) return;
|
|
26
26
|
const previousOverflow = this.options.overflow;
|
|
27
|
+
const previousCollapsed = this.options.collapsed;
|
|
27
28
|
super.setOptions(options);
|
|
28
|
-
if (previousOverflow !== this.options.overflow) {
|
|
29
|
+
if (previousOverflow !== this.options.overflow || previousCollapsed !== this.options.collapsed) {
|
|
29
30
|
this.heightCache.clear();
|
|
30
31
|
this.computeApproximateSize();
|
|
31
32
|
this.renderRange = void 0;
|
|
@@ -76,11 +77,12 @@ var VirtualizedFile = class extends File {
|
|
|
76
77
|
const isFirstCompute = this.height === 0;
|
|
77
78
|
this.height = 0;
|
|
78
79
|
if (this.file == null) return;
|
|
79
|
-
const { disableFileHeader = false, overflow = "scroll" } = this.options;
|
|
80
|
+
const { disableFileHeader = false, collapsed = false, overflow = "scroll" } = this.options;
|
|
80
81
|
const { diffHeaderHeight, fileGap, lineHeight } = this.metrics;
|
|
81
82
|
const lines = this.getOrCreateLineCache(this.file);
|
|
82
83
|
if (!disableFileHeader) this.height += diffHeaderHeight;
|
|
83
84
|
else this.height += fileGap;
|
|
85
|
+
if (collapsed) return;
|
|
84
86
|
if (overflow === "scroll" && this.lineAnnotations.length === 0) this.height += this.getOrCreateLineCache(this.file).length * lineHeight;
|
|
85
87
|
else iterateOverFile({
|
|
86
88
|
lines,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualizedFile.js","names":["virtualizer: Virtualizer","metrics: VirtualFileMetrics","idealStartHunk","startingLine","clampedTotalLines","bufferBefore","hunkOffsets: number[]","firstVisibleHunk: number | undefined","centerHunk: number | undefined","overflowCounter: number | undefined","lineHeight"],"sources":["../../src/components/VirtualizedFile.ts"],"sourcesContent":["import { DEFAULT_VIRTUAL_FILE_METRICS } from '../constants';\nimport type {\n FileContents,\n RenderRange,\n RenderWindow,\n VirtualFileMetrics,\n} from '../types';\nimport { iterateOverFile } from '../utils/iterateOverFile';\nimport type { WorkerPoolManager } from '../worker';\nimport { File, type FileOptions, type FileRenderProps } from './File';\nimport type { Virtualizer } from './Virtualizer';\n\nlet instanceId = -1;\n\nexport class VirtualizedFile<\n LAnnotation = undefined,\n> extends File<LAnnotation> {\n override readonly __id: string = `virtualized-file:${++instanceId}`;\n\n public top: number | undefined;\n public height: number = 0;\n // Sparse map: line index -> measured height\n // Only stores lines that differ from what is returned from default line\n // height\n private heightCache: Map<number, number> = new Map();\n private isVisible: boolean = false;\n\n constructor(\n options: FileOptions<LAnnotation> | undefined,\n private virtualizer: Virtualizer,\n private metrics: VirtualFileMetrics = DEFAULT_VIRTUAL_FILE_METRICS,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\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.heightCache.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 to clear height cache when overflow changes\n override setOptions(options: FileOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n const previousOverflow = this.options.overflow;\n\n super.setOptions(options);\n\n if (previousOverflow !== this.options.overflow) {\n this.heightCache.clear();\n this.computeApproximateSize();\n this.renderRange = undefined;\n }\n this.virtualizer.instanceChanged(this);\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n public reconcileHeights(): void {\n if (this.fileContainer == null || this.file == null) {\n this.height = 0;\n return;\n }\n const { overflow = 'scroll' } = this.options;\n this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);\n\n // If the file has no annotations and we are using the scroll variant, then\n // we can probably skip everything\n if (\n overflow === 'scroll' &&\n this.lineAnnotations.length === 0 &&\n !this.virtualizer.config.resizeDebugging\n ) {\n return;\n }\n\n let hasLineHeightChange = false;\n\n // Single code element (no split mode)\n if (this.code == null) return;\n const content = this.code.children[1]; // Content column (gutter is [0])\n if (!(content instanceof HTMLElement)) return;\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 = line.getBoundingClientRect().height;\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 hasLineHeightChange = 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.heightCache.delete(lineIndex);\n }\n // Non-standard height, cache it\n else {\n this.heightCache.set(lineIndex, measuredHeight);\n }\n }\n\n if (hasLineHeightChange || this.virtualizer.config.resizeDebugging) {\n this.computeApproximateSize();\n }\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.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n }\n return this.render({ file: this.file });\n };\n\n override cleanUp(): void {\n if (this.fileContainer != null) {\n this.virtualizer.disconnect(this.fileContainer);\n }\n super.cleanUp();\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\n private computeApproximateSize(): void {\n const isFirstCompute = this.height === 0;\n this.height = 0;\n if (this.file == null) {\n return;\n }\n\n const { disableFileHeader = false, overflow = 'scroll' } = this.options;\n const { diffHeaderHeight, fileGap, lineHeight } = this.metrics;\n const lines = this.getOrCreateLineCache(this.file);\n\n // Header or initial padding\n if (!disableFileHeader) {\n this.height += diffHeaderHeight;\n } else {\n this.height += fileGap;\n }\n\n if (overflow === 'scroll' && this.lineAnnotations.length === 0) {\n this.height += this.getOrCreateLineCache(this.file).length * lineHeight;\n } else {\n iterateOverFile({\n lines,\n callback: ({ lineIndex }) => {\n this.height += this.getLineHeight(lineIndex, false);\n },\n });\n }\n\n // Bottom padding\n if (lines.length > 0) {\n this.height += fileGap;\n }\n\n if (\n this.fileContainer != null &&\n this.virtualizer.config.resizeDebugging &&\n !isFirstCompute\n ) {\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: this.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 }\n\n public setVisibility(visible: boolean): void {\n if (this.fileContainer == null) {\n return;\n }\n if (visible && !this.isVisible) {\n this.top = this.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n this.isVisible = true;\n } else if (!visible && this.isVisible) {\n this.isVisible = false;\n this.rerender();\n }\n }\n\n override render({\n fileContainer,\n file,\n ...props\n }: FileRenderProps<LAnnotation>): boolean {\n const isFirstRender = this.fileContainer == null;\n\n this.file ??= file;\n\n fileContainer = this.getOrCreateFileContainerNode(fileContainer);\n\n if (this.file == null) {\n console.error(\n 'VirtualizedFile.render: attempting to virtually render when we dont have file'\n );\n return false;\n }\n\n if (isFirstRender) {\n this.computeApproximateSize();\n this.virtualizer.connect(fileContainer, this);\n this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);\n this.isVisible = this.virtualizer.isInstanceVisible(\n this.top,\n this.height\n );\n } else {\n this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);\n }\n\n if (!this.isVisible) {\n return this.renderPlaceholder(this.height);\n }\n\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const renderRange = this.computeRenderRangeFromWindow(\n this.file,\n this.top,\n windowSpecs\n );\n return super.render({\n file: this.file,\n fileContainer,\n renderRange,\n ...props,\n });\n }\n\n private computeRenderRangeFromWindow(\n file: FileContents,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const { disableFileHeader = false, overflow = 'scroll' } = this.options;\n const { diffHeaderHeight, fileGap, hunkLineCount, lineHeight } =\n this.metrics;\n const lines = this.getOrCreateLineCache(file);\n const lineCount = lines.length;\n const fileHeight = this.height;\n const headerRegion = disableFileHeader ? fileGap : diffHeaderHeight;\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 - fileGap,\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 * 2;\n const totalHunks = totalLines / hunkLineCount;\n const viewportCenter = (top + bottom) / 2;\n\n // Simple case: overflow scroll with no annotations - pure math!\n if (overflow === 'scroll' && this.lineAnnotations.length === 0) {\n // Find which line is at viewport center\n const centerLine = Math.floor(\n (viewportCenter - (fileTop + headerRegion)) / 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 = 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\n let absoluteLineTop = fileTop + headerRegion;\n let currentLine = 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n iterateOverFile({\n lines,\n callback: ({ lineIndex }) => {\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n\n if (isAtHunkBoundary) {\n hunkOffsets.push(absoluteLineTop - (fileTop + headerRegion));\n\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n return true;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(lineIndex, false);\n const currentHunk = Math.floor(currentLine / hunkLineCount);\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 return false;\n },\n });\n\n // No visible lines found\n if (firstVisibleHunk == null) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - fileGap,\n };\n }\n\n // Calculate balanced startingLine centered around the viewport center\n const collectedHunks = hunkOffsets.length;\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift startHunk back\n const maxStartHunk = Math.max(0, collectedHunks - totalHunks);\n const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));\n const startingLine = startHunk * hunkLineCount;\n\n // If we wanted to start before 0, reduce totalLines by the clamped amount\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n // Use hunkOffsets array for efficient buffer calculations\n const bufferBefore = hunkOffsets[startHunk] ?? 0;\n\n // Calculate bufferAfter\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? fileHeight - headerRegion - hunkOffsets[finalHunkIndex] - fileGap\n : fileHeight - (absoluteLineTop - fileTop) - fileGap;\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VirtualizedFile.js","names":["virtualizer: Virtualizer","metrics: VirtualFileMetrics","idealStartHunk","startingLine","clampedTotalLines","bufferBefore","hunkOffsets: number[]","firstVisibleHunk: number | undefined","centerHunk: number | undefined","overflowCounter: number | undefined","lineHeight"],"sources":["../../src/components/VirtualizedFile.ts"],"sourcesContent":["import { DEFAULT_VIRTUAL_FILE_METRICS } from '../constants';\nimport type {\n FileContents,\n RenderRange,\n RenderWindow,\n VirtualFileMetrics,\n} from '../types';\nimport { iterateOverFile } from '../utils/iterateOverFile';\nimport type { WorkerPoolManager } from '../worker';\nimport { File, type FileOptions, type FileRenderProps } from './File';\nimport type { Virtualizer } from './Virtualizer';\n\nlet instanceId = -1;\n\nexport class VirtualizedFile<\n LAnnotation = undefined,\n> extends File<LAnnotation> {\n override readonly __id: string = `virtualized-file:${++instanceId}`;\n\n public top: number | undefined;\n public height: number = 0;\n // Sparse map: line index -> measured height\n // Only stores lines that differ from what is returned from default line\n // height\n private heightCache: Map<number, number> = new Map();\n private isVisible: boolean = false;\n\n constructor(\n options: FileOptions<LAnnotation> | undefined,\n private virtualizer: Virtualizer,\n private metrics: VirtualFileMetrics = DEFAULT_VIRTUAL_FILE_METRICS,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\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.heightCache.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 to clear height cache when overflow changes\n override setOptions(options: FileOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n const previousOverflow = this.options.overflow;\n const previousCollapsed = this.options.collapsed;\n\n super.setOptions(options);\n\n if (\n previousOverflow !== this.options.overflow ||\n previousCollapsed !== this.options.collapsed\n ) {\n this.heightCache.clear();\n this.computeApproximateSize();\n this.renderRange = undefined;\n }\n this.virtualizer.instanceChanged(this);\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n public reconcileHeights(): void {\n if (this.fileContainer == null || this.file == null) {\n this.height = 0;\n return;\n }\n const { overflow = 'scroll' } = this.options;\n this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);\n\n // If the file has no annotations and we are using the scroll variant, then\n // we can probably skip everything\n if (\n overflow === 'scroll' &&\n this.lineAnnotations.length === 0 &&\n !this.virtualizer.config.resizeDebugging\n ) {\n return;\n }\n\n let hasLineHeightChange = false;\n\n // Single code element (no split mode)\n if (this.code == null) return;\n const content = this.code.children[1]; // Content column (gutter is [0])\n if (!(content instanceof HTMLElement)) return;\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 = line.getBoundingClientRect().height;\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 hasLineHeightChange = 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.heightCache.delete(lineIndex);\n }\n // Non-standard height, cache it\n else {\n this.heightCache.set(lineIndex, measuredHeight);\n }\n }\n\n if (hasLineHeightChange || this.virtualizer.config.resizeDebugging) {\n this.computeApproximateSize();\n }\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.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n }\n return this.render({ file: this.file });\n };\n\n override cleanUp(): void {\n if (this.fileContainer != null) {\n this.virtualizer.disconnect(this.fileContainer);\n }\n super.cleanUp();\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\n private computeApproximateSize(): void {\n const isFirstCompute = this.height === 0;\n this.height = 0;\n if (this.file == null) {\n return;\n }\n\n const {\n disableFileHeader = false,\n collapsed = false,\n overflow = 'scroll',\n } = this.options;\n const { diffHeaderHeight, fileGap, lineHeight } = this.metrics;\n const lines = this.getOrCreateLineCache(this.file);\n\n // Header or initial padding\n if (!disableFileHeader) {\n this.height += diffHeaderHeight;\n } else {\n this.height += fileGap;\n }\n if (collapsed) {\n return;\n }\n\n if (overflow === 'scroll' && this.lineAnnotations.length === 0) {\n this.height += this.getOrCreateLineCache(this.file).length * lineHeight;\n } else {\n iterateOverFile({\n lines,\n callback: ({ lineIndex }) => {\n this.height += this.getLineHeight(lineIndex, false);\n },\n });\n }\n\n // Bottom padding\n if (lines.length > 0) {\n this.height += fileGap;\n }\n\n if (\n this.fileContainer != null &&\n this.virtualizer.config.resizeDebugging &&\n !isFirstCompute\n ) {\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: this.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 }\n\n public setVisibility(visible: boolean): void {\n if (this.fileContainer == null) {\n return;\n }\n if (visible && !this.isVisible) {\n this.top = this.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n this.isVisible = true;\n } else if (!visible && this.isVisible) {\n this.isVisible = false;\n this.rerender();\n }\n }\n\n override render({\n fileContainer,\n file,\n ...props\n }: FileRenderProps<LAnnotation>): boolean {\n const isFirstRender = this.fileContainer == null;\n\n this.file ??= file;\n\n fileContainer = this.getOrCreateFileContainerNode(fileContainer);\n\n if (this.file == null) {\n console.error(\n 'VirtualizedFile.render: attempting to virtually render when we dont have file'\n );\n return false;\n }\n\n if (isFirstRender) {\n this.computeApproximateSize();\n this.virtualizer.connect(fileContainer, this);\n this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);\n this.isVisible = this.virtualizer.isInstanceVisible(\n this.top,\n this.height\n );\n } else {\n this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);\n }\n\n if (!this.isVisible) {\n return this.renderPlaceholder(this.height);\n }\n\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const renderRange = this.computeRenderRangeFromWindow(\n this.file,\n this.top,\n windowSpecs\n );\n return super.render({\n file: this.file,\n fileContainer,\n renderRange,\n ...props,\n });\n }\n\n private computeRenderRangeFromWindow(\n file: FileContents,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const { disableFileHeader = false, overflow = 'scroll' } = this.options;\n const { diffHeaderHeight, fileGap, hunkLineCount, lineHeight } =\n this.metrics;\n const lines = this.getOrCreateLineCache(file);\n const lineCount = lines.length;\n const fileHeight = this.height;\n const headerRegion = disableFileHeader ? fileGap : diffHeaderHeight;\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 - fileGap,\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 * 2;\n const totalHunks = totalLines / hunkLineCount;\n const viewportCenter = (top + bottom) / 2;\n\n // Simple case: overflow scroll with no annotations - pure math!\n if (overflow === 'scroll' && this.lineAnnotations.length === 0) {\n // Find which line is at viewport center\n const centerLine = Math.floor(\n (viewportCenter - (fileTop + headerRegion)) / 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 = 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\n let absoluteLineTop = fileTop + headerRegion;\n let currentLine = 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n iterateOverFile({\n lines,\n callback: ({ lineIndex }) => {\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n\n if (isAtHunkBoundary) {\n hunkOffsets.push(absoluteLineTop - (fileTop + headerRegion));\n\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n return true;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(lineIndex, false);\n const currentHunk = Math.floor(currentLine / hunkLineCount);\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 return false;\n },\n });\n\n // No visible lines found\n if (firstVisibleHunk == null) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter: fileHeight - headerRegion - fileGap,\n };\n }\n\n // Calculate balanced startingLine centered around the viewport center\n const collectedHunks = hunkOffsets.length;\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift startHunk back\n const maxStartHunk = Math.max(0, collectedHunks - totalHunks);\n const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));\n const startingLine = startHunk * hunkLineCount;\n\n // If we wanted to start before 0, reduce totalLines by the clamped amount\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n // Use hunkOffsets array for efficient buffer calculations\n const bufferBefore = hunkOffsets[startHunk] ?? 0;\n\n // Calculate bufferAfter\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? fileHeight - headerRegion - hunkOffsets[finalHunkIndex] - fileGap\n : fileHeight - (absoluteLineTop - fileTop) - fileGap;\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -30,8 +30,9 @@ var VirtualizedFileDiff = class extends FileDiff {
|
|
|
30
30
|
if (options == null) return;
|
|
31
31
|
const previousDiffStyle = this.options.diffStyle;
|
|
32
32
|
const previousOverflow = this.options.overflow;
|
|
33
|
+
const previousCollapsed = this.options.collapsed;
|
|
33
34
|
super.setOptions(options);
|
|
34
|
-
if (previousDiffStyle !== this.options.diffStyle || previousOverflow !== this.options.overflow) {
|
|
35
|
+
if (previousDiffStyle !== this.options.diffStyle || previousOverflow !== this.options.overflow || previousCollapsed !== this.options.collapsed) {
|
|
35
36
|
this.heightCache.clear();
|
|
36
37
|
this.computeApproximateSize();
|
|
37
38
|
this.renderRange = void 0;
|
|
@@ -103,12 +104,13 @@ var VirtualizedFileDiff = class extends FileDiff {
|
|
|
103
104
|
const isFirstCompute = this.height === 0;
|
|
104
105
|
this.height = 0;
|
|
105
106
|
if (this.fileDiff == null) return;
|
|
106
|
-
const { disableFileHeader = false, expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
|
|
107
|
+
const { disableFileHeader = false, expandUnchanged = false, collapsed = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
|
|
107
108
|
const { diffHeaderHeight, fileGap, hunkSeparatorHeight } = this.metrics;
|
|
108
109
|
const diffStyle = this.getDiffStyle();
|
|
109
110
|
const separatorGap = hunkSeparators !== "simple" && hunkSeparators !== "metadata" && hunkSeparators !== "line-info-basic" ? fileGap : 0;
|
|
110
111
|
if (!disableFileHeader) this.height += diffHeaderHeight;
|
|
111
112
|
else if (hunkSeparators !== "simple" && hunkSeparators !== "metadata") this.height += fileGap;
|
|
113
|
+
if (collapsed) return;
|
|
112
114
|
iterateOverDiff({
|
|
113
115
|
diff: this.fileDiff,
|
|
114
116
|
diffStyle,
|