@pierre/diffs 1.3.0-beta.9 → 1.3.0-rc.1
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/CodeView.d.ts +12 -12
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +49 -42
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +7 -2
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +36 -8
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +34 -6
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +198 -17
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +2 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +9 -5
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +14 -0
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +61 -3
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +14 -2
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +27 -2
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/edit/index.d.ts +5 -0
- package/dist/edit/index.js +3 -0
- package/dist/editor/command.d.ts +1 -1
- package/dist/editor/command.d.ts.map +1 -1
- package/dist/editor/command.js +11 -0
- package/dist/editor/command.js.map +1 -1
- package/dist/editor/editStack.d.ts +6 -2
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +53 -12
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +51 -23
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +978 -238
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +1 -1
- package/dist/editor/languages.d.ts +26 -0
- package/dist/editor/languages.d.ts.map +1 -0
- package/dist/editor/languages.js +363 -0
- package/dist/editor/languages.js.map +1 -0
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +25 -26
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +5 -3
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js +111 -91
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/matchBrackets.d.ts +3 -2
- package/dist/editor/matchBrackets.d.ts.map +1 -1
- package/dist/editor/matchBrackets.js +2 -10
- package/dist/editor/matchBrackets.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +2 -1
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +103 -39
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/platform.js +2 -0
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/popover.d.ts +25 -5
- package/dist/editor/popover.d.ts.map +1 -1
- package/dist/editor/popover.js +60 -14
- package/dist/editor/popover.js.map +1 -1
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +9 -2
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +31 -11
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +198 -70
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +4 -3
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js +9 -5
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/stateStorage.d.ts +15 -0
- package/dist/editor/stateStorage.d.ts.map +1 -0
- package/dist/editor/stateStorage.js +65 -0
- package/dist/editor/stateStorage.js.map +1 -0
- package/dist/editor/textDocument.d.ts +12 -77
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +76 -34
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.d.ts +7 -12
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +40 -32
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/{tokenzier.d.ts → tokenizer.d.ts} +3 -3
- package/dist/editor/tokenizer.d.ts.map +1 -0
- package/dist/editor/{tokenzier.js → tokenizer.js} +91 -26
- package/dist/editor/tokenizer.js.map +1 -0
- package/dist/editor/utils.js +1 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +6 -5
- package/dist/managers/InteractionManager.d.ts +18 -7
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +154 -99
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
- package/dist/managers/UniversalRenderingManager.js +1 -2
- package/dist/managers/UniversalRenderingManager.js.map +1 -1
- package/dist/react/CodeView.d.ts +13 -13
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +38 -29
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditContext.d.ts +20 -0
- package/dist/react/EditContext.d.ts.map +1 -0
- package/dist/react/EditContext.js +20 -0
- package/dist/react/EditContext.js.map +1 -0
- package/dist/react/File.d.ts +2 -1
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +3 -2
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +2 -2
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +3 -2
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +2 -2
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +3 -2
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +2 -2
- 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/UnresolvedFile.d.ts +1 -1
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +3 -3
- package/dist/react/types.d.ts +9 -1
- package/dist/react/types.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 +28 -27
- 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 +29 -25
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +3 -3
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +33 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +134 -21
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +2 -0
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +33 -11
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/ssr/FileDiffReact.js +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/preloadDiffs.js +1 -1
- package/dist/style.js +1 -1
- package/dist/types.d.ts +185 -42
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/annotationHelpers.d.ts +20 -0
- package/dist/utils/annotationHelpers.d.ts.map +1 -0
- package/dist/utils/annotationHelpers.js +29 -0
- package/dist/utils/annotationHelpers.js.map +1 -0
- package/dist/utils/computeFileOffsets.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.js +34 -5
- package/dist/utils/computeFileOffsets.js.map +1 -1
- package/dist/utils/editSessionHunks.d.ts +66 -0
- package/dist/utils/editSessionHunks.d.ts.map +1 -0
- package/dist/utils/editSessionHunks.js +437 -0
- package/dist/utils/editSessionHunks.js.map +1 -0
- package/dist/utils/getHunkSideBoundaries.d.ts +7 -0
- package/dist/utils/getHunkSideBoundaries.d.ts.map +1 -0
- package/dist/utils/getHunkSideBoundaries.js +12 -0
- package/dist/utils/getHunkSideBoundaries.js.map +1 -0
- package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js +2 -1
- package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
- package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
- package/dist/utils/hydratePartialDiff.js +4 -3
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/isGutterUtilityPath.d.ts +5 -0
- package/dist/utils/isGutterUtilityPath.d.ts.map +1 -0
- package/dist/utils/isGutterUtilityPath.js +12 -0
- package/dist/utils/isGutterUtilityPath.js.map +1 -0
- package/dist/utils/iterateOverDiff.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.js +17 -12
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +9 -6
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +6 -3
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/realignChangeContent.d.ts +33 -0
- package/dist/utils/realignChangeContent.d.ts.map +1 -0
- package/dist/utils/realignChangeContent.js +148 -0
- package/dist/utils/realignChangeContent.js.map +1 -0
- package/dist/utils/renderDiffWithHighlighter.js +1 -1
- package/dist/utils/resolveRegion.d.ts.map +1 -1
- package/dist/utils/resolveRegion.js +18 -2
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +8 -2
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +9 -7
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts +42 -2
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +101 -7
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/worker-portable.js +60 -20
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +61 -19
- package/dist/worker/worker.js.map +1 -1
- package/package.json +10 -7
- package/dist/editor/index.d.ts +0 -3
- package/dist/editor/index.js +0 -3
- package/dist/editor/tokenzier.d.ts.map +0 -1
- package/dist/editor/tokenzier.js.map +0 -1
- package/dist/react/EditorContext.d.ts +0 -15
- package/dist/react/EditorContext.d.ts.map +0 -1
- package/dist/react/EditorContext.js +0 -23
- package/dist/react/EditorContext.js.map +0 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { getHunkSideEndBoundary, getHunkSideStartBoundary } from "./getHunkSideBoundaries.js";
|
|
1
2
|
import { getDefaultHunkSeparatorHeight } from "./computeVirtualFileMetrics.js";
|
|
2
3
|
//#region src/utils/virtualDiffLayout.ts
|
|
4
|
+
/** One-based new-file line range covered by a hunk, as `[start, end)`. */
|
|
5
|
+
function getHunkAdditionLineRange(hunk) {
|
|
6
|
+
return [getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount) + 1, getHunkSideEndBoundary(hunk.additionStart, hunk.additionCount) + 1];
|
|
7
|
+
}
|
|
3
8
|
function getExpandedRegion({ isPartial, rangeSize, expandedHunks, hunkIndex, collapsedContextThreshold }) {
|
|
4
9
|
const normalizedRangeSize = Math.max(rangeSize, 0);
|
|
5
10
|
if (normalizedRangeSize === 0 || isPartial) return {
|
|
@@ -32,23 +37,23 @@ function getExpandedRegion({ isPartial, rangeSize, expandedHunks, hunkIndex, col
|
|
|
32
37
|
function hasTrailingContext(fileDiff) {
|
|
33
38
|
const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];
|
|
34
39
|
if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return false;
|
|
35
|
-
const additionRemaining = fileDiff.additionLines.length - (lastHunk.
|
|
36
|
-
const deletionRemaining = fileDiff.deletionLines.length - (lastHunk.
|
|
40
|
+
const additionRemaining = fileDiff.additionLines.length - getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);
|
|
41
|
+
const deletionRemaining = fileDiff.deletionLines.length - getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);
|
|
37
42
|
return additionRemaining > 0 || deletionRemaining > 0;
|
|
38
43
|
}
|
|
39
44
|
function hasTrailingContextMismatch(fileDiff) {
|
|
40
45
|
const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];
|
|
41
46
|
if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return false;
|
|
42
|
-
const additionRemaining = fileDiff.additionLines.length - (lastHunk.
|
|
43
|
-
const deletionRemaining = fileDiff.deletionLines.length - (lastHunk.
|
|
47
|
+
const additionRemaining = fileDiff.additionLines.length - getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);
|
|
48
|
+
const deletionRemaining = fileDiff.deletionLines.length - getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);
|
|
44
49
|
if (additionRemaining <= 0 && deletionRemaining <= 0) return false;
|
|
45
50
|
return additionRemaining !== deletionRemaining;
|
|
46
51
|
}
|
|
47
52
|
function getTrailingContextRangeSize({ fileDiff, errorPrefix }) {
|
|
48
53
|
const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];
|
|
49
54
|
if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return 0;
|
|
50
|
-
const additionRemaining = fileDiff.additionLines.length - (lastHunk.
|
|
51
|
-
const deletionRemaining = fileDiff.deletionLines.length - (lastHunk.
|
|
55
|
+
const additionRemaining = fileDiff.additionLines.length - getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);
|
|
56
|
+
const deletionRemaining = fileDiff.deletionLines.length - getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);
|
|
52
57
|
if (additionRemaining <= 0 && deletionRemaining <= 0) return 0;
|
|
53
58
|
if (additionRemaining !== deletionRemaining) throw new Error(`${errorPrefix}: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`);
|
|
54
59
|
return Math.min(additionRemaining, deletionRemaining);
|
|
@@ -77,6 +82,95 @@ function getTrailingExpandedRegion({ fileDiff, hunkIndex, expandedHunks, collaps
|
|
|
77
82
|
renderAll: fromStart >= trailingRangeSize
|
|
78
83
|
};
|
|
79
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether a one-based new-file line currently has (or will have on scroll) a
|
|
87
|
+
* rendered row under the given expansion state — the editor-facing
|
|
88
|
+
* visibility oracle. False only for lines hidden inside a collapsed
|
|
89
|
+
* unchanged region; lines outside the diff's modeled range report true so
|
|
90
|
+
* callers keep their existing missing-row handling. Computed from the same
|
|
91
|
+
* inputs as `iterateOverDiff` so layout math and the oracle cannot diverge.
|
|
92
|
+
*/
|
|
93
|
+
function isAdditionLineRenderable({ fileDiff, lineNumber, expandedHunks, collapsedContextThreshold }) {
|
|
94
|
+
if (expandedHunks === true || fileDiff.isPartial) return true;
|
|
95
|
+
for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {
|
|
96
|
+
const [hunkStart, hunkEnd] = getHunkAdditionLineRange(hunk);
|
|
97
|
+
if (lineNumber < hunkStart) {
|
|
98
|
+
const region = getExpandedRegion({
|
|
99
|
+
isPartial: fileDiff.isPartial,
|
|
100
|
+
rangeSize: hunk.collapsedBefore,
|
|
101
|
+
expandedHunks,
|
|
102
|
+
hunkIndex,
|
|
103
|
+
collapsedContextThreshold
|
|
104
|
+
});
|
|
105
|
+
const gapStart = hunkStart - region.rangeSize;
|
|
106
|
+
return region.renderAll || lineNumber < gapStart + region.fromStart || lineNumber >= hunkStart - region.fromEnd;
|
|
107
|
+
}
|
|
108
|
+
if (lineNumber < hunkEnd) return true;
|
|
109
|
+
}
|
|
110
|
+
const trailingRegion = getTrailingExpandedRegion({
|
|
111
|
+
fileDiff,
|
|
112
|
+
hunkIndex: fileDiff.hunks.length - 1,
|
|
113
|
+
expandedHunks,
|
|
114
|
+
collapsedContextThreshold,
|
|
115
|
+
errorPrefix: "isAdditionLineRenderable"
|
|
116
|
+
});
|
|
117
|
+
if (trailingRegion == null || trailingRegion.renderAll) return true;
|
|
118
|
+
const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];
|
|
119
|
+
const [, trailingStart] = getHunkAdditionLineRange(lastHunk);
|
|
120
|
+
return lineNumber < trailingStart + trailingRegion.fromStart || lineNumber >= trailingStart + trailingRegion.rangeSize;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The nearest renderable new-file line at or beyond `lineNumber` in the
|
|
124
|
+
* given direction (one-based), or undefined when every line that way is
|
|
125
|
+
* hidden inside collapsed regions. Sequential caret motion uses this to skip
|
|
126
|
+
* over collapsed regions like code folds; it walks the hunk metadata once
|
|
127
|
+
* instead of probing line by line across a gap.
|
|
128
|
+
*/
|
|
129
|
+
function getNearestRenderableAdditionLine({ fileDiff, lineNumber, direction, expandedHunks, collapsedContextThreshold }) {
|
|
130
|
+
if (expandedHunks === true || fileDiff.isPartial) return lineNumber;
|
|
131
|
+
const ranges = [];
|
|
132
|
+
let modeledEnd = 1;
|
|
133
|
+
for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {
|
|
134
|
+
const [hunkStart, hunkEnd] = getHunkAdditionLineRange(hunk);
|
|
135
|
+
const region = getExpandedRegion({
|
|
136
|
+
isPartial: fileDiff.isPartial,
|
|
137
|
+
rangeSize: hunk.collapsedBefore,
|
|
138
|
+
expandedHunks,
|
|
139
|
+
hunkIndex,
|
|
140
|
+
collapsedContextThreshold
|
|
141
|
+
});
|
|
142
|
+
const gapStart = hunkStart - region.rangeSize;
|
|
143
|
+
if (region.renderAll) ranges.push([gapStart, hunkStart]);
|
|
144
|
+
else {
|
|
145
|
+
if (region.fromStart > 0) ranges.push([gapStart, gapStart + region.fromStart]);
|
|
146
|
+
if (region.fromEnd > 0) ranges.push([hunkStart - region.fromEnd, hunkStart]);
|
|
147
|
+
}
|
|
148
|
+
ranges.push([hunkStart, hunkEnd]);
|
|
149
|
+
modeledEnd = hunkEnd;
|
|
150
|
+
}
|
|
151
|
+
const trailingRegion = getTrailingExpandedRegion({
|
|
152
|
+
fileDiff,
|
|
153
|
+
hunkIndex: fileDiff.hunks.length - 1,
|
|
154
|
+
expandedHunks,
|
|
155
|
+
collapsedContextThreshold,
|
|
156
|
+
errorPrefix: "getNearestRenderableAdditionLine"
|
|
157
|
+
});
|
|
158
|
+
if (trailingRegion != null) {
|
|
159
|
+
const trailingStart = modeledEnd;
|
|
160
|
+
modeledEnd = trailingStart + trailingRegion.rangeSize;
|
|
161
|
+
if (trailingRegion.renderAll) ranges.push([trailingStart, modeledEnd]);
|
|
162
|
+
else if (trailingRegion.fromStart > 0) ranges.push([trailingStart, trailingStart + trailingRegion.fromStart]);
|
|
163
|
+
}
|
|
164
|
+
if (lineNumber >= modeledEnd) return lineNumber;
|
|
165
|
+
if (direction === "down") {
|
|
166
|
+
for (const [start, end] of ranges) if (end > lineNumber) return Math.max(start, lineNumber);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
for (let index = ranges.length - 1; index >= 0; index--) {
|
|
170
|
+
const [start, end] = ranges[index];
|
|
171
|
+
if (start <= lineNumber) return Math.min(end - 1, lineNumber);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
80
174
|
function getHunkSeparatorHeight({ type, metrics }) {
|
|
81
175
|
return metrics.hunkSeparatorHeight ?? getDefaultHunkSeparatorHeight(type);
|
|
82
176
|
}
|
|
@@ -136,6 +230,6 @@ function getTrailingHunkSeparatorLayout({ type, metrics }) {
|
|
|
136
230
|
};
|
|
137
231
|
}
|
|
138
232
|
//#endregion
|
|
139
|
-
export { getExpandedRegion, getHunkSeparatorGap, getHunkSeparatorHeight, getLeadingHunkSeparatorLayout, getTrailingContextRangeSize, getTrailingExpandedRegion, getTrailingHunkSeparatorLayout, hasLeadingHunkSeparator, hasTrailingContext, hasTrailingContextMismatch, hasTrailingHunkSeparator };
|
|
233
|
+
export { getExpandedRegion, getHunkAdditionLineRange, getHunkSeparatorGap, getHunkSeparatorHeight, getLeadingHunkSeparatorLayout, getNearestRenderableAdditionLine, getTrailingContextRangeSize, getTrailingExpandedRegion, getTrailingHunkSeparatorLayout, hasLeadingHunkSeparator, hasTrailingContext, hasTrailingContextMismatch, hasTrailingHunkSeparator, isAdditionLineRenderable };
|
|
140
234
|
|
|
141
235
|
//# sourceMappingURL=virtualDiffLayout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtualDiffLayout.js","names":[],"sources":["../../src/utils/virtualDiffLayout.ts"],"sourcesContent":["import type {\n FileDiffMetadata,\n HunkExpansionRegion,\n HunkSeparators,\n VirtualFileMetrics,\n} from '../types';\nimport { getDefaultHunkSeparatorHeight } from './computeVirtualFileMetrics';\n\nexport interface ExpandedRegionResult {\n fromStart: number;\n fromEnd: number;\n rangeSize: number;\n collapsedLines: number;\n renderAll: boolean;\n}\n\nexport interface GetExpandedRegionProps {\n isPartial: boolean;\n rangeSize: number;\n expandedHunks: Map<number, HunkExpansionRegion> | true | undefined;\n hunkIndex: number;\n collapsedContextThreshold: number;\n}\n\nexport interface GetTrailingContextRangeSizeProps {\n fileDiff: FileDiffMetadata;\n errorPrefix: string;\n}\n\nexport interface GetTrailingExpandedRegionProps extends GetTrailingContextRangeSizeProps {\n hunkIndex: number;\n expandedHunks: GetExpandedRegionProps['expandedHunks'];\n collapsedContextThreshold: number;\n}\n\nexport interface HunkSeparatorLayout {\n height: number;\n gapBefore: number;\n gapAfter: number;\n totalHeight: number;\n}\n\ninterface HunkSeparatorBaseProps {\n type: HunkSeparators;\n metrics: VirtualFileMetrics;\n}\n\ninterface LeadingHunkSeparatorLayoutProps extends HunkSeparatorBaseProps {\n hunkIndex: number;\n hunkSpecs: string | undefined;\n}\n\n// Converts a collapsed unchanged range into the slices that should render near\n// the start and end of that range for the active hunk expansion state.\nexport function getExpandedRegion({\n isPartial,\n rangeSize,\n expandedHunks,\n hunkIndex,\n collapsedContextThreshold,\n}: GetExpandedRegionProps): ExpandedRegionResult {\n const normalizedRangeSize = Math.max(rangeSize, 0);\n if (normalizedRangeSize === 0 || isPartial) {\n return {\n fromStart: 0,\n fromEnd: 0,\n rangeSize: normalizedRangeSize,\n collapsedLines: normalizedRangeSize,\n renderAll: false,\n };\n }\n\n if (\n expandedHunks === true ||\n normalizedRangeSize <= collapsedContextThreshold\n ) {\n return {\n fromStart: normalizedRangeSize,\n fromEnd: 0,\n rangeSize: normalizedRangeSize,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n\n const region = expandedHunks?.get(hunkIndex);\n const fromStart = Math.min(\n Math.max(region?.fromStart ?? 0, 0),\n normalizedRangeSize\n );\n const fromEnd = Math.min(\n Math.max(region?.fromEnd ?? 0, 0),\n normalizedRangeSize\n );\n const expandedCount = fromStart + fromEnd;\n const renderAll = expandedCount >= normalizedRangeSize;\n return {\n fromStart: renderAll ? normalizedRangeSize : fromStart,\n fromEnd: renderAll ? 0 : fromEnd,\n rangeSize: normalizedRangeSize,\n collapsedLines: Math.max(normalizedRangeSize - expandedCount, 0),\n renderAll,\n };\n}\n\nexport function hasTrailingContext(fileDiff: FileDiffMetadata): boolean {\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n const additionRemaining =\n fileDiff.additionLines.length -\n (lastHunk.additionLineIndex + lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n (lastHunk.deletionLineIndex + lastHunk.deletionCount);\n\n return additionRemaining > 0 || deletionRemaining > 0;\n}\n\n// Returns true when trailing-context line counts disagree between sides.\nexport function hasTrailingContextMismatch(\n fileDiff: FileDiffMetadata\n): boolean {\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n const additionRemaining =\n fileDiff.additionLines.length -\n (lastHunk.additionLineIndex + lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n (lastHunk.deletionLineIndex + lastHunk.deletionCount);\n\n if (additionRemaining <= 0 && deletionRemaining <= 0) {\n return false;\n }\n\n return additionRemaining !== deletionRemaining;\n}\n\n// Measures the unchanged tail after the final hunk. Both sides must have the\n// same remaining length because trailing context represents paired lines.\nexport function getTrailingContextRangeSize({\n fileDiff,\n errorPrefix,\n}: GetTrailingContextRangeSizeProps): number {\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return 0;\n }\n\n const additionRemaining =\n fileDiff.additionLines.length -\n (lastHunk.additionLineIndex + lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n (lastHunk.deletionLineIndex + lastHunk.deletionCount);\n\n if (additionRemaining <= 0 && deletionRemaining <= 0) {\n return 0;\n }\n\n if (additionRemaining !== deletionRemaining) {\n throw new Error(\n `${errorPrefix}: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`\n );\n }\n return Math.min(additionRemaining, deletionRemaining);\n}\n\nexport function getTrailingExpandedRegion({\n fileDiff,\n hunkIndex,\n expandedHunks,\n collapsedContextThreshold,\n errorPrefix,\n}: GetTrailingExpandedRegionProps): ExpandedRegionResult | undefined {\n if (hunkIndex !== fileDiff.hunks.length - 1) {\n return undefined;\n }\n\n const trailingRangeSize = getTrailingContextRangeSize({\n fileDiff,\n errorPrefix,\n });\n if (trailingRangeSize <= 0) {\n return undefined;\n }\n\n if (\n expandedHunks === true ||\n trailingRangeSize <= collapsedContextThreshold\n ) {\n return {\n fromStart: trailingRangeSize,\n fromEnd: 0,\n rangeSize: trailingRangeSize,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n\n // The final trailing separator only exposes upward partial expansion. Treat it\n // as a bottom-only pseudo-hunk and ignore unsupported downward expansion.\n const region = expandedHunks?.get(fileDiff.hunks.length);\n const fromStart = Math.min(\n Math.max(region?.fromStart ?? 0, 0),\n trailingRangeSize\n );\n return {\n fromStart,\n fromEnd: 0,\n rangeSize: trailingRangeSize,\n collapsedLines: trailingRangeSize - fromStart,\n renderAll: fromStart >= trailingRangeSize,\n };\n}\n\nexport function getHunkSeparatorHeight({\n type,\n metrics,\n}: HunkSeparatorBaseProps): number {\n return metrics.hunkSeparatorHeight ?? getDefaultHunkSeparatorHeight(type);\n}\n\nexport function getHunkSeparatorGap({\n type,\n metrics,\n}: HunkSeparatorBaseProps): number {\n return type === 'simple' || type === 'metadata' || type === 'line-info-basic'\n ? 0\n : metrics.spacing;\n}\n\nexport function hasLeadingHunkSeparator({\n type,\n hunkIndex,\n hunkSpecs,\n}: Omit<LeadingHunkSeparatorLayoutProps, 'metrics'>): boolean {\n switch (type) {\n case 'simple':\n return hunkIndex > 0;\n case 'metadata':\n return hunkSpecs != null;\n case 'line-info':\n case 'line-info-basic':\n case 'custom':\n return true;\n }\n}\n\nexport function hasTrailingHunkSeparator(type: HunkSeparators): boolean {\n return type !== 'simple' && type !== 'metadata';\n}\n\n// Mirrors the renderer/CSS spacing rules for the separator shown before a hunk.\nexport function getLeadingHunkSeparatorLayout({\n type,\n metrics,\n hunkIndex,\n hunkSpecs,\n}: LeadingHunkSeparatorLayoutProps): HunkSeparatorLayout | undefined {\n if (!hasLeadingHunkSeparator({ type, hunkIndex, hunkSpecs })) {\n return undefined;\n }\n\n const height = getHunkSeparatorHeight({ type, metrics });\n const gap = getHunkSeparatorGap({ type, metrics });\n const gapBefore = hunkIndex > 0 ? gap : 0;\n const gapAfter = gap;\n return {\n height,\n gapBefore,\n gapAfter,\n totalHeight: gapBefore + height + gapAfter,\n };\n}\n\n// Mirrors the renderer/CSS spacing rules for the separator shown after the last\n// hunk when trailing unchanged context is collapsed.\nexport function getTrailingHunkSeparatorLayout({\n type,\n metrics,\n}: HunkSeparatorBaseProps): HunkSeparatorLayout | undefined {\n if (!hasTrailingHunkSeparator(type)) {\n return undefined;\n }\n\n const height = getHunkSeparatorHeight({ type, metrics });\n const gapBefore = getHunkSeparatorGap({ type, metrics });\n return {\n height,\n gapBefore,\n gapAfter: 0,\n totalHeight: gapBefore + height,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"virtualDiffLayout.js","names":[],"sources":["../../src/utils/virtualDiffLayout.ts"],"sourcesContent":["import type {\n FileDiffMetadata,\n Hunk,\n HunkExpansionRegion,\n HunkSeparators,\n VirtualFileMetrics,\n} from '../types';\nimport { getDefaultHunkSeparatorHeight } from './computeVirtualFileMetrics';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\n\nexport interface ExpandedRegionResult {\n fromStart: number;\n fromEnd: number;\n rangeSize: number;\n collapsedLines: number;\n renderAll: boolean;\n}\n\nexport interface GetExpandedRegionProps {\n isPartial: boolean;\n rangeSize: number;\n expandedHunks: Map<number, HunkExpansionRegion> | true | undefined;\n hunkIndex: number;\n collapsedContextThreshold: number;\n}\n\nexport interface GetTrailingContextRangeSizeProps {\n fileDiff: FileDiffMetadata;\n errorPrefix: string;\n}\n\nexport interface GetTrailingExpandedRegionProps extends GetTrailingContextRangeSizeProps {\n hunkIndex: number;\n expandedHunks: GetExpandedRegionProps['expandedHunks'];\n collapsedContextThreshold: number;\n}\n\n/** One-based new-file line range covered by a hunk, as `[start, end)`. */\nexport function getHunkAdditionLineRange(hunk: Hunk): [number, number] {\n return [\n getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount) + 1,\n getHunkSideEndBoundary(hunk.additionStart, hunk.additionCount) + 1,\n ];\n}\n\nexport interface HunkSeparatorLayout {\n height: number;\n gapBefore: number;\n gapAfter: number;\n totalHeight: number;\n}\n\ninterface HunkSeparatorBaseProps {\n type: HunkSeparators;\n metrics: VirtualFileMetrics;\n}\n\ninterface LeadingHunkSeparatorLayoutProps extends HunkSeparatorBaseProps {\n hunkIndex: number;\n hunkSpecs: string | undefined;\n}\n\n// Converts a collapsed unchanged range into the slices that should render near\n// the start and end of that range for the active hunk expansion state.\nexport function getExpandedRegion({\n isPartial,\n rangeSize,\n expandedHunks,\n hunkIndex,\n collapsedContextThreshold,\n}: GetExpandedRegionProps): ExpandedRegionResult {\n const normalizedRangeSize = Math.max(rangeSize, 0);\n if (normalizedRangeSize === 0 || isPartial) {\n return {\n fromStart: 0,\n fromEnd: 0,\n rangeSize: normalizedRangeSize,\n collapsedLines: normalizedRangeSize,\n renderAll: false,\n };\n }\n\n if (\n expandedHunks === true ||\n normalizedRangeSize <= collapsedContextThreshold\n ) {\n return {\n fromStart: normalizedRangeSize,\n fromEnd: 0,\n rangeSize: normalizedRangeSize,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n\n const region = expandedHunks?.get(hunkIndex);\n const fromStart = Math.min(\n Math.max(region?.fromStart ?? 0, 0),\n normalizedRangeSize\n );\n const fromEnd = Math.min(\n Math.max(region?.fromEnd ?? 0, 0),\n normalizedRangeSize\n );\n const expandedCount = fromStart + fromEnd;\n const renderAll = expandedCount >= normalizedRangeSize;\n return {\n fromStart: renderAll ? normalizedRangeSize : fromStart,\n fromEnd: renderAll ? 0 : fromEnd,\n rangeSize: normalizedRangeSize,\n collapsedLines: Math.max(normalizedRangeSize - expandedCount, 0),\n renderAll,\n };\n}\n\nexport function hasTrailingContext(fileDiff: FileDiffMetadata): boolean {\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n const additionRemaining =\n fileDiff.additionLines.length -\n getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);\n\n return additionRemaining > 0 || deletionRemaining > 0;\n}\n\n// Returns true when trailing-context line counts disagree between sides.\nexport function hasTrailingContextMismatch(\n fileDiff: FileDiffMetadata\n): boolean {\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n const additionRemaining =\n fileDiff.additionLines.length -\n getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);\n\n if (additionRemaining <= 0 && deletionRemaining <= 0) {\n return false;\n }\n\n return additionRemaining !== deletionRemaining;\n}\n\n// Measures the unchanged tail after the final hunk. Both sides must have the\n// same remaining length because trailing context represents paired lines.\nexport function getTrailingContextRangeSize({\n fileDiff,\n errorPrefix,\n}: GetTrailingContextRangeSizeProps): number {\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return 0;\n }\n\n const additionRemaining =\n fileDiff.additionLines.length -\n getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);\n\n if (additionRemaining <= 0 && deletionRemaining <= 0) {\n return 0;\n }\n\n if (additionRemaining !== deletionRemaining) {\n throw new Error(\n `${errorPrefix}: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`\n );\n }\n return Math.min(additionRemaining, deletionRemaining);\n}\n\nexport function getTrailingExpandedRegion({\n fileDiff,\n hunkIndex,\n expandedHunks,\n collapsedContextThreshold,\n errorPrefix,\n}: GetTrailingExpandedRegionProps): ExpandedRegionResult | undefined {\n if (hunkIndex !== fileDiff.hunks.length - 1) {\n return undefined;\n }\n\n const trailingRangeSize = getTrailingContextRangeSize({\n fileDiff,\n errorPrefix,\n });\n if (trailingRangeSize <= 0) {\n return undefined;\n }\n\n if (\n expandedHunks === true ||\n trailingRangeSize <= collapsedContextThreshold\n ) {\n return {\n fromStart: trailingRangeSize,\n fromEnd: 0,\n rangeSize: trailingRangeSize,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n\n // The final trailing separator only exposes upward partial expansion. Treat it\n // as a bottom-only pseudo-hunk and ignore unsupported downward expansion.\n const region = expandedHunks?.get(fileDiff.hunks.length);\n const fromStart = Math.min(\n Math.max(region?.fromStart ?? 0, 0),\n trailingRangeSize\n );\n return {\n fromStart,\n fromEnd: 0,\n rangeSize: trailingRangeSize,\n collapsedLines: trailingRangeSize - fromStart,\n renderAll: fromStart >= trailingRangeSize,\n };\n}\n\nexport interface IsAdditionLineRenderableProps {\n fileDiff: FileDiffMetadata;\n /** One-based line number in the new file. */\n lineNumber: number;\n expandedHunks: Map<number, HunkExpansionRegion> | true | undefined;\n collapsedContextThreshold: number;\n}\n\n/**\n * Whether a one-based new-file line currently has (or will have on scroll) a\n * rendered row under the given expansion state — the editor-facing\n * visibility oracle. False only for lines hidden inside a collapsed\n * unchanged region; lines outside the diff's modeled range report true so\n * callers keep their existing missing-row handling. Computed from the same\n * inputs as `iterateOverDiff` so layout math and the oracle cannot diverge.\n */\nexport function isAdditionLineRenderable({\n fileDiff,\n lineNumber,\n expandedHunks,\n collapsedContextThreshold,\n}: IsAdditionLineRenderableProps): boolean {\n if (expandedHunks === true || fileDiff.isPartial) {\n return true;\n }\n\n for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {\n const [hunkStart, hunkEnd] = getHunkAdditionLineRange(hunk);\n if (lineNumber < hunkStart) {\n // Inside the collapsed gap before this hunk: renderable only within\n // the expanded slices at the gap's edges.\n const region = getExpandedRegion({\n isPartial: fileDiff.isPartial,\n rangeSize: hunk.collapsedBefore,\n expandedHunks,\n hunkIndex,\n collapsedContextThreshold,\n });\n const gapStart = hunkStart - region.rangeSize;\n return (\n region.renderAll ||\n lineNumber < gapStart + region.fromStart ||\n lineNumber >= hunkStart - region.fromEnd\n );\n }\n if (lineNumber < hunkEnd) {\n return true;\n }\n }\n\n const trailingRegion = getTrailingExpandedRegion({\n fileDiff,\n hunkIndex: fileDiff.hunks.length - 1,\n expandedHunks,\n collapsedContextThreshold,\n errorPrefix: 'isAdditionLineRenderable',\n });\n if (trailingRegion == null || trailingRegion.renderAll) {\n return true;\n }\n const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];\n const [, trailingStart] = getHunkAdditionLineRange(lastHunk);\n return (\n lineNumber < trailingStart + trailingRegion.fromStart ||\n lineNumber >= trailingStart + trailingRegion.rangeSize\n );\n}\n\nexport interface GetNearestRenderableAdditionLineProps extends IsAdditionLineRenderableProps {\n direction: 'up' | 'down';\n}\n\n/**\n * The nearest renderable new-file line at or beyond `lineNumber` in the\n * given direction (one-based), or undefined when every line that way is\n * hidden inside collapsed regions. Sequential caret motion uses this to skip\n * over collapsed regions like code folds; it walks the hunk metadata once\n * instead of probing line by line across a gap.\n */\nexport function getNearestRenderableAdditionLine({\n fileDiff,\n lineNumber,\n direction,\n expandedHunks,\n collapsedContextThreshold,\n}: GetNearestRenderableAdditionLineProps): number | undefined {\n if (expandedHunks === true || fileDiff.isPartial) {\n return lineNumber;\n }\n\n // Renderable [start, end) line ranges in ascending order, plus the\n // exclusive end of the modeled range — anything past it (the editor's\n // phantom document-end line) counts as renderable.\n const ranges: Array<[start: number, end: number]> = [];\n let modeledEnd = 1;\n for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {\n const [hunkStart, hunkEnd] = getHunkAdditionLineRange(hunk);\n const region = getExpandedRegion({\n isPartial: fileDiff.isPartial,\n rangeSize: hunk.collapsedBefore,\n expandedHunks,\n hunkIndex,\n collapsedContextThreshold,\n });\n const gapStart = hunkStart - region.rangeSize;\n if (region.renderAll) {\n ranges.push([gapStart, hunkStart]);\n } else {\n if (region.fromStart > 0) {\n ranges.push([gapStart, gapStart + region.fromStart]);\n }\n if (region.fromEnd > 0) {\n ranges.push([hunkStart - region.fromEnd, hunkStart]);\n }\n }\n ranges.push([hunkStart, hunkEnd]);\n modeledEnd = hunkEnd;\n }\n const trailingRegion = getTrailingExpandedRegion({\n fileDiff,\n hunkIndex: fileDiff.hunks.length - 1,\n expandedHunks,\n collapsedContextThreshold,\n errorPrefix: 'getNearestRenderableAdditionLine',\n });\n if (trailingRegion != null) {\n const trailingStart = modeledEnd;\n modeledEnd = trailingStart + trailingRegion.rangeSize;\n if (trailingRegion.renderAll) {\n ranges.push([trailingStart, modeledEnd]);\n } else if (trailingRegion.fromStart > 0) {\n ranges.push([trailingStart, trailingStart + trailingRegion.fromStart]);\n }\n }\n\n if (lineNumber >= modeledEnd) {\n return lineNumber;\n }\n if (direction === 'down') {\n for (const [start, end] of ranges) {\n if (end > lineNumber) {\n return Math.max(start, lineNumber);\n }\n }\n return undefined;\n }\n for (let index = ranges.length - 1; index >= 0; index--) {\n const [start, end] = ranges[index];\n if (start <= lineNumber) {\n return Math.min(end - 1, lineNumber);\n }\n }\n return undefined;\n}\n\nexport function getHunkSeparatorHeight({\n type,\n metrics,\n}: HunkSeparatorBaseProps): number {\n return metrics.hunkSeparatorHeight ?? getDefaultHunkSeparatorHeight(type);\n}\n\nexport function getHunkSeparatorGap({\n type,\n metrics,\n}: HunkSeparatorBaseProps): number {\n return type === 'simple' || type === 'metadata' || type === 'line-info-basic'\n ? 0\n : metrics.spacing;\n}\n\nexport function hasLeadingHunkSeparator({\n type,\n hunkIndex,\n hunkSpecs,\n}: Omit<LeadingHunkSeparatorLayoutProps, 'metrics'>): boolean {\n switch (type) {\n case 'simple':\n return hunkIndex > 0;\n case 'metadata':\n return hunkSpecs != null;\n case 'line-info':\n case 'line-info-basic':\n case 'custom':\n return true;\n }\n}\n\nexport function hasTrailingHunkSeparator(type: HunkSeparators): boolean {\n return type !== 'simple' && type !== 'metadata';\n}\n\n// Mirrors the renderer/CSS spacing rules for the separator shown before a hunk.\nexport function getLeadingHunkSeparatorLayout({\n type,\n metrics,\n hunkIndex,\n hunkSpecs,\n}: LeadingHunkSeparatorLayoutProps): HunkSeparatorLayout | undefined {\n if (!hasLeadingHunkSeparator({ type, hunkIndex, hunkSpecs })) {\n return undefined;\n }\n\n const height = getHunkSeparatorHeight({ type, metrics });\n const gap = getHunkSeparatorGap({ type, metrics });\n const gapBefore = hunkIndex > 0 ? gap : 0;\n const gapAfter = gap;\n return {\n height,\n gapBefore,\n gapAfter,\n totalHeight: gapBefore + height + gapAfter,\n };\n}\n\n// Mirrors the renderer/CSS spacing rules for the separator shown after the last\n// hunk when trailing unchanged context is collapsed.\nexport function getTrailingHunkSeparatorLayout({\n type,\n metrics,\n}: HunkSeparatorBaseProps): HunkSeparatorLayout | undefined {\n if (!hasTrailingHunkSeparator(type)) {\n return undefined;\n }\n\n const height = getHunkSeparatorHeight({ type, metrics });\n const gapBefore = getHunkSeparatorGap({ type, metrics });\n return {\n height,\n gapBefore,\n gapAfter: 0,\n totalHeight: gapBefore + height,\n };\n}\n"],"mappings":"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"}
|
|
@@ -12536,7 +12536,14 @@ function getLineNodes(nodes) {
|
|
|
12536
12536
|
throw new Error("getLineNodes: Unable to find children");
|
|
12537
12537
|
}
|
|
12538
12538
|
//#endregion
|
|
12539
|
-
//#region src/utils/
|
|
12539
|
+
//#region src/utils/getHunkSideBoundaries.ts
|
|
12540
|
+
/** Converts a unified hunk side's start/count into its consumed-file range. */
|
|
12541
|
+
function getHunkSideStartBoundary(start, count) {
|
|
12542
|
+
return start - (count === 0 ? 0 : 1);
|
|
12543
|
+
}
|
|
12544
|
+
function getHunkSideEndBoundary(start, count) {
|
|
12545
|
+
return getHunkSideStartBoundary(start, count) + count;
|
|
12546
|
+
}
|
|
12540
12547
|
function getExpandedRegion({ isPartial, rangeSize, expandedHunks, hunkIndex, collapsedContextThreshold }) {
|
|
12541
12548
|
const normalizedRangeSize = Math.max(rangeSize, 0);
|
|
12542
12549
|
if (normalizedRangeSize === 0 || isPartial) return {
|
|
@@ -12569,8 +12576,8 @@ function getExpandedRegion({ isPartial, rangeSize, expandedHunks, hunkIndex, col
|
|
|
12569
12576
|
function getTrailingContextRangeSize({ fileDiff, errorPrefix }) {
|
|
12570
12577
|
const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];
|
|
12571
12578
|
if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return 0;
|
|
12572
|
-
const additionRemaining = fileDiff.additionLines.length - (lastHunk.
|
|
12573
|
-
const deletionRemaining = fileDiff.deletionLines.length - (lastHunk.
|
|
12579
|
+
const additionRemaining = fileDiff.additionLines.length - getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount);
|
|
12580
|
+
const deletionRemaining = fileDiff.deletionLines.length - getHunkSideEndBoundary(lastHunk.deletionStart, lastHunk.deletionCount);
|
|
12574
12581
|
if (additionRemaining <= 0 && deletionRemaining <= 0) return 0;
|
|
12575
12582
|
if (additionRemaining !== deletionRemaining) throw new Error(`${errorPrefix}: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`);
|
|
12576
12583
|
return Math.min(additionRemaining, deletionRemaining);
|
|
@@ -12661,6 +12668,10 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
12661
12668
|
const hunk = diff.hunks[hunkIndex];
|
|
12662
12669
|
if (hunk == null) throw new Error("iterateOverDiff: invalid hunk index");
|
|
12663
12670
|
if (state.shouldBreak()) break;
|
|
12671
|
+
const deletionBoundary = getHunkSideStartBoundary(hunk.deletionStart, hunk.deletionCount);
|
|
12672
|
+
const additionBoundary = getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount);
|
|
12673
|
+
const deletionStartIndex = !diff.isPartial && hunk.deletionCount === 0 ? deletionBoundary : hunk.deletionLineIndex;
|
|
12674
|
+
const additionStartIndex = !diff.isPartial && hunk.additionCount === 0 ? additionBoundary : hunk.additionLineIndex;
|
|
12664
12675
|
const leadingRegion = getExpandedRegion({
|
|
12665
12676
|
isPartial: diff.isPartial,
|
|
12666
12677
|
rangeSize: hunk.collapsedBefore,
|
|
@@ -12690,10 +12701,10 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
12690
12701
|
if (!state.shouldSkip(expandedLineCount, expandedLineCount)) {
|
|
12691
12702
|
let unifiedLineIndex = hunk.unifiedLineStart - leadingRegion.rangeSize;
|
|
12692
12703
|
let splitLineIndex = hunk.splitLineStart - leadingRegion.rangeSize;
|
|
12693
|
-
let deletionLineIndex =
|
|
12694
|
-
let additionLineIndex =
|
|
12695
|
-
let deletionLineNumber =
|
|
12696
|
-
let additionLineNumber =
|
|
12704
|
+
let deletionLineIndex = deletionStartIndex - leadingRegion.rangeSize;
|
|
12705
|
+
let additionLineIndex = additionStartIndex - leadingRegion.rangeSize;
|
|
12706
|
+
let deletionLineNumber = deletionBoundary + 1 - leadingRegion.rangeSize;
|
|
12707
|
+
let additionLineNumber = additionBoundary + 1 - leadingRegion.rangeSize;
|
|
12697
12708
|
if (walkContextLines(state, leadingRegion.fromStart, diffStyle, (index) => {
|
|
12698
12709
|
return state.emit({
|
|
12699
12710
|
hunkIndex,
|
|
@@ -12719,10 +12730,10 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
12719
12730
|
})) break hunkIterator;
|
|
12720
12731
|
unifiedLineIndex = hunk.unifiedLineStart - leadingRegion.fromEnd;
|
|
12721
12732
|
splitLineIndex = hunk.splitLineStart - leadingRegion.fromEnd;
|
|
12722
|
-
deletionLineIndex =
|
|
12723
|
-
additionLineIndex =
|
|
12724
|
-
deletionLineNumber =
|
|
12725
|
-
additionLineNumber =
|
|
12733
|
+
deletionLineIndex = deletionStartIndex - leadingRegion.fromEnd;
|
|
12734
|
+
additionLineIndex = additionStartIndex - leadingRegion.fromEnd;
|
|
12735
|
+
deletionLineNumber = deletionBoundary + 1 - leadingRegion.fromEnd;
|
|
12736
|
+
additionLineNumber = additionBoundary + 1 - leadingRegion.fromEnd;
|
|
12726
12737
|
if (walkContextLines(state, leadingRegion.fromEnd, diffStyle, (index) => {
|
|
12727
12738
|
return state.emit({
|
|
12728
12739
|
hunkIndex,
|
|
@@ -12754,10 +12765,10 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
12754
12765
|
}
|
|
12755
12766
|
let unifiedLineIndex = hunk.unifiedLineStart;
|
|
12756
12767
|
let splitLineIndex = hunk.splitLineStart;
|
|
12757
|
-
let deletionLineIndex =
|
|
12758
|
-
let additionLineIndex =
|
|
12759
|
-
let deletionLineNumber =
|
|
12760
|
-
let additionLineNumber =
|
|
12768
|
+
let deletionLineIndex = deletionStartIndex;
|
|
12769
|
+
let additionLineIndex = additionStartIndex;
|
|
12770
|
+
let deletionLineNumber = deletionBoundary + 1;
|
|
12771
|
+
let additionLineNumber = additionBoundary + 1;
|
|
12761
12772
|
const lastContent = hunk.hunkContent.at(-1);
|
|
12762
12773
|
for (const content of hunk.hunkContent) {
|
|
12763
12774
|
if (state.shouldBreak()) break hunkIterator;
|
|
@@ -13366,16 +13377,45 @@ function renderTwoFiles({ deletionFile, additionFile, deletionInfo, additionInfo
|
|
|
13366
13377
|
//#region src/utils/computeFileOffsets.ts
|
|
13367
13378
|
const LINE_FEED = 10;
|
|
13368
13379
|
const CARRIAGE_RETURN = 13;
|
|
13380
|
+
const DENSE_LINE_BREAK_BLOCK_SIZE = 4;
|
|
13381
|
+
const DENSE_LINE_BREAK_BLOCK_SPAN = 40;
|
|
13369
13382
|
/**
|
|
13370
13383
|
* Computes line start offsets for a string.
|
|
13371
13384
|
*/
|
|
13372
13385
|
function computeLineOffsets(contents) {
|
|
13373
13386
|
const offsets = [0];
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
13387
|
+
let carriageReturn = contents.indexOf("\r");
|
|
13388
|
+
let lineFeed = contents.indexOf("\n");
|
|
13389
|
+
let blockStart = 0;
|
|
13390
|
+
let blockBreaks = 0;
|
|
13391
|
+
while (carriageReturn !== -1 || lineFeed !== -1) {
|
|
13392
|
+
let nextOffset;
|
|
13393
|
+
if (carriageReturn !== -1 && (lineFeed === -1 || carriageReturn < lineFeed)) if (lineFeed === carriageReturn + 1) {
|
|
13394
|
+
nextOffset = lineFeed + 1;
|
|
13395
|
+
carriageReturn = contents.indexOf("\r", nextOffset);
|
|
13396
|
+
lineFeed = contents.indexOf("\n", nextOffset);
|
|
13397
|
+
} else {
|
|
13398
|
+
nextOffset = carriageReturn + 1;
|
|
13399
|
+
carriageReturn = contents.indexOf("\r", nextOffset);
|
|
13400
|
+
}
|
|
13401
|
+
else {
|
|
13402
|
+
nextOffset = lineFeed + 1;
|
|
13403
|
+
lineFeed = contents.indexOf("\n", nextOffset);
|
|
13404
|
+
}
|
|
13405
|
+
offsets.push(nextOffset);
|
|
13406
|
+
if (++blockBreaks === DENSE_LINE_BREAK_BLOCK_SIZE) {
|
|
13407
|
+
if (nextOffset - blockStart <= DENSE_LINE_BREAK_BLOCK_SPAN) {
|
|
13408
|
+
for (let i = nextOffset; i < contents.length; i++) {
|
|
13409
|
+
const char = contents.charCodeAt(i);
|
|
13410
|
+
if (char === LINE_FEED || char === CARRIAGE_RETURN) {
|
|
13411
|
+
if (char === CARRIAGE_RETURN && i + 1 < contents.length && contents.charCodeAt(i + 1) === LINE_FEED) i++;
|
|
13412
|
+
offsets.push(i + 1);
|
|
13413
|
+
}
|
|
13414
|
+
}
|
|
13415
|
+
return offsets;
|
|
13416
|
+
}
|
|
13417
|
+
blockStart = nextOffset;
|
|
13418
|
+
blockBreaks = 0;
|
|
13379
13419
|
}
|
|
13380
13420
|
}
|
|
13381
13421
|
return offsets;
|