@pierre/diffs 1.1.0-beta.6 → 1.1.0-beta.8
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 +40 -0
- package/dist/components/AdvancedVirtualizedFileDiff.d.ts.map +1 -0
- package/dist/components/AdvancedVirtualizedFileDiff.js +145 -0
- package/dist/components/AdvancedVirtualizedFileDiff.js.map +1 -0
- package/dist/components/AdvancedVirtualizer.d.ts +38 -0
- package/dist/components/AdvancedVirtualizer.d.ts.map +1 -0
- package/dist/components/AdvancedVirtualizer.js +201 -0
- package/dist/components/AdvancedVirtualizer.js.map +1 -0
- package/dist/components/File.d.ts +58 -33
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +223 -22
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +42 -16
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +505 -65
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/FileStream.d.ts +5 -0
- package/dist/components/FileStream.d.ts.map +1 -1
- package/dist/components/FileStream.js +66 -8
- package/dist/components/FileStream.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +33 -0
- package/dist/components/VirtualizedFile.d.ts.map +1 -0
- package/dist/components/VirtualizedFile.js +227 -0
- package/dist/components/VirtualizedFile.js.map +1 -0
- package/dist/components/VirtualizedFileDiff.d.ts +39 -0
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -0
- package/dist/components/VirtualizedFileDiff.js +316 -0
- package/dist/components/VirtualizedFileDiff.js.map +1 -0
- package/dist/components/Virtualizer.d.ts +63 -0
- package/dist/components/Virtualizer.d.ts.map +1 -0
- package/dist/components/Virtualizer.js +369 -0
- package/dist/components/Virtualizer.js.map +1 -0
- package/dist/components/VirtulizerDevelopment.d.ts +14 -0
- package/dist/components/VirtulizerDevelopment.d.ts.map +1 -0
- package/dist/components/web-components.d.ts +1 -1
- package/dist/components/web-components.d.ts.map +1 -1
- package/dist/constants.d.ts +4 -7
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +14 -6
- package/dist/constants.js.map +1 -1
- package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
- package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/cleanUpResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/constants.d.ts.map +1 -1
- package/dist/highlighter/languages/getResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +1 -1
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/hasResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/registerCustomLanguage.d.ts +11 -4
- package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/resolveLanguage.d.ts +1 -1
- package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/resolveLanguages.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/constants.d.ts.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.js +10 -7
- package/dist/managers/LineSelectionManager.d.ts +14 -15
- package/dist/managers/LineSelectionManager.d.ts.map +1 -1
- package/dist/managers/LineSelectionManager.js +60 -71
- package/dist/managers/LineSelectionManager.js.map +1 -1
- package/dist/managers/MouseEventManager.d.ts +13 -6
- package/dist/managers/MouseEventManager.d.ts.map +1 -1
- package/dist/managers/MouseEventManager.js +161 -47
- package/dist/managers/MouseEventManager.js.map +1 -1
- package/dist/managers/ResizeManager.d.ts +6 -1
- package/dist/managers/ResizeManager.d.ts.map +1 -1
- package/dist/managers/ResizeManager.js +114 -64
- package/dist/managers/ResizeManager.js.map +1 -1
- package/dist/managers/ScrollSyncManager.d.ts.map +1 -1
- package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
- package/dist/react/File.d.ts +1 -0
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +2 -1
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +1 -0
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +2 -1
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +1 -0
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +2 -1
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +1 -0
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +3 -2
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/Virtualizer.d.ts +25 -0
- package/dist/react/Virtualizer.d.ts.map +1 -0
- package/dist/react/Virtualizer.js +38 -0
- package/dist/react/Virtualizer.js.map +1 -0
- package/dist/react/WorkerPoolContext.d.ts.map +1 -1
- package/dist/react/WorkerPoolContext.js +1 -1
- package/dist/react/WorkerPoolContext.js.map +1 -1
- package/dist/react/constants.d.ts.map +1 -1
- package/dist/react/index.d.ts +3 -2
- package/dist/react/index.js +2 -1
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/types.d.ts +5 -3
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.d.ts +5 -5
- package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
- package/dist/react/utils/renderFileChildren.d.ts +5 -5
- package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
- package/dist/react/utils/templateRender.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +5 -3
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +6 -2
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +5 -3
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +6 -2
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useStableCallback.d.ts.map +1 -1
- package/dist/react/utils/useStableCallback.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +15 -10
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +240 -136
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +12 -5
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +90 -31
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/shiki-stream/stream.d.ts +2 -2
- package/dist/shiki-stream/stream.d.ts.map +1 -1
- package/dist/shiki-stream/stream.js.map +1 -1
- package/dist/shiki-stream/tokenizer.d.ts +2 -2
- package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
- package/dist/shiki-stream/tokenizer.js.map +1 -1
- package/dist/shiki-stream/types.d.ts +18 -18
- package/dist/shiki-stream/types.d.ts.map +1 -1
- package/dist/sprite.d.ts +1 -1
- package/dist/sprite.d.ts.map +1 -1
- package/dist/ssr/FileDiffReact.d.ts.map +1 -1
- package/dist/ssr/FileDiffReact.js +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
- package/dist/ssr/preloadPatchFile.js.map +1 -1
- package/dist/ssr/renderHTML.d.ts.map +1 -1
- package/dist/style.js +1 -1
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +191 -172
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.js.map +1 -1
- package/dist/utils/areFilesEqual.d.ts.map +1 -1
- package/dist/utils/areHunkDataEqual.d.ts.map +1 -1
- package/dist/utils/areLineAnnotationsEqual.d.ts.map +1 -1
- package/dist/utils/areObjectsEqual.d.ts.map +1 -1
- package/dist/utils/areOptionsEqual.d.ts +1 -1
- package/dist/utils/areOptionsEqual.d.ts.map +1 -1
- package/dist/utils/arePrePropertiesEqual.d.ts.map +1 -1
- package/dist/utils/arePrePropertiesEqual.js +1 -1
- package/dist/utils/arePrePropertiesEqual.js.map +1 -1
- package/dist/utils/areRenderRangesEqual.d.ts.map +1 -1
- package/dist/utils/areSelectionsEqual.d.ts.map +1 -1
- package/dist/utils/areThemesEqual.d.ts.map +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.d.ts.map +1 -1
- package/dist/utils/areWorkerStatsEqual.d.ts.map +1 -1
- package/dist/utils/cleanLastNewline.d.ts.map +1 -1
- package/dist/utils/createAnnotationElement.d.ts.map +1 -1
- package/dist/utils/createAnnotationWrapperNode.d.ts.map +1 -1
- package/dist/utils/createContentColumn.d.ts +7 -0
- package/dist/utils/createContentColumn.d.ts.map +1 -0
- package/dist/utils/createContentColumn.js +17 -0
- package/dist/utils/createContentColumn.js.map +1 -0
- package/dist/utils/createEmptyRowBuffer.d.ts.map +1 -1
- package/dist/utils/createEmptyRowBuffer.js +2 -1
- package/dist/utils/createEmptyRowBuffer.js.map +1 -1
- package/dist/utils/createFileHeaderElement.d.ts.map +1 -1
- package/dist/utils/createHoverContentNode.d.ts.map +1 -1
- package/dist/utils/createNoNewlineElement.d.ts +2 -1
- package/dist/utils/createNoNewlineElement.d.ts.map +1 -1
- package/dist/utils/createNoNewlineElement.js +3 -6
- package/dist/utils/createNoNewlineElement.js.map +1 -1
- package/dist/utils/createPreElement.d.ts +2 -1
- package/dist/utils/createPreElement.d.ts.map +1 -1
- package/dist/utils/createPreElement.js +4 -3
- package/dist/utils/createPreElement.js.map +1 -1
- package/dist/utils/createRowNodes.d.ts.map +1 -1
- package/dist/utils/createSeparator.d.ts.map +1 -1
- package/dist/utils/createSeparator.js +1 -1
- package/dist/utils/createSeparator.js.map +1 -1
- package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
- package/dist/utils/createSpanNodeFromToken.js.map +1 -1
- package/dist/utils/createStyleElement.d.ts.map +1 -1
- package/dist/utils/createTransformerWithState.d.ts.map +1 -1
- package/dist/utils/createUnsafeCSSStyleNode.d.ts.map +1 -1
- package/dist/utils/createWindowFromScrollPosition.d.ts.map +1 -1
- package/dist/utils/cssWrappers.d.ts.map +1 -1
- package/dist/utils/diffAcceptRejectHunk.d.ts +1 -1
- package/dist/utils/diffAcceptRejectHunk.d.ts.map +1 -1
- package/dist/utils/formatCSSVariablePrefix.d.ts +1 -1
- package/dist/utils/formatCSSVariablePrefix.d.ts.map +1 -1
- package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
- package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
- package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
- package/dist/utils/getHunkSeparatorSlotName.d.ts +3 -1
- package/dist/utils/getHunkSeparatorSlotName.d.ts.map +1 -1
- package/dist/utils/getHunkSeparatorSlotName.js.map +1 -1
- package/dist/utils/getIconForType.d.ts +1 -1
- package/dist/utils/getIconForType.d.ts.map +1 -1
- package/dist/utils/getLineAnnotationName.d.ts.map +1 -1
- package/dist/utils/getLineEndingType.d.ts +1 -1
- package/dist/utils/getLineEndingType.d.ts.map +1 -1
- package/dist/utils/getLineNodes.d.ts.map +1 -1
- package/dist/utils/getOrCreateCodeNode.d.ts +4 -2
- package/dist/utils/getOrCreateCodeNode.d.ts.map +1 -1
- package/dist/utils/getOrCreateCodeNode.js +9 -6
- package/dist/utils/getOrCreateCodeNode.js.map +1 -1
- package/dist/utils/getSingularPatch.d.ts.map +1 -1
- package/dist/utils/getThemes.d.ts.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
- package/dist/utils/hast_utils.d.ts +6 -3
- package/dist/utils/hast_utils.d.ts.map +1 -1
- package/dist/utils/hast_utils.js +28 -4
- package/dist/utils/hast_utils.js.map +1 -1
- package/dist/utils/isDefaultRenderRange.d.ts.map +1 -1
- package/dist/utils/isWorkerContext.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.d.ts +26 -13
- package/dist/utils/iterateOverDiff.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.js +94 -55
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/iterateOverFile.d.ts +50 -0
- package/dist/utils/iterateOverFile.d.ts.map +1 -0
- package/dist/utils/iterateOverFile.js +49 -0
- package/dist/utils/iterateOverFile.js.map +1 -0
- package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.d.ts +6 -6
- package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.js +3 -2
- package/dist/utils/parseDiffFromFile.js.map +1 -1
- package/dist/utils/parseLineType.d.ts +1 -1
- package/dist/utils/parseLineType.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts +12 -10
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +16 -9
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.d.ts.map +1 -1
- package/dist/utils/processLine.d.ts.map +1 -1
- package/dist/utils/processLine.js +7 -24
- package/dist/utils/processLine.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.d.ts +2 -2
- package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +15 -14
- package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
- package/dist/utils/renderFileWithHighlighter.d.ts +7 -2
- package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderFileWithHighlighter.js +30 -4
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/resolveVirtualFileMetrics.d.ts +7 -0
- package/dist/utils/resolveVirtualFileMetrics.d.ts.map +1 -0
- package/dist/utils/resolveVirtualFileMetrics.js +24 -0
- package/dist/utils/resolveVirtualFileMetrics.js.map +1 -0
- package/dist/utils/setLanguageOverride.d.ts.map +1 -1
- package/dist/utils/setWrapperNodeProps.d.ts +1 -0
- package/dist/utils/setWrapperNodeProps.d.ts.map +1 -1
- package/dist/utils/setWrapperNodeProps.js +19 -12
- package/dist/utils/setWrapperNodeProps.js.map +1 -1
- package/dist/utils/splitFileContents.d.ts +12 -0
- package/dist/utils/splitFileContents.d.ts.map +1 -0
- package/dist/utils/splitFileContents.js +17 -0
- package/dist/utils/splitFileContents.js.map +1 -0
- package/dist/utils/trimPatchContext.d.ts +5 -5
- package/dist/utils/trimPatchContext.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +2 -2
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +36 -24
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/getOrCreateWorkerPoolSingleton.d.ts.map +1 -1
- package/dist/worker/getOrCreateWorkerPoolSingleton.js.map +1 -1
- package/dist/worker/types.d.ts +26 -26
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/worker-portable.js +323 -143
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +206 -106
- package/dist/worker/worker.js.map +1 -1
- package/package.json +52 -53
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { DEFAULT_VIRTUAL_FILE_METRICS } from "../constants.js";
|
|
2
|
+
import { iterateOverFile } from "../utils/iterateOverFile.js";
|
|
3
|
+
import { File } from "./File.js";
|
|
4
|
+
|
|
5
|
+
//#region src/components/VirtualizedFile.ts
|
|
6
|
+
let instanceId = -1;
|
|
7
|
+
var VirtualizedFile = class extends File {
|
|
8
|
+
__id = `virtualized-file:${++instanceId}`;
|
|
9
|
+
top;
|
|
10
|
+
height = 0;
|
|
11
|
+
heightCache = /* @__PURE__ */ new Map();
|
|
12
|
+
isVisible = false;
|
|
13
|
+
constructor(options, virtualizer, metrics = DEFAULT_VIRTUAL_FILE_METRICS, workerManager, isContainerManaged = false) {
|
|
14
|
+
super(options, workerManager, isContainerManaged);
|
|
15
|
+
this.virtualizer = virtualizer;
|
|
16
|
+
this.metrics = metrics;
|
|
17
|
+
}
|
|
18
|
+
getLineHeight(lineIndex, hasMetadataLine = false) {
|
|
19
|
+
const cached = this.heightCache.get(lineIndex);
|
|
20
|
+
if (cached != null) return cached;
|
|
21
|
+
const multiplier = hasMetadataLine ? 2 : 1;
|
|
22
|
+
return this.metrics.lineHeight * multiplier;
|
|
23
|
+
}
|
|
24
|
+
setOptions(options) {
|
|
25
|
+
if (options == null) return;
|
|
26
|
+
const previousOverflow = this.options.overflow;
|
|
27
|
+
super.setOptions(options);
|
|
28
|
+
if (previousOverflow !== this.options.overflow) {
|
|
29
|
+
this.heightCache.clear();
|
|
30
|
+
this.computeApproximateSize();
|
|
31
|
+
this.renderRange = void 0;
|
|
32
|
+
}
|
|
33
|
+
this.virtualizer.instanceChanged(this);
|
|
34
|
+
}
|
|
35
|
+
reconcileHeights() {
|
|
36
|
+
if (this.fileContainer == null || this.file == null) {
|
|
37
|
+
this.height = 0;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const { overflow = "scroll" } = this.options;
|
|
41
|
+
this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);
|
|
42
|
+
if (overflow === "scroll" && this.lineAnnotations.length === 0 && !this.virtualizer.config.resizeDebugging) return;
|
|
43
|
+
let hasLineHeightChange = false;
|
|
44
|
+
if (this.code == null) return;
|
|
45
|
+
const content = this.code.children[1];
|
|
46
|
+
if (!(content instanceof HTMLElement)) return;
|
|
47
|
+
for (const line of content.children) {
|
|
48
|
+
if (!(line instanceof HTMLElement)) continue;
|
|
49
|
+
const lineIndexAttr = line.dataset.lineIndex;
|
|
50
|
+
if (lineIndexAttr == null) continue;
|
|
51
|
+
const lineIndex = Number(lineIndexAttr);
|
|
52
|
+
let measuredHeight = line.getBoundingClientRect().height;
|
|
53
|
+
let hasMetadata = false;
|
|
54
|
+
if (line.nextElementSibling instanceof HTMLElement && ("lineAnnotation" in line.nextElementSibling.dataset || "noNewline" in line.nextElementSibling.dataset)) {
|
|
55
|
+
if ("noNewline" in line.nextElementSibling.dataset) hasMetadata = true;
|
|
56
|
+
measuredHeight += line.nextElementSibling.getBoundingClientRect().height;
|
|
57
|
+
}
|
|
58
|
+
const expectedHeight = this.getLineHeight(lineIndex, hasMetadata);
|
|
59
|
+
if (measuredHeight === expectedHeight) continue;
|
|
60
|
+
hasLineHeightChange = true;
|
|
61
|
+
if (measuredHeight === this.metrics.lineHeight * (hasMetadata ? 2 : 1)) this.heightCache.delete(lineIndex);
|
|
62
|
+
else this.heightCache.set(lineIndex, measuredHeight);
|
|
63
|
+
}
|
|
64
|
+
if (hasLineHeightChange || this.virtualizer.config.resizeDebugging) this.computeApproximateSize();
|
|
65
|
+
}
|
|
66
|
+
onRender = (dirty) => {
|
|
67
|
+
if (this.fileContainer == null || this.file == null) return false;
|
|
68
|
+
if (dirty) this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);
|
|
69
|
+
return this.render({ file: this.file });
|
|
70
|
+
};
|
|
71
|
+
cleanUp() {
|
|
72
|
+
if (this.fileContainer != null) this.virtualizer.disconnect(this.fileContainer);
|
|
73
|
+
super.cleanUp();
|
|
74
|
+
}
|
|
75
|
+
computeApproximateSize() {
|
|
76
|
+
this.height = 0;
|
|
77
|
+
if (this.file == null) return;
|
|
78
|
+
const { disableFileHeader = false, overflow = "scroll" } = this.options;
|
|
79
|
+
const { diffHeaderHeight, fileGap, lineHeight } = this.metrics;
|
|
80
|
+
const lines = this.getOrCreateLineCache(this.file);
|
|
81
|
+
if (!disableFileHeader) this.height += diffHeaderHeight;
|
|
82
|
+
else this.height += fileGap;
|
|
83
|
+
if (overflow === "scroll" && this.lineAnnotations.length === 0) this.height += this.getOrCreateLineCache(this.file).length * lineHeight;
|
|
84
|
+
else iterateOverFile({
|
|
85
|
+
lines,
|
|
86
|
+
callback: ({ lineIndex }) => {
|
|
87
|
+
this.height += this.getLineHeight(lineIndex, false);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
if (lines.length > 0) this.height += fileGap;
|
|
91
|
+
if (this.fileContainer != null && this.virtualizer.config.resizeDebugging) {
|
|
92
|
+
const rect = this.fileContainer.getBoundingClientRect();
|
|
93
|
+
if (rect.height !== this.height) console.log("VirtualizedFile.computeApproximateSize: computed height doesnt match", {
|
|
94
|
+
name: this.file.name,
|
|
95
|
+
elementHeight: rect.height,
|
|
96
|
+
computedHeight: this.height
|
|
97
|
+
});
|
|
98
|
+
else console.log("VirtualizedFile.computeApproximateSize: computed height IS CORRECT");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
setVisibility(visible) {
|
|
102
|
+
if (this.fileContainer == null) return;
|
|
103
|
+
if (visible && !this.isVisible) {
|
|
104
|
+
this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);
|
|
105
|
+
this.isVisible = true;
|
|
106
|
+
} else if (!visible && this.isVisible) {
|
|
107
|
+
this.isVisible = false;
|
|
108
|
+
this.rerender();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
render({ fileContainer, file,...props }) {
|
|
112
|
+
const isFirstRender = this.fileContainer == null;
|
|
113
|
+
this.file ??= file;
|
|
114
|
+
fileContainer = this.getOrCreateFileContainerNode(fileContainer);
|
|
115
|
+
if (this.file == null) {
|
|
116
|
+
console.error("VirtualizedFile.render: attempting to virtually render when we dont have file");
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);
|
|
120
|
+
if (isFirstRender) {
|
|
121
|
+
this.computeApproximateSize();
|
|
122
|
+
this.virtualizer.connect(fileContainer, this);
|
|
123
|
+
this.isVisible = this.virtualizer.isInstanceVisible(this.top, this.height);
|
|
124
|
+
}
|
|
125
|
+
if (!this.isVisible) return this.renderPlaceholder(this.height);
|
|
126
|
+
const windowSpecs = this.virtualizer.getWindowSpecs();
|
|
127
|
+
const renderRange = this.computeRenderRangeFromWindow(this.file, this.top, windowSpecs);
|
|
128
|
+
return super.render({
|
|
129
|
+
file: this.file,
|
|
130
|
+
fileContainer,
|
|
131
|
+
renderRange,
|
|
132
|
+
...props
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
computeRenderRangeFromWindow(file, fileTop, { top, bottom }) {
|
|
136
|
+
const { disableFileHeader = false, overflow = "scroll" } = this.options;
|
|
137
|
+
const { diffHeaderHeight, fileGap, hunkLineCount, lineHeight } = this.metrics;
|
|
138
|
+
const lines = this.getOrCreateLineCache(file);
|
|
139
|
+
const lineCount = lines.length;
|
|
140
|
+
const fileHeight = this.height;
|
|
141
|
+
const headerRegion = disableFileHeader ? fileGap : diffHeaderHeight;
|
|
142
|
+
if (fileTop < top - fileHeight || fileTop > bottom) return {
|
|
143
|
+
startingLine: 0,
|
|
144
|
+
totalLines: 0,
|
|
145
|
+
bufferBefore: 0,
|
|
146
|
+
bufferAfter: fileHeight - headerRegion - fileGap
|
|
147
|
+
};
|
|
148
|
+
if (lineCount <= hunkLineCount) return {
|
|
149
|
+
startingLine: 0,
|
|
150
|
+
totalLines: hunkLineCount,
|
|
151
|
+
bufferBefore: 0,
|
|
152
|
+
bufferAfter: 0
|
|
153
|
+
};
|
|
154
|
+
const estimatedTargetLines = Math.ceil(Math.max(bottom - top, 0) / lineHeight);
|
|
155
|
+
const totalLines = Math.ceil(estimatedTargetLines / hunkLineCount) * hunkLineCount + hunkLineCount * 2;
|
|
156
|
+
const totalHunks = totalLines / hunkLineCount;
|
|
157
|
+
const viewportCenter = (top + bottom) / 2;
|
|
158
|
+
if (overflow === "scroll" && this.lineAnnotations.length === 0) {
|
|
159
|
+
const centerLine = Math.floor((viewportCenter - (fileTop + headerRegion)) / lineHeight);
|
|
160
|
+
const idealStartHunk$1 = Math.floor(centerLine / hunkLineCount) - Math.floor(totalHunks / 2);
|
|
161
|
+
const totalHunksInFile = Math.ceil(lineCount / hunkLineCount);
|
|
162
|
+
const startingLine$1 = Math.max(0, Math.min(idealStartHunk$1, totalHunksInFile)) * hunkLineCount;
|
|
163
|
+
const clampedTotalLines$1 = idealStartHunk$1 < 0 ? totalLines + idealStartHunk$1 * hunkLineCount : totalLines;
|
|
164
|
+
const bufferBefore$1 = startingLine$1 * lineHeight;
|
|
165
|
+
const renderedLines = Math.min(clampedTotalLines$1, lineCount - startingLine$1);
|
|
166
|
+
return {
|
|
167
|
+
startingLine: startingLine$1,
|
|
168
|
+
totalLines: clampedTotalLines$1,
|
|
169
|
+
bufferBefore: bufferBefore$1,
|
|
170
|
+
bufferAfter: Math.max(0, (lineCount - startingLine$1 - renderedLines) * lineHeight)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const overflowHunks = totalHunks;
|
|
174
|
+
const hunkOffsets = [];
|
|
175
|
+
let absoluteLineTop = fileTop + headerRegion;
|
|
176
|
+
let currentLine = 0;
|
|
177
|
+
let firstVisibleHunk;
|
|
178
|
+
let centerHunk;
|
|
179
|
+
let overflowCounter;
|
|
180
|
+
iterateOverFile({
|
|
181
|
+
lines,
|
|
182
|
+
callback: ({ lineIndex }) => {
|
|
183
|
+
const isAtHunkBoundary = currentLine % hunkLineCount === 0;
|
|
184
|
+
if (isAtHunkBoundary) {
|
|
185
|
+
hunkOffsets.push(absoluteLineTop - (fileTop + headerRegion));
|
|
186
|
+
if (overflowCounter != null) {
|
|
187
|
+
if (overflowCounter <= 0) return true;
|
|
188
|
+
overflowCounter--;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const lineHeight$1 = this.getLineHeight(lineIndex, false);
|
|
192
|
+
const currentHunk = Math.floor(currentLine / hunkLineCount);
|
|
193
|
+
if (absoluteLineTop > top - lineHeight$1 && absoluteLineTop < bottom) firstVisibleHunk ??= currentHunk;
|
|
194
|
+
if (absoluteLineTop + lineHeight$1 > viewportCenter) centerHunk ??= currentHunk;
|
|
195
|
+
if (overflowCounter == null && absoluteLineTop >= bottom && isAtHunkBoundary) overflowCounter = overflowHunks;
|
|
196
|
+
currentLine++;
|
|
197
|
+
absoluteLineTop += lineHeight$1;
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
if (firstVisibleHunk == null) return {
|
|
202
|
+
startingLine: 0,
|
|
203
|
+
totalLines: 0,
|
|
204
|
+
bufferBefore: 0,
|
|
205
|
+
bufferAfter: fileHeight - headerRegion - fileGap
|
|
206
|
+
};
|
|
207
|
+
const collectedHunks = hunkOffsets.length;
|
|
208
|
+
centerHunk ??= firstVisibleHunk;
|
|
209
|
+
const idealStartHunk = Math.round(centerHunk - totalHunks / 2);
|
|
210
|
+
const maxStartHunk = Math.max(0, collectedHunks - totalHunks);
|
|
211
|
+
const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));
|
|
212
|
+
const startingLine = startHunk * hunkLineCount;
|
|
213
|
+
const clampedTotalLines = idealStartHunk < 0 ? totalLines + idealStartHunk * hunkLineCount : totalLines;
|
|
214
|
+
const bufferBefore = hunkOffsets[startHunk] ?? 0;
|
|
215
|
+
const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;
|
|
216
|
+
return {
|
|
217
|
+
startingLine,
|
|
218
|
+
totalLines: clampedTotalLines,
|
|
219
|
+
bufferBefore,
|
|
220
|
+
bufferAfter: finalHunkIndex < hunkOffsets.length ? fileHeight - headerRegion - hunkOffsets[finalHunkIndex] - fileGap : fileHeight - (absoluteLineTop - fileTop) - fileGap
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
export { VirtualizedFile };
|
|
227
|
+
//# sourceMappingURL=VirtualizedFile.js.map
|
|
@@ -0,0 +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 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 (this.fileContainer != null && this.virtualizer.config.resizeDebugging) {\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 this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);\n if (isFirstRender) {\n this.computeApproximateSize();\n this.virtualizer.connect(fileContainer, this);\n this.isVisible = this.virtualizer.isInstanceVisible(\n this.top,\n this.height\n );\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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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ExpansionDirections, VirtualFileMetrics } from "../types.js";
|
|
2
|
+
import { WorkerPoolManager } from "../worker/WorkerPoolManager.js";
|
|
3
|
+
import "../worker/index.js";
|
|
4
|
+
import { Virtualizer } from "./Virtualizer.js";
|
|
5
|
+
import { FileDiff, FileDiffOptions, FileDiffRenderProps } from "./FileDiff.js";
|
|
6
|
+
|
|
7
|
+
//#region src/components/VirtualizedFileDiff.d.ts
|
|
8
|
+
declare class VirtualizedFileDiff<LAnnotation = undefined> extends FileDiff<LAnnotation> {
|
|
9
|
+
readonly __id: string;
|
|
10
|
+
top: number | undefined;
|
|
11
|
+
height: number;
|
|
12
|
+
private metrics;
|
|
13
|
+
private heightCache;
|
|
14
|
+
private isVisible;
|
|
15
|
+
private virtualizer;
|
|
16
|
+
constructor(options: FileDiffOptions<LAnnotation> | undefined, virtualizer: Virtualizer, metrics?: Partial<VirtualFileMetrics>, workerManager?: WorkerPoolManager, isContainerManaged?: boolean);
|
|
17
|
+
private getLineHeight;
|
|
18
|
+
setOptions(options: FileDiffOptions<LAnnotation> | undefined): void;
|
|
19
|
+
reconcileHeights(): void;
|
|
20
|
+
onRender: (dirty: boolean) => boolean;
|
|
21
|
+
cleanUp(): void;
|
|
22
|
+
expandHunk(hunkIndex: number, direction: ExpansionDirections): void;
|
|
23
|
+
setVisibility(visible: boolean): void;
|
|
24
|
+
private computeApproximateSize;
|
|
25
|
+
render({
|
|
26
|
+
fileContainer,
|
|
27
|
+
oldFile,
|
|
28
|
+
newFile,
|
|
29
|
+
fileDiff,
|
|
30
|
+
...props
|
|
31
|
+
}?: FileDiffRenderProps<LAnnotation>): boolean;
|
|
32
|
+
private getDiffStyle;
|
|
33
|
+
private getExpandedRegion;
|
|
34
|
+
private getExpandedLineCount;
|
|
35
|
+
private computeRenderRangeFromWindow;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { VirtualizedFileDiff };
|
|
39
|
+
//# sourceMappingURL=VirtualizedFileDiff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualizedFileDiff.d.ts","names":["ExpansionDirections","VirtualFileMetrics","WorkerPoolManager","FileDiff","FileDiffOptions","FileDiffRenderProps","Virtualizer","VirtualizedFileDiff","LAnnotation","Partial","fileContainer","oldFile","newFile","fileDiff"],"sources":["../../src/components/VirtualizedFileDiff.d.ts"],"sourcesContent":["import type { ExpansionDirections, VirtualFileMetrics } from '../types';\nimport type { WorkerPoolManager } from '../worker';\nimport { FileDiff, type FileDiffOptions, type FileDiffRenderProps } from './FileDiff';\nimport type { Virtualizer } from './Virtualizer';\nexport declare class VirtualizedFileDiff<LAnnotation = undefined> extends FileDiff<LAnnotation> {\n readonly __id: string;\n top: number | undefined;\n height: number;\n private metrics;\n private heightCache;\n private isVisible;\n private virtualizer;\n constructor(options: FileDiffOptions<LAnnotation> | undefined, virtualizer: Virtualizer, metrics?: Partial<VirtualFileMetrics>, workerManager?: WorkerPoolManager, isContainerManaged?: boolean);\n private getLineHeight;\n setOptions(options: FileDiffOptions<LAnnotation> | undefined): void;\n reconcileHeights(): void;\n onRender: (dirty: boolean) => boolean;\n cleanUp(): void;\n expandHunk(hunkIndex: number, direction: ExpansionDirections): void;\n setVisibility(visible: boolean): void;\n private computeApproximateSize;\n render({ fileContainer, oldFile, newFile, fileDiff, ...props }?: FileDiffRenderProps<LAnnotation>): boolean;\n private getDiffStyle;\n private getExpandedRegion;\n private getExpandedLineCount;\n private computeRenderRangeFromWindow;\n}\n//# sourceMappingURL=VirtualizedFileDiff.d.ts.map"],"mappings":";;;;;;;cAIqBO,qDAAqDJ,SAASK;;;EAA9DD,MAAAA,EAAAA,MAAAA;EAA8DC,QAAAA,OAAAA;EAQ1CA,QAAAA,WAAAA;EAAhBJ,QAAAA,SAAAA;EAAuDE,QAAAA,WAAAA;EAA+BL,WAAAA,CAAAA,OAAAA,EAAtFG,eAAsFH,CAAtEO,WAAsEP,CAAAA,GAAAA,SAAAA,EAAAA,WAAAA,EAA/BK,WAA+BL,EAAAA,OAAAA,CAAAA,EAARQ,OAAQR,CAAAA,kBAAAA,CAAAA,EAAAA,aAAAA,CAAAA,EAAqCC,iBAArCD,EAAAA,kBAAAA,CAAAA,EAAAA,OAAAA;EAARQ,QAAAA,aAAAA;EAA6CP,UAAAA,CAAAA,OAAAA,EAE5HE,eAF4HF,CAE5GM,WAF4GN,CAAAA,GAAAA,SAAAA,CAAAA,EAAAA,IAAAA;EAE5GM,gBAAAA,CAAAA,CAAAA,EAAAA,IAAAA;EAAhBJ,QAAAA,EAAAA,CAAAA,KAAAA,EAAAA,OAAAA,EAAAA,GAAAA,OAAAA;EAIqBJ,OAAAA,CAAAA,CAAAA,EAAAA,IAAAA;EAGhCU,UAAAA,CAAAA,SAAAA,EAAAA,MAAAA,EAAAA,SAAAA,EAHgCV,mBAGhCU,CAAAA,EAAAA,IAAAA;EAAeC,aAAAA,CAAAA,OAAAA,EAAAA,OAAAA,CAAAA,EAAAA,IAAAA;EAASC,QAAAA,sBAAAA;EAASC,MAAAA,CAAAA;IAAAA,aAAAA;IAAAA,OAAAA;IAAAA,OAAAA;IAAAA,QAAAA;IAAAA,GAAAA;EAAAA,CAAAA,CAAAA,EAAuBR,mBAAvBQ,CAA2CL,WAA3CK,CAAAA,CAAAA,EAAAA,OAAAA;EAA2CL,QAAAA,YAAAA;EAApBH,QAAAA,iBAAAA;EAjBKF,QAAAA,oBAAAA;EAAQ,QAAA,4BAAA"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } from "../constants.js";
|
|
2
|
+
import { iterateOverDiff } from "../utils/iterateOverDiff.js";
|
|
3
|
+
import { parseDiffFromFile } from "../utils/parseDiffFromFile.js";
|
|
4
|
+
import { FileDiff } from "./FileDiff.js";
|
|
5
|
+
import { resolveVirtualFileMetrics } from "../utils/resolveVirtualFileMetrics.js";
|
|
6
|
+
|
|
7
|
+
//#region src/components/VirtualizedFileDiff.ts
|
|
8
|
+
let instanceId = -1;
|
|
9
|
+
var VirtualizedFileDiff = class extends FileDiff {
|
|
10
|
+
__id = `little-virtualized-file-diff:${++instanceId}`;
|
|
11
|
+
top;
|
|
12
|
+
height = 0;
|
|
13
|
+
metrics;
|
|
14
|
+
heightCache = /* @__PURE__ */ new Map();
|
|
15
|
+
isVisible = false;
|
|
16
|
+
virtualizer;
|
|
17
|
+
constructor(options, virtualizer, metrics, workerManager, isContainerManaged = false) {
|
|
18
|
+
super(options, workerManager, isContainerManaged);
|
|
19
|
+
const { hunkSeparators = "line-info" } = this.options;
|
|
20
|
+
this.virtualizer = virtualizer;
|
|
21
|
+
this.metrics = resolveVirtualFileMetrics(typeof hunkSeparators === "function" ? "custom" : hunkSeparators, metrics);
|
|
22
|
+
}
|
|
23
|
+
getLineHeight(lineIndex, hasMetadataLine = false) {
|
|
24
|
+
const cached = this.heightCache.get(lineIndex);
|
|
25
|
+
if (cached != null) return cached;
|
|
26
|
+
const multiplier = hasMetadataLine ? 2 : 1;
|
|
27
|
+
return this.metrics.lineHeight * multiplier;
|
|
28
|
+
}
|
|
29
|
+
setOptions(options) {
|
|
30
|
+
if (options == null) return;
|
|
31
|
+
const previousDiffStyle = this.options.diffStyle;
|
|
32
|
+
const previousOverflow = this.options.overflow;
|
|
33
|
+
super.setOptions(options);
|
|
34
|
+
if (previousDiffStyle !== this.options.diffStyle || previousOverflow !== this.options.overflow) {
|
|
35
|
+
this.heightCache.clear();
|
|
36
|
+
this.computeApproximateSize();
|
|
37
|
+
this.renderRange = void 0;
|
|
38
|
+
}
|
|
39
|
+
this.virtualizer.instanceChanged(this);
|
|
40
|
+
}
|
|
41
|
+
reconcileHeights() {
|
|
42
|
+
const { overflow = "scroll" } = this.options;
|
|
43
|
+
if (this.fileContainer != null) this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);
|
|
44
|
+
if (this.fileContainer == null || this.fileDiff == null) {
|
|
45
|
+
this.height = 0;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (overflow === "scroll" && this.lineAnnotations.length === 0 && !this.virtualizer.config.resizeDebugging) return;
|
|
49
|
+
const diffStyle = this.getDiffStyle();
|
|
50
|
+
let hasLineHeightChange = false;
|
|
51
|
+
const codeGroups = diffStyle === "split" ? [this.codeDeletions, this.codeAdditions] : [this.codeUnified];
|
|
52
|
+
for (const codeGroup of codeGroups) {
|
|
53
|
+
if (codeGroup == null) continue;
|
|
54
|
+
const content = codeGroup.children[1];
|
|
55
|
+
if (!(content instanceof HTMLElement)) continue;
|
|
56
|
+
for (const line of content.children) {
|
|
57
|
+
if (!(line instanceof HTMLElement)) continue;
|
|
58
|
+
const lineIndexAttr = line.dataset.lineIndex;
|
|
59
|
+
if (lineIndexAttr == null) continue;
|
|
60
|
+
const lineIndex = parseLineIndex(lineIndexAttr, diffStyle);
|
|
61
|
+
let measuredHeight = line.getBoundingClientRect().height;
|
|
62
|
+
let hasMetadata = false;
|
|
63
|
+
if (line.nextElementSibling instanceof HTMLElement && ("lineAnnotation" in line.nextElementSibling.dataset || "noNewline" in line.nextElementSibling.dataset)) {
|
|
64
|
+
if ("noNewline" in line.nextElementSibling.dataset) hasMetadata = true;
|
|
65
|
+
measuredHeight += line.nextElementSibling.getBoundingClientRect().height;
|
|
66
|
+
}
|
|
67
|
+
const expectedHeight = this.getLineHeight(lineIndex, hasMetadata);
|
|
68
|
+
if (measuredHeight === expectedHeight) continue;
|
|
69
|
+
hasLineHeightChange = true;
|
|
70
|
+
if (measuredHeight === this.metrics.lineHeight * (hasMetadata ? 2 : 1)) this.heightCache.delete(lineIndex);
|
|
71
|
+
else this.heightCache.set(lineIndex, measuredHeight);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (hasLineHeightChange || this.virtualizer.config.resizeDebugging) this.computeApproximateSize();
|
|
75
|
+
}
|
|
76
|
+
onRender = (dirty) => {
|
|
77
|
+
if (this.fileContainer == null) return false;
|
|
78
|
+
if (dirty) this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);
|
|
79
|
+
return this.render();
|
|
80
|
+
};
|
|
81
|
+
cleanUp() {
|
|
82
|
+
if (this.fileContainer != null) this.virtualizer.disconnect(this.fileContainer);
|
|
83
|
+
super.cleanUp();
|
|
84
|
+
}
|
|
85
|
+
expandHunk(hunkIndex, direction) {
|
|
86
|
+
this.hunksRenderer.expandHunk(hunkIndex, direction);
|
|
87
|
+
this.computeApproximateSize();
|
|
88
|
+
this.renderRange = void 0;
|
|
89
|
+
this.virtualizer.instanceChanged(this);
|
|
90
|
+
}
|
|
91
|
+
setVisibility(visible) {
|
|
92
|
+
if (this.fileContainer == null) return;
|
|
93
|
+
if (visible && !this.isVisible) {
|
|
94
|
+
this.top = this.virtualizer.getOffsetInScrollContainer(this.fileContainer);
|
|
95
|
+
this.isVisible = true;
|
|
96
|
+
} else if (!visible && this.isVisible) {
|
|
97
|
+
this.isVisible = false;
|
|
98
|
+
this.rerender();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
computeApproximateSize() {
|
|
102
|
+
this.height = 0;
|
|
103
|
+
if (this.fileDiff == null) return;
|
|
104
|
+
const { disableFileHeader = false, expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
|
|
105
|
+
const { diffHeaderHeight, fileGap, hunkSeparatorHeight } = this.metrics;
|
|
106
|
+
const diffStyle = this.getDiffStyle();
|
|
107
|
+
const separatorGap = hunkSeparators === "simple" || hunkSeparators === "metadata" ? 0 : fileGap;
|
|
108
|
+
if (!disableFileHeader) this.height += diffHeaderHeight;
|
|
109
|
+
else if (hunkSeparators !== "simple" && hunkSeparators !== "metadata") this.height += fileGap;
|
|
110
|
+
iterateOverDiff({
|
|
111
|
+
diff: this.fileDiff,
|
|
112
|
+
diffStyle,
|
|
113
|
+
expandedHunks: expandUnchanged ? true : this.hunksRenderer.getExpandedHunksMap(),
|
|
114
|
+
collapsedContextThreshold,
|
|
115
|
+
callback: ({ hunkIndex, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
|
|
116
|
+
const splitLineIndex = additionLine != null ? additionLine.splitLineIndex : deletionLine.splitLineIndex;
|
|
117
|
+
const unifiedLineIndex = additionLine != null ? additionLine.unifiedLineIndex : deletionLine.unifiedLineIndex;
|
|
118
|
+
const hasMetadata = (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);
|
|
119
|
+
if (collapsedBefore > 0) {
|
|
120
|
+
if (hunkIndex > 0) this.height += separatorGap;
|
|
121
|
+
this.height += hunkSeparatorHeight + separatorGap;
|
|
122
|
+
}
|
|
123
|
+
this.height += this.getLineHeight(diffStyle === "split" ? splitLineIndex : unifiedLineIndex, hasMetadata);
|
|
124
|
+
if (collapsedAfter > 0 && hunkSeparators !== "simple") this.height += separatorGap + hunkSeparatorHeight;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
if (this.fileDiff.hunks.length > 0) this.height += fileGap;
|
|
128
|
+
if (this.fileContainer != null && this.virtualizer.config.resizeDebugging) {
|
|
129
|
+
const rect = this.fileContainer.getBoundingClientRect();
|
|
130
|
+
if (rect.height !== this.height) console.log("VirtualizedFileDiff.computeApproximateSize: computed height doesnt match", {
|
|
131
|
+
name: this.fileDiff.name,
|
|
132
|
+
elementHeight: rect.height,
|
|
133
|
+
computedHeight: this.height
|
|
134
|
+
});
|
|
135
|
+
else console.log("VirtualizedFileDiff.computeApproximateSize: computed height IS CORRECT");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
render({ fileContainer, oldFile, newFile, fileDiff,...props } = {}) {
|
|
139
|
+
const isFirstRender = this.fileContainer == null;
|
|
140
|
+
this.fileDiff ??= fileDiff ?? (oldFile != null && newFile != null ? parseDiffFromFile(oldFile, newFile) : void 0);
|
|
141
|
+
fileContainer = this.getOrCreateFileContainer(fileContainer);
|
|
142
|
+
if (this.fileDiff == null) {
|
|
143
|
+
console.error("VirtualizedFileDiff.render: attempting to virtually render when we dont have the correct data");
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);
|
|
147
|
+
if (isFirstRender) {
|
|
148
|
+
this.computeApproximateSize();
|
|
149
|
+
this.virtualizer.connect(fileContainer, this);
|
|
150
|
+
this.isVisible = this.virtualizer.isInstanceVisible(this.top, this.height);
|
|
151
|
+
}
|
|
152
|
+
if (!this.isVisible) return this.renderPlaceholder(this.height);
|
|
153
|
+
const windowSpecs = this.virtualizer.getWindowSpecs();
|
|
154
|
+
const renderRange = this.computeRenderRangeFromWindow(this.fileDiff, this.top, windowSpecs);
|
|
155
|
+
return super.render({
|
|
156
|
+
fileDiff: this.fileDiff,
|
|
157
|
+
fileContainer,
|
|
158
|
+
renderRange,
|
|
159
|
+
oldFile,
|
|
160
|
+
newFile,
|
|
161
|
+
...props
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
getDiffStyle() {
|
|
165
|
+
return this.options.diffStyle ?? "split";
|
|
166
|
+
}
|
|
167
|
+
getExpandedRegion(isPartial, hunkIndex, rangeSize) {
|
|
168
|
+
if (rangeSize <= 0 || isPartial) return {
|
|
169
|
+
fromStart: 0,
|
|
170
|
+
fromEnd: 0,
|
|
171
|
+
collapsedLines: Math.max(rangeSize, 0),
|
|
172
|
+
renderAll: false
|
|
173
|
+
};
|
|
174
|
+
const { expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } = this.options;
|
|
175
|
+
if (expandUnchanged || rangeSize <= collapsedContextThreshold) return {
|
|
176
|
+
fromStart: rangeSize,
|
|
177
|
+
fromEnd: 0,
|
|
178
|
+
collapsedLines: 0,
|
|
179
|
+
renderAll: true
|
|
180
|
+
};
|
|
181
|
+
const region = this.hunksRenderer.getExpandedHunk(hunkIndex);
|
|
182
|
+
const fromStart = Math.min(Math.max(region.fromStart, 0), rangeSize);
|
|
183
|
+
const fromEnd = Math.min(Math.max(region.fromEnd, 0), rangeSize);
|
|
184
|
+
const expandedCount = fromStart + fromEnd;
|
|
185
|
+
const renderAll = expandedCount >= rangeSize;
|
|
186
|
+
return {
|
|
187
|
+
fromStart,
|
|
188
|
+
fromEnd,
|
|
189
|
+
collapsedLines: Math.max(rangeSize - expandedCount, 0),
|
|
190
|
+
renderAll
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
getExpandedLineCount(fileDiff, diffStyle) {
|
|
194
|
+
let count = 0;
|
|
195
|
+
if (fileDiff.isPartial) {
|
|
196
|
+
for (const hunk of fileDiff.hunks) count += diffStyle === "split" ? hunk.splitLineCount : hunk.unifiedLineCount;
|
|
197
|
+
return count;
|
|
198
|
+
}
|
|
199
|
+
for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {
|
|
200
|
+
const hunkCount = diffStyle === "split" ? hunk.splitLineCount : hunk.unifiedLineCount;
|
|
201
|
+
count += hunkCount;
|
|
202
|
+
const collapsedBefore = Math.max(hunk.collapsedBefore, 0);
|
|
203
|
+
const { fromStart, fromEnd, renderAll } = this.getExpandedRegion(fileDiff.isPartial, hunkIndex, collapsedBefore);
|
|
204
|
+
if (collapsedBefore > 0) count += renderAll ? collapsedBefore : fromStart + fromEnd;
|
|
205
|
+
}
|
|
206
|
+
const lastHunk = fileDiff.hunks.at(-1);
|
|
207
|
+
if (lastHunk != null && hasFinalHunk(fileDiff)) {
|
|
208
|
+
const additionRemaining = fileDiff.additionLines.length - (lastHunk.additionLineIndex + lastHunk.additionCount);
|
|
209
|
+
const deletionRemaining = fileDiff.deletionLines.length - (lastHunk.deletionLineIndex + lastHunk.deletionCount);
|
|
210
|
+
if (lastHunk != null && additionRemaining !== deletionRemaining) throw new Error(`VirtualizedFileDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`);
|
|
211
|
+
const trailingRangeSize = Math.min(additionRemaining, deletionRemaining);
|
|
212
|
+
if (lastHunk != null && trailingRangeSize > 0) {
|
|
213
|
+
const { fromStart, renderAll } = this.getExpandedRegion(fileDiff.isPartial, fileDiff.hunks.length, trailingRangeSize);
|
|
214
|
+
count += renderAll ? trailingRangeSize : fromStart;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return count;
|
|
218
|
+
}
|
|
219
|
+
computeRenderRangeFromWindow(fileDiff, fileTop, { top, bottom }) {
|
|
220
|
+
const { disableFileHeader = false, expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, hunkSeparators = "line-info" } = this.options;
|
|
221
|
+
const { diffHeaderHeight, fileGap, hunkLineCount, hunkSeparatorHeight, lineHeight } = this.metrics;
|
|
222
|
+
const diffStyle = this.getDiffStyle();
|
|
223
|
+
const fileHeight = this.height;
|
|
224
|
+
const lineCount = this.getExpandedLineCount(fileDiff, diffStyle);
|
|
225
|
+
const headerRegion = disableFileHeader ? fileGap : diffHeaderHeight;
|
|
226
|
+
if (fileTop < top - fileHeight || fileTop > bottom) return {
|
|
227
|
+
startingLine: 0,
|
|
228
|
+
totalLines: 0,
|
|
229
|
+
bufferBefore: 0,
|
|
230
|
+
bufferAfter: fileHeight - headerRegion - fileGap
|
|
231
|
+
};
|
|
232
|
+
if (lineCount <= hunkLineCount || fileDiff.hunks.length === 0) return {
|
|
233
|
+
startingLine: 0,
|
|
234
|
+
totalLines: hunkLineCount,
|
|
235
|
+
bufferBefore: 0,
|
|
236
|
+
bufferAfter: 0
|
|
237
|
+
};
|
|
238
|
+
const estimatedTargetLines = Math.ceil(Math.max(bottom - top, 0) / lineHeight);
|
|
239
|
+
const totalLines = Math.ceil(estimatedTargetLines / hunkLineCount) * hunkLineCount + hunkLineCount;
|
|
240
|
+
const totalHunks = totalLines / hunkLineCount;
|
|
241
|
+
const overflowHunks = totalHunks;
|
|
242
|
+
const hunkOffsets = [];
|
|
243
|
+
const viewportCenter = (top + bottom) / 2;
|
|
244
|
+
const separatorGap = hunkSeparators === "simple" || hunkSeparators === "metadata" ? 0 : fileGap;
|
|
245
|
+
let absoluteLineTop = fileTop + headerRegion;
|
|
246
|
+
let currentLine = 0;
|
|
247
|
+
let firstVisibleHunk;
|
|
248
|
+
let centerHunk;
|
|
249
|
+
let overflowCounter;
|
|
250
|
+
iterateOverDiff({
|
|
251
|
+
diff: fileDiff,
|
|
252
|
+
diffStyle,
|
|
253
|
+
expandedHunks: expandUnchanged ? true : this.hunksRenderer.getExpandedHunksMap(),
|
|
254
|
+
collapsedContextThreshold,
|
|
255
|
+
callback: ({ hunkIndex, collapsedBefore, collapsedAfter, deletionLine, additionLine }) => {
|
|
256
|
+
const splitLineIndex = additionLine != null ? additionLine.splitLineIndex : deletionLine.splitLineIndex;
|
|
257
|
+
const unifiedLineIndex = additionLine != null ? additionLine.unifiedLineIndex : deletionLine.unifiedLineIndex;
|
|
258
|
+
const hasMetadata = (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);
|
|
259
|
+
let gapAdjustment = collapsedBefore > 0 ? hunkSeparatorHeight + separatorGap + (hunkIndex > 0 ? separatorGap : 0) : 0;
|
|
260
|
+
if (hunkIndex === 0 && hunkSeparators === "simple") gapAdjustment = 0;
|
|
261
|
+
absoluteLineTop += gapAdjustment;
|
|
262
|
+
const isAtHunkBoundary = currentLine % hunkLineCount === 0;
|
|
263
|
+
if (isAtHunkBoundary) {
|
|
264
|
+
hunkOffsets.push(absoluteLineTop - (fileTop + headerRegion + gapAdjustment));
|
|
265
|
+
if (overflowCounter != null) {
|
|
266
|
+
if (overflowCounter <= 0) return true;
|
|
267
|
+
overflowCounter--;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const lineHeight$1 = this.getLineHeight(diffStyle === "split" ? splitLineIndex : unifiedLineIndex, hasMetadata);
|
|
271
|
+
const currentHunk = Math.floor(currentLine / hunkLineCount);
|
|
272
|
+
if (absoluteLineTop > top - lineHeight$1 && absoluteLineTop < bottom) firstVisibleHunk ??= currentHunk;
|
|
273
|
+
if (centerHunk == null && absoluteLineTop + lineHeight$1 > viewportCenter) centerHunk = currentHunk;
|
|
274
|
+
if (overflowCounter == null && absoluteLineTop >= bottom && isAtHunkBoundary) overflowCounter = overflowHunks;
|
|
275
|
+
currentLine++;
|
|
276
|
+
absoluteLineTop += lineHeight$1;
|
|
277
|
+
if (collapsedAfter > 0 && hunkSeparators !== "simple") absoluteLineTop += hunkSeparatorHeight + fileGap;
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
if (firstVisibleHunk == null) return {
|
|
282
|
+
startingLine: 0,
|
|
283
|
+
totalLines: 0,
|
|
284
|
+
bufferBefore: 0,
|
|
285
|
+
bufferAfter: fileHeight - headerRegion - fileGap
|
|
286
|
+
};
|
|
287
|
+
const collectedHunks = hunkOffsets.length;
|
|
288
|
+
centerHunk ??= firstVisibleHunk;
|
|
289
|
+
const idealStartHunk = Math.round(centerHunk - totalHunks / 2);
|
|
290
|
+
const maxStartHunk = Math.max(0, collectedHunks - totalHunks);
|
|
291
|
+
const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));
|
|
292
|
+
const startingLine = startHunk * hunkLineCount;
|
|
293
|
+
const clampedTotalLines = idealStartHunk < 0 ? totalLines + idealStartHunk * hunkLineCount : totalLines;
|
|
294
|
+
const bufferBefore = hunkOffsets[startHunk] ?? 0;
|
|
295
|
+
const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;
|
|
296
|
+
return {
|
|
297
|
+
startingLine,
|
|
298
|
+
totalLines: clampedTotalLines,
|
|
299
|
+
bufferBefore,
|
|
300
|
+
bufferAfter: finalHunkIndex < hunkOffsets.length ? fileHeight - headerRegion - hunkOffsets[finalHunkIndex] - fileGap : fileHeight - (absoluteLineTop - fileTop) - fileGap
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
function hasFinalHunk(fileDiff) {
|
|
305
|
+
const lastHunk = fileDiff.hunks.at(-1);
|
|
306
|
+
if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return false;
|
|
307
|
+
return lastHunk.additionLineIndex + lastHunk.additionCount < fileDiff.additionLines.length || lastHunk.deletionLineIndex + lastHunk.deletionCount < fileDiff.deletionLines.length;
|
|
308
|
+
}
|
|
309
|
+
function parseLineIndex(lineIndexAttr, diffStyle) {
|
|
310
|
+
const [unifiedIndex, splitIndex] = lineIndexAttr.split(",").map(Number);
|
|
311
|
+
return diffStyle === "split" ? splitIndex : unifiedIndex;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
//#endregion
|
|
315
|
+
export { VirtualizedFileDiff };
|
|
316
|
+
//# sourceMappingURL=VirtualizedFileDiff.js.map
|