@pierre/diffs 1.2.6 → 1.3.0-beta.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 +0 -1
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +0 -23
- 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 -2
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +8 -2
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +73 -1
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +2 -2
- package/dist/components/VirtualizedFile.d.ts +2 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +48 -48
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +42 -22
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +1 -1
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +3 -5
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/editor/command.d.ts +6 -0
- package/dist/editor/command.d.ts.map +1 -0
- package/dist/editor/command.js +31 -0
- package/dist/editor/command.js.map +1 -0
- package/dist/editor/css.d.ts +6 -0
- package/dist/editor/css.d.ts.map +1 -0
- package/dist/editor/css.js +218 -0
- package/dist/editor/css.js.map +1 -0
- package/dist/editor/editStack.d.ts +66 -0
- package/dist/editor/editStack.d.ts.map +1 -0
- package/dist/editor/editStack.js +218 -0
- package/dist/editor/editStack.js.map +1 -0
- package/dist/editor/editor.d.ts +22 -0
- package/dist/editor/editor.d.ts.map +1 -0
- package/dist/editor/editor.js +1323 -0
- package/dist/editor/editor.js.map +1 -0
- package/dist/editor/index.d.ts +3 -0
- package/dist/editor/index.js +4 -0
- package/dist/editor/lineAnnotations.d.ts +8 -0
- package/dist/editor/lineAnnotations.d.ts.map +1 -0
- package/dist/editor/lineAnnotations.js +32 -0
- package/dist/editor/lineAnnotations.js.map +1 -0
- package/dist/editor/pieceTable.d.ts +33 -0
- package/dist/editor/pieceTable.d.ts.map +1 -0
- package/dist/editor/pieceTable.js +590 -0
- package/dist/editor/pieceTable.js.map +1 -0
- package/dist/editor/platform.d.ts +12 -0
- package/dist/editor/platform.d.ts.map +1 -0
- package/dist/editor/platform.js +44 -0
- package/dist/editor/platform.js.map +1 -0
- package/dist/editor/quickEdit.d.ts +29 -0
- package/dist/editor/quickEdit.d.ts.map +1 -0
- package/dist/editor/quickEdit.js +81 -0
- package/dist/editor/quickEdit.js.map +1 -0
- package/dist/editor/searchPanel.d.ts +30 -0
- package/dist/editor/searchPanel.d.ts.map +1 -0
- package/dist/editor/searchPanel.js +219 -0
- package/dist/editor/searchPanel.js.map +1 -0
- package/dist/editor/selection.d.ts +126 -0
- package/dist/editor/selection.d.ts.map +1 -0
- package/dist/editor/selection.js +900 -0
- package/dist/editor/selection.js.map +1 -0
- package/dist/editor/textDocument.d.ts +139 -0
- package/dist/editor/textDocument.d.ts.map +1 -0
- package/dist/editor/textDocument.js +202 -0
- package/dist/editor/textDocument.js.map +1 -0
- package/dist/editor/textMeasure.d.ts +32 -0
- package/dist/editor/textMeasure.d.ts.map +1 -0
- package/dist/editor/textMeasure.js +108 -0
- package/dist/editor/textMeasure.js.map +1 -0
- package/dist/editor/tokenzier.d.ts +37 -0
- package/dist/editor/tokenzier.d.ts.map +1 -0
- package/dist/editor/tokenzier.js +348 -0
- package/dist/editor/tokenzier.js.map +1 -0
- package/dist/editor/utils.d.ts +16 -0
- package/dist/editor/utils.d.ts.map +1 -0
- package/dist/editor/utils.js +37 -0
- package/dist/editor/utils.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/react/EditorContext.d.ts +16 -0
- package/dist/react/EditorContext.d.ts.map +1 -0
- package/dist/react/EditorContext.js +26 -0
- package/dist/react/EditorContext.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 +3 -1
- 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 +3 -1
- 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 +3 -1
- 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/index.d.ts +3 -2
- package/dist/react/index.js +2 -1
- package/dist/react/jsx.d.ts +0 -1
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/types.d.ts +1 -0
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/types.js +0 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +3 -1
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +31 -5
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +4 -1
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +30 -5
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +2 -2
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +9 -5
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +5 -1
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +108 -41
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/style.js +1 -1
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +45 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/cleanLastNewline.js +6 -1
- package/dist/utils/cleanLastNewline.js.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.js +20 -9
- package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
- package/dist/utils/computeFileOffsets.d.ts +13 -0
- package/dist/utils/computeFileOffsets.d.ts.map +1 -0
- package/dist/utils/computeFileOffsets.js +33 -0
- package/dist/utils/computeFileOffsets.js.map +1 -0
- package/dist/utils/createTransformerWithState.js +9 -0
- package/dist/utils/createTransformerWithState.js.map +1 -1
- package/dist/utils/iterateOverDiff.js +182 -147
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +1 -1
- package/dist/utils/renderFileWithHighlighter.js +5 -14
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts +2 -23
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +1 -41
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/WorkerPoolManager.js +1 -1
- package/dist/worker/{wasm-BaDzIkIn.js → wasm-D4DU5jgR.js} +2 -2
- package/dist/worker/wasm-D4DU5jgR.js.map +1 -0
- package/dist/worker/worker-portable.js +349 -363
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +222 -243
- package/dist/worker/worker.js.map +1 -1
- package/package.json +9 -1
- package/dist/utils/iterateOverFile.d.ts +0 -50
- package/dist/utils/iterateOverFile.d.ts.map +0 -1
- package/dist/utils/iterateOverFile.js +0 -49
- package/dist/utils/iterateOverFile.js.map +0 -1
- package/dist/worker/wasm-BaDzIkIn.js.map +0 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/utils/computeFileOffsets.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Computes line start offsets for a string.
|
|
4
|
+
*/
|
|
5
|
+
declare function computeLineOffsets(contents: string): number[];
|
|
6
|
+
/**
|
|
7
|
+
* Splits file contents into lines aligned with {@link computeLineOffsets}.
|
|
8
|
+
* Unlike splitFileContents, a trailing newline produces a final empty line.
|
|
9
|
+
*/
|
|
10
|
+
declare function linesFromFileContents(contents: string): string[];
|
|
11
|
+
//#endregion
|
|
12
|
+
export { computeLineOffsets, linesFromFileContents };
|
|
13
|
+
//# sourceMappingURL=computeFileOffsets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"computeFileOffsets.d.ts","names":["computeLineOffsets","linesFromFileContents"],"sources":["../../src/utils/computeFileOffsets.d.ts"],"sourcesContent":["/**\n * Computes line start offsets for a string.\n */\nexport declare function computeLineOffsets(contents: string): number[];\n/**\n * Splits file contents into lines aligned with {@link computeLineOffsets}.\n * Unlike splitFileContents, a trailing newline produces a final empty line.\n */\nexport declare function linesFromFileContents(contents: string): string[];\n//# sourceMappingURL=computeFileOffsets.d.ts.map"],"mappings":";;AAGA;AAKA;iBALwBA,kBAAAA;;;;;iBAKAC,qBAAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/utils/computeFileOffsets.ts
|
|
2
|
+
const LINE_FEED = 10;
|
|
3
|
+
const CARRIAGE_RETURN = 13;
|
|
4
|
+
/**
|
|
5
|
+
* Computes line start offsets for a string.
|
|
6
|
+
*/
|
|
7
|
+
function computeLineOffsets(contents) {
|
|
8
|
+
const offsets = [0];
|
|
9
|
+
for (let i = 0; i < contents.length; i++) {
|
|
10
|
+
const char = contents.charCodeAt(i);
|
|
11
|
+
if (char === LINE_FEED || char === CARRIAGE_RETURN) {
|
|
12
|
+
if (char === CARRIAGE_RETURN && i + 1 < contents.length && contents.charCodeAt(i + 1) === LINE_FEED) i++;
|
|
13
|
+
offsets.push(i + 1);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return offsets;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Splits file contents into lines aligned with {@link computeLineOffsets}.
|
|
20
|
+
* Unlike splitFileContents, a trailing newline produces a final empty line.
|
|
21
|
+
*/
|
|
22
|
+
function linesFromFileContents(contents) {
|
|
23
|
+
const offsets = computeLineOffsets(contents);
|
|
24
|
+
return Array.from({ length: offsets.length }, (_, i) => {
|
|
25
|
+
const start = offsets[i];
|
|
26
|
+
const end = offsets[i + 1] ?? contents.length;
|
|
27
|
+
return contents.slice(start, end);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { computeLineOffsets, linesFromFileContents };
|
|
33
|
+
//# sourceMappingURL=computeFileOffsets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"computeFileOffsets.js","names":["offsets: number[]"],"sources":["../../src/utils/computeFileOffsets.ts"],"sourcesContent":["const LINE_FEED = 10; // \\n\nconst CARRIAGE_RETURN = 13; // \\r\n\n/**\n * Computes line start offsets for a string.\n */\nexport function computeLineOffsets(contents: string): number[] {\n const offsets: number[] = [0];\n for (let i = 0; i < contents.length; i++) {\n const char = contents.charCodeAt(i);\n if (char === LINE_FEED || char === CARRIAGE_RETURN) {\n if (\n char === CARRIAGE_RETURN &&\n i + 1 < contents.length &&\n contents.charCodeAt(i + 1) === LINE_FEED\n ) {\n i++;\n }\n offsets.push(i + 1);\n }\n }\n return offsets;\n}\n\n/**\n * Splits file contents into lines aligned with {@link computeLineOffsets}.\n * Unlike splitFileContents, a trailing newline produces a final empty line.\n */\nexport function linesFromFileContents(contents: string): string[] {\n const offsets = computeLineOffsets(contents);\n const lines = Array.from({ length: offsets.length }, (_, i) => {\n const start = offsets[i];\n const end = offsets[i + 1] ?? contents.length;\n return contents.slice(start, end);\n });\n return lines;\n}\n"],"mappings":";AAAA,MAAM,YAAY;AAClB,MAAM,kBAAkB;;;;AAKxB,SAAgB,mBAAmB,UAA4B;CAC7D,MAAMA,UAAoB,CAAC,EAAE;AAC7B,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,OAAO,SAAS,WAAW,EAAE;AACnC,MAAI,SAAS,aAAa,SAAS,iBAAiB;AAClD,OACE,SAAS,mBACT,IAAI,IAAI,SAAS,UACjB,SAAS,WAAW,IAAI,EAAE,KAAK,UAE/B;AAEF,WAAQ,KAAK,IAAI,EAAE;;;AAGvB,QAAO;;;;;;AAOT,SAAgB,sBAAsB,UAA4B;CAChE,MAAM,UAAU,mBAAmB,SAAS;AAM5C,QALc,MAAM,KAAK,EAAE,QAAQ,QAAQ,QAAQ,GAAG,GAAG,MAAM;EAC7D,MAAM,QAAQ,QAAQ;EACtB,MAAM,MAAM,QAAQ,IAAI,MAAM,SAAS;AACvC,SAAO,SAAS,MAAM,OAAO,IAAI;GACjC"}
|
|
@@ -51,6 +51,15 @@ function createTransformerWithState(useTokenTransformer = false, useCSSClasses =
|
|
|
51
51
|
} : null
|
|
52
52
|
}];
|
|
53
53
|
if (useCSSClasses) transformers.push(tokenStyleNormalizer, toClass);
|
|
54
|
+
if (useTokenTransformer) transformers.push({ line: (node) => {
|
|
55
|
+
if (node.type === "element" && node.children.length === 0) node.children.push({
|
|
56
|
+
type: "element",
|
|
57
|
+
tagName: "br",
|
|
58
|
+
properties: {},
|
|
59
|
+
children: []
|
|
60
|
+
});
|
|
61
|
+
return node;
|
|
62
|
+
} });
|
|
54
63
|
return {
|
|
55
64
|
state,
|
|
56
65
|
transformers,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTransformerWithState.js","names":["state: SharedRenderState","transformers: ShikiTransformer[]","children: ElementContent[]","tokenStyleNormalizer: ShikiTransformer","style: Record<string, string>"],"sources":["../../src/utils/createTransformerWithState.ts"],"sourcesContent":["import {\n type ShikiTransformerStyleToClass,\n transformerStyleToClass,\n} from '@shikijs/transformers';\nimport type { ElementContent } from 'hast';\nimport type { ThemedToken } from 'shiki';\n\nimport type { SharedRenderState, ShikiTransformer } from '../types';\nimport { findCodeElement } from './hast_utils';\nimport { processLine } from './processLine';\nimport { wrapTokenFragments } from './wrapTokenFragments';\n\ninterface CreateTransformerWithStateReturn {\n state: SharedRenderState;\n transformers: ShikiTransformer[];\n toClass: ShikiTransformerStyleToClass;\n}\n\ntype TokenWithLineChar = ThemedToken & {\n __lineChar?: number;\n};\n\nexport function createTransformerWithState(\n useTokenTransformer = false,\n useCSSClasses = false\n): CreateTransformerWithStateReturn {\n const state: SharedRenderState = { lineInfo: [] };\n const transformers: ShikiTransformer[] = [\n {\n line(node) {\n // Remove the default class\n delete node.properties.class;\n return node;\n },\n pre(pre) {\n const code = findCodeElement(pre);\n const children: ElementContent[] = [];\n if (code != null) {\n let index = 1;\n for (const node of code.children) {\n if (node.type !== 'element') continue;\n if (useTokenTransformer) {\n wrapTokenFragments(node);\n }\n children.push(processLine(node, index, state));\n index++;\n }\n code.children = children;\n }\n return pre;\n },\n ...(useTokenTransformer\n ? {\n tokens(lines) {\n for (const line of lines) {\n let col = 0;\n for (const token of line) {\n const tokenWithOriginalRange = token as TokenWithLineChar;\n tokenWithOriginalRange.__lineChar ??= col;\n col += token.content.length;\n }\n }\n },\n preprocess(_code, options) {\n options.mergeWhitespaces = 'never';\n },\n span(hast, _line, _char, _lineElement, token) {\n if (token?.offset != null && token.content != null) {\n const tokenWithOriginalRange = token as TokenWithLineChar;\n const tokenChar = tokenWithOriginalRange.__lineChar;\n if (tokenChar != null) {\n hast.properties['data-char'] = tokenChar;\n }\n return hast;\n }\n return hast;\n },\n }\n : null),\n },\n ];\n if (useCSSClasses) {\n transformers.push(tokenStyleNormalizer, toClass);\n }\n return { state, transformers, toClass };\n}\n\nconst toClass = transformerStyleToClass({ classPrefix: 'hl-' });\n\n// Create a transformer that converts token color/fontStyle to htmlStyle\n// This needs to run BEFORE transformerStyleToClass\nconst tokenStyleNormalizer: ShikiTransformer = {\n name: 'token-style-normalizer',\n tokens(lines) {\n for (const line of lines) {\n for (const token of line) {\n // Skip if htmlStyle is already set\n if (token.htmlStyle != null) continue;\n\n const style: Record<string, string> = {};\n\n if (token.color != null) {\n style.color = token.color;\n }\n if (token.bgColor != null) {\n style['background-color'] = token.bgColor;\n }\n if (token.fontStyle != null && token.fontStyle !== 0) {\n // FontStyle is a bitmask: 1 = italic, 2 = bold, 4 = underline\n if ((token.fontStyle & 1) !== 0) {\n style['font-style'] = 'italic';\n }\n if ((token.fontStyle & 2) !== 0) {\n style['font-weight'] = 'bold';\n }\n if ((token.fontStyle & 4) !== 0) {\n style['text-decoration'] = 'underline';\n }\n }\n\n // Only set htmlStyle if we have any styles\n if (Object.keys(style).length > 0) {\n token.htmlStyle = style;\n }\n }\n }\n },\n};\n"],"mappings":";;;;;;AAsBA,SAAgB,2BACd,sBAAsB,OACtB,gBAAgB,OACkB;CAClC,MAAMA,QAA2B,EAAE,UAAU,EAAE,EAAE;CACjD,MAAMC,eAAmC,CACvC;EACE,KAAK,MAAM;AAET,UAAO,KAAK,WAAW;AACvB,UAAO;;EAET,IAAI,KAAK;GACP,MAAM,OAAO,gBAAgB,IAAI;GACjC,MAAMC,WAA6B,EAAE;AACrC,OAAI,QAAQ,MAAM;IAChB,IAAI,QAAQ;AACZ,SAAK,MAAM,QAAQ,KAAK,UAAU;AAChC,SAAI,KAAK,SAAS,UAAW;AAC7B,SAAI,oBACF,oBAAmB,KAAK;AAE1B,cAAS,KAAK,YAAY,MAAM,OAAO,MAAM,CAAC;AAC9C;;AAEF,SAAK,WAAW;;AAElB,UAAO;;EAET,GAAI,sBACA;GACE,OAAO,OAAO;AACZ,SAAK,MAAM,QAAQ,OAAO;KACxB,IAAI,MAAM;AACV,UAAK,MAAM,SAAS,MAAM;MACxB,MAAM,yBAAyB;AAC/B,6BAAuB,eAAe;AACtC,aAAO,MAAM,QAAQ;;;;GAI3B,WAAW,OAAO,SAAS;AACzB,YAAQ,mBAAmB;;GAE7B,KAAK,MAAM,OAAO,OAAO,cAAc,OAAO;AAC5C,QAAI,OAAO,UAAU,QAAQ,MAAM,WAAW,MAAM;KAElD,MAAM,YADyB,MACU;AACzC,SAAI,aAAa,KACf,MAAK,WAAW,eAAe;AAEjC,YAAO;;AAET,WAAO;;GAEV,GACD;EACL,CACF;AACD,KAAI,cACF,cAAa,KAAK,sBAAsB,QAAQ;AAElD,QAAO;EAAE;EAAO;EAAc;EAAS;;AAGzC,MAAM,UAAU,wBAAwB,EAAE,aAAa,OAAO,CAAC;AAI/D,MAAMC,uBAAyC;CAC7C,MAAM;CACN,OAAO,OAAO;AACZ,OAAK,MAAM,QAAQ,MACjB,MAAK,MAAM,SAAS,MAAM;AAExB,OAAI,MAAM,aAAa,KAAM;GAE7B,MAAMC,QAAgC,EAAE;AAExC,OAAI,MAAM,SAAS,KACjB,OAAM,QAAQ,MAAM;AAEtB,OAAI,MAAM,WAAW,KACnB,OAAM,sBAAsB,MAAM;AAEpC,OAAI,MAAM,aAAa,QAAQ,MAAM,cAAc,GAAG;AAEpD,SAAK,MAAM,YAAY,OAAO,EAC5B,OAAM,gBAAgB;AAExB,SAAK,MAAM,YAAY,OAAO,EAC5B,OAAM,iBAAiB;AAEzB,SAAK,MAAM,YAAY,OAAO,EAC5B,OAAM,qBAAqB;;AAK/B,OAAI,OAAO,KAAK,MAAM,CAAC,SAAS,EAC9B,OAAM,YAAY;;;CAK3B"}
|
|
1
|
+
{"version":3,"file":"createTransformerWithState.js","names":["state: SharedRenderState","transformers: ShikiTransformer[]","children: ElementContent[]","tokenStyleNormalizer: ShikiTransformer","style: Record<string, string>"],"sources":["../../src/utils/createTransformerWithState.ts"],"sourcesContent":["import {\n type ShikiTransformerStyleToClass,\n transformerStyleToClass,\n} from '@shikijs/transformers';\nimport type { ElementContent } from 'hast';\nimport type { ThemedToken } from 'shiki';\n\nimport type { SharedRenderState, ShikiTransformer } from '../types';\nimport { findCodeElement } from './hast_utils';\nimport { processLine } from './processLine';\nimport { wrapTokenFragments } from './wrapTokenFragments';\n\ninterface CreateTransformerWithStateReturn {\n state: SharedRenderState;\n transformers: ShikiTransformer[];\n toClass: ShikiTransformerStyleToClass;\n}\n\ntype TokenWithLineChar = ThemedToken & {\n __lineChar?: number;\n};\n\nexport function createTransformerWithState(\n useTokenTransformer = false,\n useCSSClasses = false\n): CreateTransformerWithStateReturn {\n const state: SharedRenderState = { lineInfo: [] };\n const transformers: ShikiTransformer[] = [\n {\n line(node) {\n // Remove the default class\n delete node.properties.class;\n return node;\n },\n pre(pre) {\n const code = findCodeElement(pre);\n const children: ElementContent[] = [];\n if (code != null) {\n let index = 1;\n for (const node of code.children) {\n if (node.type !== 'element') continue;\n if (useTokenTransformer) {\n wrapTokenFragments(node);\n }\n children.push(processLine(node, index, state));\n index++;\n }\n code.children = children;\n }\n return pre;\n },\n ...(useTokenTransformer\n ? {\n tokens(lines) {\n for (const line of lines) {\n let col = 0;\n for (const token of line) {\n const tokenWithOriginalRange = token as TokenWithLineChar;\n tokenWithOriginalRange.__lineChar ??= col;\n col += token.content.length;\n }\n }\n },\n preprocess(_code, options) {\n options.mergeWhitespaces = 'never';\n },\n span(hast, _line, _char, _lineElement, token) {\n if (token?.offset != null && token.content != null) {\n const tokenWithOriginalRange = token as TokenWithLineChar;\n const tokenChar = tokenWithOriginalRange.__lineChar;\n if (tokenChar != null) {\n hast.properties['data-char'] = tokenChar;\n }\n return hast;\n }\n return hast;\n },\n }\n : null),\n },\n ];\n if (useCSSClasses) {\n transformers.push(tokenStyleNormalizer, toClass);\n }\n if (useTokenTransformer) {\n // shiki renders empty lines as \" \" that breaks the editor selection.\n // We replace them with <br> tags.\n transformers.push({\n line: (node) => {\n if (node.type === 'element' && node.children.length === 0) {\n node.children.push({\n type: 'element',\n tagName: 'br',\n properties: {},\n children: [],\n });\n }\n return node;\n },\n });\n }\n return { state, transformers, toClass };\n}\n\nconst toClass = transformerStyleToClass({ classPrefix: 'hl-' });\n\n// Create a transformer that converts token color/fontStyle to htmlStyle\n// This needs to run BEFORE transformerStyleToClass\nconst tokenStyleNormalizer: ShikiTransformer = {\n name: 'token-style-normalizer',\n tokens(lines) {\n for (const line of lines) {\n for (const token of line) {\n // Skip if htmlStyle is already set\n if (token.htmlStyle != null) continue;\n\n const style: Record<string, string> = {};\n\n if (token.color != null) {\n style.color = token.color;\n }\n if (token.bgColor != null) {\n style['background-color'] = token.bgColor;\n }\n if (token.fontStyle != null && token.fontStyle !== 0) {\n // FontStyle is a bitmask: 1 = italic, 2 = bold, 4 = underline\n if ((token.fontStyle & 1) !== 0) {\n style['font-style'] = 'italic';\n }\n if ((token.fontStyle & 2) !== 0) {\n style['font-weight'] = 'bold';\n }\n if ((token.fontStyle & 4) !== 0) {\n style['text-decoration'] = 'underline';\n }\n }\n\n // Only set htmlStyle if we have any styles\n if (Object.keys(style).length > 0) {\n token.htmlStyle = style;\n }\n }\n }\n },\n};\n"],"mappings":";;;;;;AAsBA,SAAgB,2BACd,sBAAsB,OACtB,gBAAgB,OACkB;CAClC,MAAMA,QAA2B,EAAE,UAAU,EAAE,EAAE;CACjD,MAAMC,eAAmC,CACvC;EACE,KAAK,MAAM;AAET,UAAO,KAAK,WAAW;AACvB,UAAO;;EAET,IAAI,KAAK;GACP,MAAM,OAAO,gBAAgB,IAAI;GACjC,MAAMC,WAA6B,EAAE;AACrC,OAAI,QAAQ,MAAM;IAChB,IAAI,QAAQ;AACZ,SAAK,MAAM,QAAQ,KAAK,UAAU;AAChC,SAAI,KAAK,SAAS,UAAW;AAC7B,SAAI,oBACF,oBAAmB,KAAK;AAE1B,cAAS,KAAK,YAAY,MAAM,OAAO,MAAM,CAAC;AAC9C;;AAEF,SAAK,WAAW;;AAElB,UAAO;;EAET,GAAI,sBACA;GACE,OAAO,OAAO;AACZ,SAAK,MAAM,QAAQ,OAAO;KACxB,IAAI,MAAM;AACV,UAAK,MAAM,SAAS,MAAM;MACxB,MAAM,yBAAyB;AAC/B,6BAAuB,eAAe;AACtC,aAAO,MAAM,QAAQ;;;;GAI3B,WAAW,OAAO,SAAS;AACzB,YAAQ,mBAAmB;;GAE7B,KAAK,MAAM,OAAO,OAAO,cAAc,OAAO;AAC5C,QAAI,OAAO,UAAU,QAAQ,MAAM,WAAW,MAAM;KAElD,MAAM,YADyB,MACU;AACzC,SAAI,aAAa,KACf,MAAK,WAAW,eAAe;AAEjC,YAAO;;AAET,WAAO;;GAEV,GACD;EACL,CACF;AACD,KAAI,cACF,cAAa,KAAK,sBAAsB,QAAQ;AAElD,KAAI,oBAGF,cAAa,KAAK,EAChB,OAAO,SAAS;AACd,MAAI,KAAK,SAAS,aAAa,KAAK,SAAS,WAAW,EACtD,MAAK,SAAS,KAAK;GACjB,MAAM;GACN,SAAS;GACT,YAAY,EAAE;GACd,UAAU,EAAE;GACb,CAAC;AAEJ,SAAO;IAEV,CAAC;AAEJ,QAAO;EAAE;EAAO;EAAc;EAAS;;AAGzC,MAAM,UAAU,wBAAwB,EAAE,aAAa,OAAO,CAAC;AAI/D,MAAMC,uBAAyC;CAC7C,MAAM;CACN,OAAO,OAAO;AACZ,OAAK,MAAM,QAAQ,MACjB,MAAK,MAAM,SAAS,MAAM;AAExB,OAAI,MAAM,aAAa,KAAM;GAE7B,MAAMC,QAAgC,EAAE;AAExC,OAAI,MAAM,SAAS,KACjB,OAAM,QAAQ,MAAM;AAEtB,OAAI,MAAM,WAAW,KACnB,OAAM,sBAAsB,MAAM;AAEpC,OAAI,MAAM,aAAa,QAAQ,MAAM,cAAc,GAAG;AAEpD,SAAK,MAAM,YAAY,OAAO,EAC5B,OAAM,gBAAgB;AAExB,SAAK,MAAM,YAAY,OAAO,EAC5B,OAAM,iBAAiB;AAEzB,SAAK,MAAM,YAAY,OAAO,EAC5B,OAAM,qBAAqB;;AAK/B,OAAI,OAAO,KAAK,MAAM,CAAC,SAAS,EAC9B,OAAM,YAAY;;;CAK3B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } from "../constants.js";
|
|
2
|
-
import { getExpandedRegion
|
|
2
|
+
import { getExpandedRegion } from "./virtualDiffLayout.js";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/iterateOverDiff.ts
|
|
5
5
|
function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infinity, expandedHunks, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, callback }) {
|
|
@@ -11,12 +11,12 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
11
11
|
collapsedContextThreshold
|
|
12
12
|
});
|
|
13
13
|
const state = {
|
|
14
|
+
finalHunk: diff.hunks.at(-1),
|
|
14
15
|
viewportStart: startingLine,
|
|
15
16
|
viewportEnd: startingLine + totalLines,
|
|
16
17
|
isWindowedHighlight: startingLine > 0 || totalLines < Infinity,
|
|
17
18
|
splitCount: iterationStart.splitCount,
|
|
18
19
|
unifiedCount: iterationStart.unifiedCount,
|
|
19
|
-
finalHunkIndex: diff.hunks.length - 1,
|
|
20
20
|
shouldBreak() {
|
|
21
21
|
if (!state.isWindowedHighlight) return false;
|
|
22
22
|
const breakUnified = state.unifiedCount >= startingLine + totalLines;
|
|
@@ -69,24 +69,31 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
69
69
|
hunkIndex,
|
|
70
70
|
collapsedContextThreshold
|
|
71
71
|
});
|
|
72
|
-
const trailingRegion =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
const trailingRegion = (() => {
|
|
73
|
+
if (hunk !== state.finalHunk || !hasFinalCollapsedHunk(diff)) return;
|
|
74
|
+
const additionRemaining = diff.additionLines.length - (hunk.additionLineIndex + hunk.additionCount);
|
|
75
|
+
const deletionRemaining = diff.deletionLines.length - (hunk.deletionLineIndex + hunk.deletionCount);
|
|
76
|
+
if (additionRemaining !== deletionRemaining) throw new Error(`iterateOverDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${diff.name}`);
|
|
77
|
+
const trailingRangeSize = Math.min(additionRemaining, deletionRemaining);
|
|
78
|
+
return getExpandedRegion({
|
|
79
|
+
isPartial: diff.isPartial,
|
|
80
|
+
rangeSize: trailingRangeSize,
|
|
81
|
+
expandedHunks,
|
|
82
|
+
hunkIndex: diff.hunks.length,
|
|
83
|
+
collapsedContextThreshold
|
|
84
|
+
});
|
|
85
|
+
})();
|
|
79
86
|
const expandedLineCount = leadingRegion.fromStart + leadingRegion.fromEnd;
|
|
80
87
|
function getTrailingCollapsedAfter(unifiedLineIndex$1, splitLineIndex$1) {
|
|
81
88
|
if (trailingRegion == null || trailingRegion.collapsedLines <= 0 || trailingRegion.fromStart + trailingRegion.fromEnd > 0) return 0;
|
|
82
89
|
if (diffStyle === "unified") return unifiedLineIndex$1 === hunk.unifiedLineStart + hunk.unifiedLineCount - 1 ? trailingRegion.collapsedLines : 0;
|
|
83
90
|
return splitLineIndex$1 === hunk.splitLineStart + hunk.splitLineCount - 1 ? trailingRegion.collapsedLines : 0;
|
|
84
91
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return
|
|
92
|
+
function getPendingCollapsed() {
|
|
93
|
+
if (leadingRegion.collapsedLines === 0) return 0;
|
|
94
|
+
const value = leadingRegion.collapsedLines;
|
|
95
|
+
leadingRegion.collapsedLines = 0;
|
|
96
|
+
return value;
|
|
90
97
|
}
|
|
91
98
|
if (!state.shouldSkip(expandedLineCount, expandedLineCount)) {
|
|
92
99
|
let unifiedLineIndex$1 = hunk.unifiedLineStart - leadingRegion.rangeSize;
|
|
@@ -95,63 +102,81 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
95
102
|
let additionLineIndex$1 = hunk.additionLineIndex - leadingRegion.rangeSize;
|
|
96
103
|
let deletionLineNumber$1 = hunk.deletionStart - leadingRegion.rangeSize;
|
|
97
104
|
let additionLineNumber$1 = hunk.additionStart - leadingRegion.rangeSize;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
105
|
+
const [startIndex, endIndex] = getEqualLineIterationRange(state, leadingRegion.fromStart, diffStyle);
|
|
106
|
+
if (startIndex > 0) state.incrementCounts(startIndex, startIndex);
|
|
107
|
+
let index = startIndex;
|
|
108
|
+
while (index < leadingRegion.fromStart) {
|
|
109
|
+
if (index >= endIndex) {
|
|
110
|
+
state.incrementCounts(leadingRegion.fromStart - index, leadingRegion.fromStart - index);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (state.isInWindow(0, 0)) {
|
|
114
|
+
if (state.emit({
|
|
115
|
+
hunkIndex,
|
|
116
|
+
hunk,
|
|
117
|
+
collapsedBefore: 0,
|
|
118
|
+
collapsedAfter: 0,
|
|
119
|
+
type: "context-expanded",
|
|
120
|
+
deletionLine: {
|
|
121
|
+
lineNumber: deletionLineNumber$1 + index,
|
|
122
|
+
lineIndex: deletionLineIndex$1 + index,
|
|
123
|
+
noEOFCR: false,
|
|
124
|
+
unifiedLineIndex: unifiedLineIndex$1 + index,
|
|
125
|
+
splitLineIndex: splitLineIndex$1 + index
|
|
126
|
+
},
|
|
127
|
+
additionLine: {
|
|
128
|
+
unifiedLineIndex: unifiedLineIndex$1 + index,
|
|
129
|
+
splitLineIndex: splitLineIndex$1 + index,
|
|
130
|
+
lineIndex: additionLineIndex$1 + index,
|
|
131
|
+
lineNumber: additionLineNumber$1 + index,
|
|
132
|
+
noEOFCR: false
|
|
133
|
+
}
|
|
134
|
+
})) break hunkIterator;
|
|
135
|
+
} else state.incrementCounts(1, 1);
|
|
136
|
+
index++;
|
|
137
|
+
}
|
|
121
138
|
unifiedLineIndex$1 = hunk.unifiedLineStart - leadingRegion.fromEnd;
|
|
122
139
|
splitLineIndex$1 = hunk.splitLineStart - leadingRegion.fromEnd;
|
|
123
140
|
deletionLineIndex$1 = hunk.deletionLineIndex - leadingRegion.fromEnd;
|
|
124
141
|
additionLineIndex$1 = hunk.additionLineIndex - leadingRegion.fromEnd;
|
|
125
142
|
deletionLineNumber$1 = hunk.deletionStart - leadingRegion.fromEnd;
|
|
126
143
|
additionLineNumber$1 = hunk.additionStart - leadingRegion.fromEnd;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
const [fromEndStartIndex, fromEndEndIndex] = getEqualLineIterationRange(state, leadingRegion.fromEnd, diffStyle);
|
|
145
|
+
if (fromEndStartIndex > 0) state.incrementCounts(fromEndStartIndex, fromEndStartIndex);
|
|
146
|
+
index = fromEndStartIndex;
|
|
147
|
+
while (index < leadingRegion.fromEnd) {
|
|
148
|
+
if (index >= fromEndEndIndex) {
|
|
149
|
+
state.incrementCounts(leadingRegion.fromEnd - index, leadingRegion.fromEnd - index);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
if (state.isInWindow(0, 0)) {
|
|
153
|
+
if (state.emit({
|
|
154
|
+
hunkIndex,
|
|
155
|
+
hunk,
|
|
156
|
+
collapsedBefore: getPendingCollapsed(),
|
|
157
|
+
collapsedAfter: 0,
|
|
158
|
+
type: "context-expanded",
|
|
159
|
+
deletionLine: {
|
|
160
|
+
lineNumber: deletionLineNumber$1 + index,
|
|
161
|
+
lineIndex: deletionLineIndex$1 + index,
|
|
162
|
+
noEOFCR: false,
|
|
163
|
+
unifiedLineIndex: unifiedLineIndex$1 + index,
|
|
164
|
+
splitLineIndex: splitLineIndex$1 + index
|
|
165
|
+
},
|
|
166
|
+
additionLine: {
|
|
167
|
+
unifiedLineIndex: unifiedLineIndex$1 + index,
|
|
168
|
+
splitLineIndex: splitLineIndex$1 + index,
|
|
169
|
+
lineIndex: additionLineIndex$1 + index,
|
|
170
|
+
lineNumber: additionLineNumber$1 + index,
|
|
171
|
+
noEOFCR: false
|
|
172
|
+
}
|
|
173
|
+
})) break hunkIterator;
|
|
174
|
+
} else state.incrementCounts(1, 1);
|
|
175
|
+
index++;
|
|
176
|
+
}
|
|
152
177
|
} else {
|
|
153
178
|
state.incrementCounts(expandedLineCount, expandedLineCount);
|
|
154
|
-
|
|
179
|
+
getPendingCollapsed();
|
|
155
180
|
}
|
|
156
181
|
let unifiedLineIndex = hunk.unifiedLineStart;
|
|
157
182
|
let splitLineIndex = hunk.splitLineStart;
|
|
@@ -165,37 +190,45 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
165
190
|
const isLastContent = content === lastContent;
|
|
166
191
|
if (content.type === "context") {
|
|
167
192
|
if (!state.shouldSkip(content.lines, content.lines)) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
const [startIndex, endIndex] = getEqualLineIterationRange(state, content.lines, diffStyle);
|
|
194
|
+
if (startIndex > 0) state.incrementCounts(startIndex, startIndex);
|
|
195
|
+
let index = startIndex;
|
|
196
|
+
while (index < content.lines) {
|
|
197
|
+
if (index >= endIndex) {
|
|
198
|
+
state.incrementCounts(content.lines - index, content.lines - index);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
if (state.isInWindow(0, 0)) {
|
|
202
|
+
const isLastLine = isLastContent && index === content.lines - 1;
|
|
203
|
+
const unifiedRowIndex = unifiedLineIndex + index;
|
|
204
|
+
const splitRowIndex = splitLineIndex + index;
|
|
205
|
+
if (state.emit({
|
|
206
|
+
hunkIndex,
|
|
207
|
+
hunk,
|
|
208
|
+
collapsedBefore: getPendingCollapsed(),
|
|
209
|
+
collapsedAfter: getTrailingCollapsedAfter(unifiedRowIndex, splitRowIndex),
|
|
210
|
+
type: "context",
|
|
211
|
+
deletionLine: {
|
|
212
|
+
lineNumber: deletionLineNumber + index,
|
|
213
|
+
lineIndex: deletionLineIndex + index,
|
|
214
|
+
noEOFCR: isLastLine && hunk.noEOFCRDeletions,
|
|
215
|
+
unifiedLineIndex: unifiedRowIndex,
|
|
216
|
+
splitLineIndex: splitRowIndex
|
|
217
|
+
},
|
|
218
|
+
additionLine: {
|
|
219
|
+
unifiedLineIndex: unifiedRowIndex,
|
|
220
|
+
splitLineIndex: splitRowIndex,
|
|
221
|
+
lineIndex: additionLineIndex + index,
|
|
222
|
+
lineNumber: additionLineNumber + index,
|
|
223
|
+
noEOFCR: isLastLine && hunk.noEOFCRAdditions
|
|
224
|
+
}
|
|
225
|
+
})) break hunkIterator;
|
|
226
|
+
} else state.incrementCounts(1, 1);
|
|
227
|
+
index++;
|
|
228
|
+
}
|
|
196
229
|
} else {
|
|
197
230
|
state.incrementCounts(content.lines, content.lines);
|
|
198
|
-
|
|
231
|
+
getPendingCollapsed();
|
|
199
232
|
}
|
|
200
233
|
unifiedLineIndex += content.lines;
|
|
201
234
|
splitLineIndex += content.lines;
|
|
@@ -208,13 +241,12 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
208
241
|
const unifiedCount = content.deletions + content.additions;
|
|
209
242
|
if (!state.shouldSkip(unifiedCount, splitCount)) {
|
|
210
243
|
const iterationRanges = getChangeIterationRanges(state, content, diffStyle);
|
|
211
|
-
if ((iterationRanges[0]?.[0] ?? 0) > 0) consumePendingCollapsed();
|
|
212
244
|
for (const [rangeStart, rangeEnd] of iterationRanges) for (let index = rangeStart; index < rangeEnd; index++) {
|
|
213
245
|
const collapsedAfter = getTrailingCollapsedAfter(unifiedLineIndex + index, diffStyle === "unified" ? splitLineIndex + (index < content.deletions ? index : index - content.deletions) : splitLineIndex + index);
|
|
214
246
|
if (state.emit(getChangeLineData({
|
|
215
247
|
hunkIndex,
|
|
216
248
|
hunk,
|
|
217
|
-
collapsedBefore:
|
|
249
|
+
collapsedBefore: getPendingCollapsed(),
|
|
218
250
|
collapsedAfter,
|
|
219
251
|
diffStyle,
|
|
220
252
|
index,
|
|
@@ -231,7 +263,7 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
231
263
|
}), true)) break hunkIterator;
|
|
232
264
|
}
|
|
233
265
|
}
|
|
234
|
-
|
|
266
|
+
getPendingCollapsed();
|
|
235
267
|
state.incrementCounts(unifiedCount, splitCount);
|
|
236
268
|
unifiedLineIndex += unifiedCount;
|
|
237
269
|
splitLineIndex += splitCount;
|
|
@@ -244,30 +276,41 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
|
|
|
244
276
|
if (trailingRegion != null) {
|
|
245
277
|
const { collapsedLines, fromStart, fromEnd } = trailingRegion;
|
|
246
278
|
const len = fromStart + fromEnd;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
279
|
+
const [startIndex, endIndex] = getEqualLineIterationRange(state, len, diffStyle);
|
|
280
|
+
if (startIndex > 0) state.incrementCounts(startIndex, startIndex);
|
|
281
|
+
let index = startIndex;
|
|
282
|
+
while (index < len) {
|
|
283
|
+
if (state.shouldBreak()) break hunkIterator;
|
|
284
|
+
if (index >= endIndex) {
|
|
285
|
+
state.incrementCounts(len - index, len - index);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
if (state.isInWindow(0, 0)) {
|
|
289
|
+
const isLastLine = index === len - 1;
|
|
290
|
+
if (state.emit({
|
|
291
|
+
hunkIndex: diff.hunks.length,
|
|
292
|
+
hunk: void 0,
|
|
293
|
+
collapsedBefore: 0,
|
|
294
|
+
collapsedAfter: isLastLine ? collapsedLines : 0,
|
|
295
|
+
type: "context-expanded",
|
|
296
|
+
deletionLine: {
|
|
297
|
+
lineNumber: deletionLineNumber + index,
|
|
298
|
+
lineIndex: deletionLineIndex + index,
|
|
299
|
+
noEOFCR: false,
|
|
300
|
+
unifiedLineIndex: unifiedLineIndex + index,
|
|
301
|
+
splitLineIndex: splitLineIndex + index
|
|
302
|
+
},
|
|
303
|
+
additionLine: {
|
|
304
|
+
unifiedLineIndex: unifiedLineIndex + index,
|
|
305
|
+
splitLineIndex: splitLineIndex + index,
|
|
306
|
+
lineIndex: additionLineIndex + index,
|
|
307
|
+
lineNumber: additionLineNumber + index,
|
|
308
|
+
noEOFCR: false
|
|
309
|
+
}
|
|
310
|
+
})) break hunkIterator;
|
|
311
|
+
} else state.incrementCounts(1, 1);
|
|
312
|
+
index++;
|
|
313
|
+
}
|
|
271
314
|
}
|
|
272
315
|
}
|
|
273
316
|
}
|
|
@@ -332,14 +375,15 @@ function getHunkPrefixCounts({ diff, expandedHunks, collapsedContextThreshold })
|
|
|
332
375
|
const leadingCount = leadingRegion.fromStart + leadingRegion.fromEnd;
|
|
333
376
|
splitCount += leadingCount + hunk.splitLineCount;
|
|
334
377
|
unifiedCount += leadingCount + hunk.unifiedLineCount;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
378
|
+
if (index === finalHunkIndex && hasFinalCollapsedHunk(diff)) {
|
|
379
|
+
const trailingRangeSize = getTrailingRangeSize(diff, hunk);
|
|
380
|
+
const trailingRegion = getExpandedRegion({
|
|
381
|
+
isPartial: diff.isPartial,
|
|
382
|
+
rangeSize: trailingRangeSize,
|
|
383
|
+
expandedHunks,
|
|
384
|
+
hunkIndex: diff.hunks.length,
|
|
385
|
+
collapsedContextThreshold
|
|
386
|
+
});
|
|
343
387
|
const trailingCount = trailingRegion.fromStart + trailingRegion.fromEnd;
|
|
344
388
|
splitCount += trailingCount;
|
|
345
389
|
unifiedCount += trailingCount;
|
|
@@ -351,7 +395,7 @@ function getHunkPrefixCounts({ diff, expandedHunks, collapsedContextThreshold })
|
|
|
351
395
|
}
|
|
352
396
|
return prefixCounts;
|
|
353
397
|
}
|
|
354
|
-
function
|
|
398
|
+
function getEqualLineIterationRange(state, count, diffStyle) {
|
|
355
399
|
if (!state.isWindowedHighlight || count <= 0) return [0, count];
|
|
356
400
|
const ranges = [];
|
|
357
401
|
function pushRange(currentCount) {
|
|
@@ -371,25 +415,16 @@ function getContextLineIterationBounds(state, count, diffStyle) {
|
|
|
371
415
|
}
|
|
372
416
|
return [start, end];
|
|
373
417
|
}
|
|
374
|
-
function
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
state.incrementCounts(count - index, count - index);
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
if (state.isInWindow(0, 0)) {
|
|
388
|
-
if (callback(index) === true) return true;
|
|
389
|
-
} else state.incrementCounts(1, 1);
|
|
390
|
-
index++;
|
|
391
|
-
}
|
|
392
|
-
return false;
|
|
418
|
+
function getTrailingRangeSize(diff, hunk) {
|
|
419
|
+
const additionRemaining = diff.additionLines.length - (hunk.additionLineIndex + hunk.additionCount);
|
|
420
|
+
const deletionRemaining = diff.deletionLines.length - (hunk.deletionLineIndex + hunk.deletionCount);
|
|
421
|
+
if (additionRemaining !== deletionRemaining) throw new Error(`iterateOverDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${diff.name}`);
|
|
422
|
+
return Math.min(additionRemaining, deletionRemaining);
|
|
423
|
+
}
|
|
424
|
+
function hasFinalCollapsedHunk(diff) {
|
|
425
|
+
const lastHunk = diff.hunks.at(-1);
|
|
426
|
+
if (lastHunk == null || diff.isPartial || diff.additionLines.length === 0 || diff.deletionLines.length === 0) return false;
|
|
427
|
+
return lastHunk.additionLineIndex + lastHunk.additionCount < diff.additionLines.length || lastHunk.deletionLineIndex + lastHunk.deletionCount < diff.deletionLines.length;
|
|
393
428
|
}
|
|
394
429
|
function getChangeIterationRanges(state, content, diffStyle) {
|
|
395
430
|
if (!state.isWindowedHighlight) return [[0, diffStyle === "unified" ? content.deletions + content.additions : Math.max(content.deletions, content.additions)]];
|