@pierre/diffs 1.6.0-beta.1 → 1.6.0
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 +3 -2
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +18 -14
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +31 -9
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +165 -84
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +32 -9
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +213 -124
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts +14 -4
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +35 -16
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +3 -2
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +28 -20
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +3 -2
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +31 -24
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/constants.d.ts +2 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/editor/platform.d.ts +1 -1
- package/dist/editor/platform.js +5 -4
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/selection.d.ts +2 -2
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +31 -6
- package/dist/editor/selection.js.map +1 -1
- package/dist/highlighter/shared_highlighter.d.ts +2 -1
- package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.js +2 -2
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.js +8 -3
- package/dist/react/CodeView.d.ts +4 -3
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +48 -39
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/File.js +3 -3
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.js +3 -3
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.js +2 -2
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.js +3 -3
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.js +2 -2
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/types.d.ts +4 -2
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +1 -1
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.js +1 -1
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +1 -0
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +29 -24
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +2 -0
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +38 -28
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useForceUpdate.d.ts +5 -0
- package/dist/react/utils/useForceUpdate.d.ts.map +1 -0
- package/dist/react/utils/useForceUpdate.js +27 -0
- package/dist/react/utils/useForceUpdate.js.map +1 -0
- package/dist/react/utils/useNextRenderData.d.ts +9 -0
- package/dist/react/utils/useNextRenderData.d.ts.map +1 -0
- package/dist/react/utils/useNextRenderData.js +9 -0
- package/dist/react/utils/useNextRenderData.js.map +1 -0
- package/dist/react/utils/useUnresolvedFileInstance.d.ts +1 -0
- package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +26 -11
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +2 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +62 -32
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +4 -1
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +55 -30
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
- package/dist/ssr/FileDiffReact.js +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/canUseWASM.d.ts +13 -0
- package/dist/utils/canUseWASM.d.ts.map +1 -0
- package/dist/utils/canUseWASM.js +59 -0
- package/dist/utils/canUseWASM.js.map +1 -0
- package/dist/utils/getCodeViewItemRenderData.d.ts +10 -0
- package/dist/utils/getCodeViewItemRenderData.d.ts.map +1 -0
- package/dist/utils/getCodeViewItemRenderData.js +19 -0
- package/dist/utils/getCodeViewItemRenderData.js.map +1 -0
- package/dist/utils/hastToHtml.d.ts +2 -2
- package/dist/utils/hastToHtml.js +2 -2
- package/dist/utils/hastToHtml.js.map +1 -1
- package/dist/utils/hydratePartialDiff.js +4 -0
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +2 -0
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +24 -4
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/renderTokenLines.d.ts +6 -1
- package/dist/utils/renderTokenLines.d.ts.map +1 -1
- package/dist/utils/renderTokenLines.js +4 -0
- package/dist/utils/renderTokenLines.js.map +1 -1
- package/dist/utils/resolveRegion.js +20 -10
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/tokenStyle.d.ts +5 -1
- package/dist/utils/tokenStyle.d.ts.map +1 -1
- package/dist/utils/tokenStyle.js +5 -1
- package/dist/utils/tokenStyle.js.map +1 -1
- package/dist/utils/tokensToHtml.d.ts +5 -2
- package/dist/utils/tokensToHtml.d.ts.map +1 -1
- package/dist/utils/tokensToHtml.js +5 -2
- package/dist/utils/tokensToHtml.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +2 -2
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +7 -3
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +12 -0
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +99 -21
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/{highlights-sAHlxqlf.js → highlights-CpZm9DAR.js} +2 -2
- package/dist/worker/{highlights-sAHlxqlf.js.map → highlights-CpZm9DAR.js.map} +1 -1
- package/dist/worker/{shiki-Bx2JpdqZ.js → shiki-Ci4cdHsM.js} +2 -2
- package/dist/worker/{shiki-Bx2JpdqZ.js.map → shiki-Ci4cdHsM.js.map} +1 -1
- package/dist/worker/{stream-tokenizer-YZ6M1qSx.js → stream-tokenizer-DK9xp5M5.js} +8 -5
- package/dist/worker/stream-tokenizer-DK9xp5M5.js.map +1 -0
- package/dist/worker/types.d.ts +11 -0
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/worker-portable.js +2 -2
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +12 -3
- package/dist/worker/worker.js.map +1 -1
- package/package.json +28 -30
- package/dist/worker/stream-tokenizer-YZ6M1qSx.js.map +0 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { ThemedToken } from "../highlighter/types.js";
|
|
2
2
|
import "../types.js";
|
|
3
3
|
//#region src/utils/tokenStyle.d.ts
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Returns CSS declarations for a highlighted token. Enable caching only when
|
|
6
|
+
* htmlStyle objects are immutable and reused across tokens.
|
|
7
|
+
*/
|
|
8
|
+
declare function tokenStyle(token: ThemedToken, cacheHtmlStyle?: boolean): string;
|
|
5
9
|
//#endregion
|
|
6
10
|
export { tokenStyle };
|
|
7
11
|
//# sourceMappingURL=tokenStyle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenStyle.d.ts","names":[],"sources":["../../src/utils/tokenStyle.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tokenStyle.d.ts","names":[],"sources":["../../src/utils/tokenStyle.ts"],"mappings":";;;;;;;iBAUgB,WACd,OAAO,aACP"}
|
package/dist/utils/tokenStyle.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
//#region src/utils/tokenStyle.ts
|
|
2
2
|
const htmlStyleCache = /* @__PURE__ */ new WeakMap();
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Returns CSS declarations for a highlighted token. Enable caching only when
|
|
5
|
+
* htmlStyle objects are immutable and reused across tokens.
|
|
6
|
+
*/
|
|
7
|
+
function tokenStyle(token, cacheHtmlStyle = false) {
|
|
4
8
|
const { htmlStyle } = token;
|
|
5
9
|
if (htmlStyle != null) {
|
|
6
10
|
let style = cacheHtmlStyle ? htmlStyleCache.get(htmlStyle) : void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenStyle.js","names":[],"sources":["../../src/utils/tokenStyle.ts"],"sourcesContent":["import type { ThemedToken } from '../types';\n\n// Warning: cache only tokens from Highlights, which reuses htmlStyle objects.\n// Shiki creates one per token, so caching them adds a WeakMap entry per token.\nconst htmlStyleCache = new WeakMap<Record<string, string>, string>();\n\nexport function tokenStyle(\n token: ThemedToken,\n cacheHtmlStyle: boolean\n): string {\n const { htmlStyle } = token;\n if (htmlStyle != null) {\n let style = cacheHtmlStyle ? htmlStyleCache.get(htmlStyle) : undefined;\n if (style == null) {\n style = '';\n for (const name in htmlStyle) {\n style += `${style === '' ? '' : ';'}${name}:${htmlStyle[name]}`;\n }\n if (cacheHtmlStyle) htmlStyleCache.set(htmlStyle, style);\n }\n return style;\n }\n let style = token.color != null ? `color:${token.color}` : '';\n if (token.bgColor != null) style += `;background-color:${token.bgColor}`;\n if (token.fontStyle != null) {\n if ((token.fontStyle & 1) !== 0) style += ';font-style:italic';\n if ((token.fontStyle & 2) !== 0) style += ';font-weight:bold';\n const underline = (token.fontStyle & 4) !== 0;\n const strikethrough = (token.fontStyle & 8) !== 0;\n if (underline || strikethrough)\n style += `;text-decoration:${underline ? 'underline' : ''}${underline && strikethrough ? ' ' : ''}${strikethrough ? 'line-through' : ''}`;\n }\n return style.replace(/^;/, '');\n}\n"],"mappings":";AAIA,MAAM,iCAAiB,IAAI,QAAwC
|
|
1
|
+
{"version":3,"file":"tokenStyle.js","names":[],"sources":["../../src/utils/tokenStyle.ts"],"sourcesContent":["import type { ThemedToken } from '../types';\n\n// Warning: cache only tokens from Highlights, which reuses htmlStyle objects.\n// Shiki creates one per token, so caching them adds a WeakMap entry per token.\nconst htmlStyleCache = new WeakMap<Record<string, string>, string>();\n\n/**\n * Returns CSS declarations for a highlighted token. Enable caching only when\n * htmlStyle objects are immutable and reused across tokens.\n */\nexport function tokenStyle(\n token: ThemedToken,\n cacheHtmlStyle: boolean = false\n): string {\n const { htmlStyle } = token;\n if (htmlStyle != null) {\n let style = cacheHtmlStyle ? htmlStyleCache.get(htmlStyle) : undefined;\n if (style == null) {\n style = '';\n for (const name in htmlStyle) {\n style += `${style === '' ? '' : ';'}${name}:${htmlStyle[name]}`;\n }\n if (cacheHtmlStyle) htmlStyleCache.set(htmlStyle, style);\n }\n return style;\n }\n let style = token.color != null ? `color:${token.color}` : '';\n if (token.bgColor != null) style += `;background-color:${token.bgColor}`;\n if (token.fontStyle != null) {\n if ((token.fontStyle & 1) !== 0) style += ';font-style:italic';\n if ((token.fontStyle & 2) !== 0) style += ';font-weight:bold';\n const underline = (token.fontStyle & 4) !== 0;\n const strikethrough = (token.fontStyle & 8) !== 0;\n if (underline || strikethrough)\n style += `;text-decoration:${underline ? 'underline' : ''}${underline && strikethrough ? ' ' : ''}${strikethrough ? 'line-through' : ''}`;\n }\n return style.replace(/^;/, '');\n}\n"],"mappings":";AAIA,MAAM,iCAAiB,IAAI,QAAwC;;;;;AAMnE,SAAgB,WACd,OACA,iBAA0B,OAClB;CACR,MAAM,EAAE,cAAc;CACtB,IAAI,aAAa,MAAM;EACrB,IAAI,QAAQ,iBAAiB,eAAe,IAAI,SAAS,IAAI,KAAA;EAC7D,IAAI,SAAS,MAAM;GACjB,QAAQ;GACR,KAAK,MAAM,QAAQ,WACjB,SAAS,GAAG,UAAU,KAAK,KAAK,MAAM,KAAK,GAAG,UAAU;GAE1D,IAAI,gBAAgB,eAAe,IAAI,WAAW,KAAK;EACzD;EACA,OAAO;CACT;CACA,IAAI,QAAQ,MAAM,SAAS,OAAO,SAAS,MAAM,UAAU;CAC3D,IAAI,MAAM,WAAW,MAAM,SAAS,qBAAqB,MAAM;CAC/D,IAAI,MAAM,aAAa,MAAM;EAC3B,KAAK,MAAM,YAAY,OAAO,GAAG,SAAS;EAC1C,KAAK,MAAM,YAAY,OAAO,GAAG,SAAS;EAC1C,MAAM,aAAa,MAAM,YAAY,OAAO;EAC5C,MAAM,iBAAiB,MAAM,YAAY,OAAO;EAChD,IAAI,aAAa,eACf,SAAS,oBAAoB,YAAY,cAAc,KAAK,aAAa,gBAAgB,MAAM,KAAK,gBAAgB,iBAAiB;CACzI;CACA,OAAO,MAAM,QAAQ,MAAM,EAAE;AAC/B"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { CodeToHtmlOptions, TokensResult } from "../highlighter/types.js";
|
|
2
2
|
import "../types.js";
|
|
3
3
|
//#region src/utils/tokensToHtml.d.ts
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Renders existing tokens as a pre/code HTML block without highlighting again.
|
|
6
|
+
* Pass the original source to resolve numeric decoration offsets.
|
|
7
|
+
*/
|
|
8
|
+
declare function tokensToHtml(source: string, result: TokensResult, options: CodeToHtmlOptions, cacheHtmlStyles?: boolean): string;
|
|
6
9
|
//#endregion
|
|
7
10
|
export { tokensToHtml };
|
|
8
11
|
//# sourceMappingURL=tokensToHtml.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokensToHtml.d.ts","names":[],"sources":["../../src/utils/tokensToHtml.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tokensToHtml.d.ts","names":[],"sources":["../../src/utils/tokensToHtml.ts"],"mappings":";;;;;;;iBAUgB,aACd,gBACA,QAAQ,cACR,SAAS,mBACT"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { hastToHtml } from "./hastToHtml.js";
|
|
2
2
|
import { renderTokenLines } from "./renderTokenLines.js";
|
|
3
3
|
//#region src/utils/tokensToHtml.ts
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Renders existing tokens as a pre/code HTML block without highlighting again.
|
|
6
|
+
* Pass the original source to resolve numeric decoration offsets.
|
|
7
|
+
*/
|
|
8
|
+
function tokensToHtml(source, result, options, cacheHtmlStyles = false) {
|
|
6
9
|
const lineOffsets = [0];
|
|
7
10
|
if (options.decorations?.some((item) => typeof item.start === "number" || typeof item.end === "number") === true) for (let index = source.indexOf("\n"); index !== -1; index = source.indexOf("\n", index + 1)) lineOffsets.push(index + 1);
|
|
8
11
|
const code = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokensToHtml.js","names":[],"sources":["../../src/utils/tokensToHtml.ts"],"sourcesContent":["import type { Element, Root } from 'hast';\n\nimport type { CodeToHtmlOptions, TokensResult } from '../types';\nimport { hastToHtml } from './hastToHtml';\nimport { renderTokenLines } from './renderTokenLines';\n\n
|
|
1
|
+
{"version":3,"file":"tokensToHtml.js","names":[],"sources":["../../src/utils/tokensToHtml.ts"],"sourcesContent":["import type { Element, Root } from 'hast';\n\nimport type { CodeToHtmlOptions, TokensResult } from '../types';\nimport { hastToHtml } from './hastToHtml';\nimport { renderTokenLines } from './renderTokenLines';\n\n/**\n * Renders existing tokens as a pre/code HTML block without highlighting again.\n * Pass the original source to resolve numeric decoration offsets.\n */\nexport function tokensToHtml(\n source: string,\n result: TokensResult,\n options: CodeToHtmlOptions,\n cacheHtmlStyles: boolean = false\n): string {\n const lineOffsets = [0];\n if (\n options.decorations?.some(\n (item) => typeof item.start === 'number' || typeof item.end === 'number'\n ) === true\n ) {\n for (\n let index = source.indexOf('\\n');\n index !== -1;\n index = source.indexOf('\\n', index + 1)\n )\n lineOffsets.push(index + 1);\n }\n const code: Element = {\n type: 'element',\n tagName: 'code',\n properties: {},\n children: [],\n };\n const lines = renderTokenLines(result.tokens, {\n decorations: options.decorations,\n mergeWhitespaces: options.mergeWhitespaces,\n lineOffsets,\n cacheHtmlStyles,\n });\n for (let i = 0; i < lines.length; i++) {\n if (i > 0) code.children.push({ type: 'text', value: '\\n' });\n code.children.push(lines[i]);\n }\n const root: Root = {\n type: 'root',\n children: [\n {\n type: 'element',\n tagName: 'pre',\n properties: {\n class: 'diffs',\n style:\n result.rootStyle === false\n ? undefined\n : (result.rootStyle ??\n [\n result.fg != null ? `color:${result.fg}` : '',\n result.bg != null ? `background-color:${result.bg}` : '',\n ]\n .filter(Boolean)\n .join(';')),\n tabIndex: 0,\n },\n children: [code],\n },\n ],\n };\n return hastToHtml(root);\n}\n"],"mappings":";;;;;;;AAUA,SAAgB,aACd,QACA,QACA,SACA,kBAA2B,OACnB;CACR,MAAM,cAAc,CAAC,CAAC;CACtB,IACE,QAAQ,aAAa,MAClB,SAAS,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,QAAQ,QAClE,MAAM,MAEN,KACE,IAAI,QAAQ,OAAO,QAAQ,IAAI,GAC/B,UAAU,IACV,QAAQ,OAAO,QAAQ,MAAM,QAAQ,CAAC,GAEtC,YAAY,KAAK,QAAQ,CAAC;CAE9B,MAAM,OAAgB;EACpB,MAAM;EACN,SAAS;EACT,YAAY,CAAC;EACb,UAAU,CAAC;CACb;CACA,MAAM,QAAQ,iBAAiB,OAAO,QAAQ;EAC5C,aAAa,QAAQ;EACrB,kBAAkB,QAAQ;EAC1B;EACA;CACF,CAAC;CACD,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,IAAI,IAAI,GAAG,KAAK,SAAS,KAAK;GAAE,MAAM;GAAQ,OAAO;EAAK,CAAC;EAC3D,KAAK,SAAS,KAAK,MAAM,EAAE;CAC7B;CACA,MAAM,OAAa;EACjB,MAAM;EACN,UAAU,CACR;GACE,MAAM;GACN,SAAS;GACT,YAAY;IACV,OAAO;IACP,OACE,OAAO,cAAc,QACjB,KAAA,IACC,OAAO,aACR,CACE,OAAO,MAAM,OAAO,SAAS,OAAO,OAAO,IAC3C,OAAO,MAAM,OAAO,oBAAoB,OAAO,OAAO,EACxD,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;IACjB,UAAU;GACZ;GACA,UAAU,CAAC,IAAI;EACjB,CACF;CACF;CACA,OAAO,WAAW,IAAI;AACxB"}
|
|
@@ -3,11 +3,11 @@ import { CreatePatchOptionsNonabortable } from "diff";
|
|
|
3
3
|
//#region src/utils/updateDiffHunks.d.ts
|
|
4
4
|
type HunkContent = ContextContent | ChangeContent;
|
|
5
5
|
type HunkMetadataUpdate = Pick<FileDiffMetadata, 'hunks' | 'splitLineCount' | 'unifiedLineCount' | 'type'>;
|
|
6
|
-
type FullDiffHunkUpdate = HunkMetadataUpdate & Pick<FileDiffMetadata, 'additionLines' | 'deletionLines'>;
|
|
6
|
+
type FullDiffHunkUpdate = HunkMetadataUpdate & Pick<FileDiffMetadata, 'additionLines' | 'deletionLines' | 'additionCharacterCount' | 'deletionCharacterCount'>;
|
|
7
7
|
/** Rebuilds all hunk metadata from the current deletion/addition line arrays. */
|
|
8
8
|
declare function recomputeDiffHunks(diff: FileDiffMetadata, parseDiffOptions?: CreatePatchOptionsNonabortable): FullDiffHunkUpdate;
|
|
9
9
|
declare function shouldTopAlignAdditionRecompute(diff: FileDiffMetadata, additionLines: string[]): boolean;
|
|
10
|
-
declare function recomputeTopAlignedAdditionDiff(diff: FileDiffMetadata, additionLines: string[], parseDiffOptions?: CreatePatchOptionsNonabortable): FullDiffHunkUpdate;
|
|
10
|
+
declare function recomputeTopAlignedAdditionDiff(diff: FileDiffMetadata, additionLines: string[], additionCharacterCount: number, parseDiffOptions?: CreatePatchOptionsNonabortable): FullDiffHunkUpdate;
|
|
11
11
|
declare function recomputeEmptyDocumentDiff(diff: FileDiffMetadata, parseDiffOptions?: CreatePatchOptionsNonabortable): FullDiffHunkUpdate;
|
|
12
12
|
/** Rebuilds diff hunks after an edit, top-aligning sparse addition sides when needed. */
|
|
13
13
|
declare function recomputeDiffHunksForEdit(diff: FileDiffMetadata, parseDiffOptions?: CreatePatchOptionsNonabortable): FullDiffHunkUpdate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateDiffHunks.d.ts","names":[],"sources":["../../src/utils/updateDiffHunks.ts"],"mappings":";;;KAgBK,cAAc,iBAAiB;KAE/B,qBAAqB,KACxB;KAIG,qBAAqB,qBACxB,
|
|
1
|
+
{"version":3,"file":"updateDiffHunks.d.ts","names":[],"sources":["../../src/utils/updateDiffHunks.ts"],"mappings":";;;KAgBK,cAAc,iBAAiB;KAE/B,qBAAqB,KACxB;KAIG,qBAAqB,qBACxB,KACE;;iBAQY,mBACd,MAAM,kBACN,mBAAmB,iCAClB;iBA0Da,gCACd,MAAM,kBACN;iBAYc,gCACd,MAAM,kBACN,yBACA,gCACA,mBAAmB,iCAClB;iBAoCa,2BACd,MAAM,kBACN,mBAAmB,iCAClB;;iBAKa,0BACd,MAAM,kBACN,mBAAmB,iCAClB;iBAyBa,gCACd,YAAY,KACV,wFAGF;;iBAyCc,gBACd,MAAM,kBACN,4BAA4B,kBAC5B,mBAAmB,iCAClB;iBA2Ja,4BACd,MAAM,kBACN;iBAiDc,kBACd,SAAS,aACT,wBACA,yBACC;iBAQa,8BAA8B,MAAM;iBAkBpC,8BACd,MAAM,KACJ"}
|
|
@@ -19,6 +19,8 @@ function recomputeDiffHunks(diff, parseDiffOptions) {
|
|
|
19
19
|
unifiedLineCount: recomputed.unifiedLineCount,
|
|
20
20
|
additionLines: recomputed.additionLines,
|
|
21
21
|
deletionLines: recomputed.deletionLines,
|
|
22
|
+
additionCharacterCount: recomputed.additionCharacterCount,
|
|
23
|
+
deletionCharacterCount: recomputed.deletionCharacterCount,
|
|
22
24
|
type: recomputed.type
|
|
23
25
|
};
|
|
24
26
|
}
|
|
@@ -35,7 +37,7 @@ function hasOnlyBlankAdditionContents(additionLines) {
|
|
|
35
37
|
function shouldTopAlignAdditionRecompute(diff, additionLines) {
|
|
36
38
|
return additionLines.length > 0 && additionLines.length < diff.deletionLines.length && hasOnlyBlankAdditionContents(additionLines);
|
|
37
39
|
}
|
|
38
|
-
function recomputeTopAlignedAdditionDiff(diff, additionLines, parseDiffOptions) {
|
|
40
|
+
function recomputeTopAlignedAdditionDiff(diff, additionLines, additionCharacterCount, parseDiffOptions) {
|
|
39
41
|
const deletionContents = diff.deletionLines.join("");
|
|
40
42
|
const additionSentinel = buildTopAlignedAdditionSentinel(additionLines.length, deletionContents);
|
|
41
43
|
const recomputed = parseDiffFromFile({
|
|
@@ -52,16 +54,18 @@ function recomputeTopAlignedAdditionDiff(diff, additionLines, parseDiffOptions)
|
|
|
52
54
|
unifiedLineCount: recomputed.unifiedLineCount,
|
|
53
55
|
additionLines,
|
|
54
56
|
deletionLines: recomputed.deletionLines,
|
|
57
|
+
additionCharacterCount,
|
|
58
|
+
deletionCharacterCount: recomputed.deletionCharacterCount,
|
|
55
59
|
type: recomputed.type
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
function recomputeEmptyDocumentDiff(diff, parseDiffOptions) {
|
|
59
|
-
return recomputeTopAlignedAdditionDiff(diff, [""], parseDiffOptions);
|
|
63
|
+
return recomputeTopAlignedAdditionDiff(diff, [""], 0, parseDiffOptions);
|
|
60
64
|
}
|
|
61
65
|
/** Rebuilds diff hunks after an edit, top-aligning sparse addition sides when needed. */
|
|
62
66
|
function recomputeDiffHunksForEdit(diff, parseDiffOptions) {
|
|
63
67
|
if (diff.additionLines.length === 0) return recomputeEmptyDocumentDiff(diff, parseDiffOptions);
|
|
64
|
-
if (shouldTopAlignAdditionRecompute(diff, diff.additionLines)) return recomputeTopAlignedAdditionDiff(diff, diff.additionLines, parseDiffOptions);
|
|
68
|
+
if (shouldTopAlignAdditionRecompute(diff, diff.additionLines)) return recomputeTopAlignedAdditionDiff(diff, diff.additionLines, diff.additionCharacterCount, parseDiffOptions);
|
|
65
69
|
const additionLines = diff.additionLines;
|
|
66
70
|
const recomputed = recomputeDiffHunks(diff, parseDiffOptions);
|
|
67
71
|
preserveTrailingEditorBlankLine(recomputed, additionLines);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateDiffHunks.js","names":[],"sources":["../../src/utils/updateDiffHunks.ts"],"sourcesContent":["import type { CreatePatchOptionsNonabortable } from 'diff';\n\nimport type {\n ChangeContent,\n ContextContent,\n FileDiffMetadata,\n Hunk,\n} from '../types';\nimport { cleanLastNewline } from './cleanLastNewline';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\nimport { parseDiffFromFile } from './parseDiffFromFile';\nimport { hasTrailingContextMismatch } from './virtualDiffLayout';\n\ntype HunkContent = ContextContent | ChangeContent;\n\ntype HunkMetadataUpdate = Pick<\n FileDiffMetadata,\n 'hunks' | 'splitLineCount' | 'unifiedLineCount' | 'type'\n>;\n\ntype FullDiffHunkUpdate = HunkMetadataUpdate &\n Pick<FileDiffMetadata, 'additionLines' | 'deletionLines'>;\n\n/** Rebuilds all hunk metadata from the current deletion/addition line arrays. */\nexport function recomputeDiffHunks(\n diff: FileDiffMetadata,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n const recomputed = parseDiffFromFile(\n {\n name: diff.prevName ?? diff.name,\n contents: diff.deletionLines.join(''),\n },\n {\n name: diff.name,\n contents: diff.additionLines.join(''),\n lang: diff.lang,\n },\n parseDiffOptions\n );\n return {\n hunks: recomputed.hunks,\n splitLineCount: recomputed.splitLineCount,\n unifiedLineCount: recomputed.unifiedLineCount,\n additionLines: recomputed.additionLines,\n deletionLines: recomputed.deletionLines,\n type: recomputed.type,\n };\n}\n\n// Builds placeholder addition contents that diff as one top-aligned change row per\n// line. Bare `\\\\n` sentinels align as context against the first deletion lines,\n// which pushes the real addition rows down in split view.\nfunction buildTopAlignedAdditionSentinel(\n lineCount: number,\n deletionContents: string\n): string {\n const count = Math.max(lineCount, 1);\n let sentinel = Array.from(\n { length: count },\n (_, index) => `${' '.repeat(index + 1)}\\n`\n ).join('');\n if (sentinel === deletionContents) {\n sentinel = Array.from(\n { length: count },\n (_, index) => `\\u0000${' '.repeat(index)}\\n`\n ).join('');\n }\n return sentinel;\n}\n\nfunction hasOnlyBlankAdditionContents(additionLines: string[]): boolean {\n for (const line of additionLines) {\n if (line.trim().length > 0) {\n return false;\n }\n }\n return true;\n}\n\n// After delete-all the editable side is blank and much shorter than the deletion\n// side. A normal recompute can still treat newline-only additions as context and\n// render the first editable row deep in split view instead of at the top.\nexport function shouldTopAlignAdditionRecompute(\n diff: FileDiffMetadata,\n additionLines: string[]\n): boolean {\n return (\n additionLines.length > 0 &&\n additionLines.length < diff.deletionLines.length &&\n hasOnlyBlankAdditionContents(additionLines)\n );\n}\n\n// Rebuilds hunk metadata while keeping the editable addition rows top-aligned in\n// split view. The sentinel only shapes hunks; the caller's addition lines are\n// preserved so the editor document stays the source of truth.\nexport function recomputeTopAlignedAdditionDiff(\n diff: FileDiffMetadata,\n additionLines: string[],\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n const deletionContents = diff.deletionLines.join('');\n const additionSentinel = buildTopAlignedAdditionSentinel(\n additionLines.length,\n deletionContents\n );\n const recomputed = parseDiffFromFile(\n {\n name: diff.prevName ?? diff.name,\n contents: deletionContents,\n },\n {\n name: diff.name,\n contents: additionSentinel,\n lang: diff.lang,\n },\n parseDiffOptions\n );\n return {\n hunks: recomputed.hunks,\n splitLineCount: recomputed.splitLineCount,\n unifiedLineCount: recomputed.unifiedLineCount,\n additionLines,\n deletionLines: recomputed.deletionLines,\n type: recomputed.type,\n };\n}\n\n// Rebuilds hunk metadata when the editable side has been emptied of all text.\n//\n// The editor always keeps one (empty) line for an empty document, but an empty\n// string splits into zero addition lines, so a normal recompute produces a diff\n// with no addition rows at all. Rendering that leaves the attached editor with\n// no line element to host its caret.\nexport function recomputeEmptyDocumentDiff(\n diff: FileDiffMetadata,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n return recomputeTopAlignedAdditionDiff(diff, [''], parseDiffOptions);\n}\n\n/** Rebuilds diff hunks after an edit, top-aligning sparse addition sides when needed. */\nexport function recomputeDiffHunksForEdit(\n diff: FileDiffMetadata,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n if (diff.additionLines.length === 0) {\n return recomputeEmptyDocumentDiff(diff, parseDiffOptions);\n }\n if (shouldTopAlignAdditionRecompute(diff, diff.additionLines)) {\n return recomputeTopAlignedAdditionDiff(\n diff,\n diff.additionLines,\n parseDiffOptions\n );\n }\n const additionLines = diff.additionLines;\n const recomputed = recomputeDiffHunks(diff, parseDiffOptions);\n preserveTrailingEditorBlankLine(recomputed, additionLines);\n return recomputed;\n}\n\nfunction hasTrailingEditorBlankLine(additionLines: string[]): boolean {\n return additionLines.length > 1 && additionLines.at(-1) === '';\n}\n\n// Re-adds the editor's phantom trailing empty line (a document ending in a\n// newline exposes one extra empty line) as an addition row when the last\n// hunk's final change block can absorb it, so the caret keeps a rendered row.\nexport function preserveTrailingEditorBlankLine(\n recomputed: Pick<\n FullDiffHunkUpdate,\n 'hunks' | 'additionLines' | 'splitLineCount' | 'unifiedLineCount'\n >,\n additionLines: string[]\n): void {\n if (!hasTrailingEditorBlankLine(additionLines)) {\n return;\n }\n const extraLineCount = additionLines.length - recomputed.additionLines.length;\n if (extraLineCount <= 0) {\n return;\n }\n const extraAdditionLineIndex = recomputed.additionLines.length;\n\n const lastHunk = recomputed.hunks.at(-1);\n if (lastHunk == null) {\n return;\n }\n\n const lastHunkAdditionEnd = getHunkSideEndBoundary(\n lastHunk.additionStart,\n lastHunk.additionCount\n );\n if (lastHunkAdditionEnd !== extraAdditionLineIndex) {\n return;\n }\n\n for (const content of lastHunk.hunkContent) {\n if (\n content.type === 'change' &&\n content.additions < content.deletions &&\n content.additionLineIndex + content.additions === extraAdditionLineIndex\n ) {\n recomputed.additionLines = additionLines;\n content.additions += extraLineCount;\n lastHunk.additionCount += extraLineCount;\n lastHunk.additionLines += extraLineCount;\n recomputeDiffRenderLineCounts(recomputed);\n return;\n }\n }\n}\n\n/** Updates hunk metadata after addition lines change; re-parses affected hunks only. */\nexport function updateDiffHunks(\n diff: FileDiffMetadata,\n changedAdditionLineIndexes: Iterable<number>,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): HunkMetadataUpdate {\n if (diff.isPartial) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n if (diff.deletionLines.length !== diff.additionLines.length) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n const changedLines = Array.from(changedAdditionLineIndexes);\n if (changedLines.length === 0) {\n return applyHunkUpdateResult(diff, {\n hunks: diff.hunks,\n splitLineCount: diff.splitLineCount,\n unifiedLineCount: diff.unifiedLineCount,\n type: diff.type,\n });\n }\n for (const line of changedLines) {\n const additionLine = diff.additionLines[line];\n const deletionLine = diff.deletionLines[line];\n if (additionLine == null || deletionLine == null) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n // Restoring a line to the old side can merge/split hunks across context windows.\n if (cleanLastNewline(additionLine) === cleanLastNewline(deletionLine)) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n }\n\n const affectedHunkIndexes = getAffectedHunkIndexes(diff, changedLines);\n if (affectedHunkIndexes.size === 0) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n for (const hunkIndex of affectedHunkIndexes) {\n const updated = reparseHunkRegion(diff, hunkIndex, parseDiffOptions);\n if (!updated) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n }\n\n recomputeDiffRenderLineCounts(diff);\n\n if (hasTrailingContextMismatch(diff)) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n return applyHunkUpdateResult(diff, {\n hunks: diff.hunks,\n splitLineCount: diff.splitLineCount,\n unifiedLineCount: diff.unifiedLineCount,\n type: diff.type,\n });\n}\n\nfunction applyHunkUpdateResult<T extends HunkMetadataUpdate>(\n diff: FileDiffMetadata,\n result: T\n): T {\n Object.assign(diff, result);\n return result;\n}\n\nfunction getAffectedHunkIndexes(\n diff: FileDiffMetadata,\n changedAdditionLineIndexes: Iterable<number>\n): Set<number> {\n const indexes = new Set<number>();\n for (const line of changedAdditionLineIndexes) {\n const hunkIndex = findHunkIndexForAdditionLine(diff, line);\n if (hunkIndex == null) {\n return new Set();\n }\n indexes.add(hunkIndex);\n }\n return indexes;\n}\n\nfunction findHunkIndexForAdditionLine(\n diff: FileDiffMetadata,\n line: number\n): number | undefined {\n for (const [hunkIndex, hunk] of diff.hunks.entries()) {\n const end = hunk.additionLineIndex + hunk.additionCount;\n if (line >= hunk.additionLineIndex && line < end) {\n return hunkIndex;\n }\n }\n return undefined;\n}\n\nfunction reparseHunkRegion(\n diff: FileDiffMetadata,\n hunkIndex: number,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): boolean {\n const hunk = diff.hunks[hunkIndex];\n if (hunk == null) {\n return false;\n }\n\n const deletionSlice = diff.deletionLines.slice(\n hunk.deletionLineIndex,\n hunk.deletionLineIndex + hunk.deletionCount\n );\n const additionSlice = diff.additionLines.slice(\n hunk.additionLineIndex,\n hunk.additionLineIndex + hunk.additionCount\n );\n\n const reparsed = parseDiffFromFile(\n {\n name: diff.prevName ?? diff.name,\n contents: deletionSlice.join(''),\n },\n {\n name: diff.name,\n contents: additionSlice.join(''),\n lang: diff.lang,\n },\n { ...parseDiffOptions, context: 0 }\n );\n\n const reparsedHunk = reparsed.hunks[0];\n if (reparsedHunk == null || reparsed.hunks.length !== 1) {\n return false;\n }\n\n applyReparsedHunk(hunk, reparsedHunk);\n syncHunkNoEOFCRFromFullFile(diff, hunkIndex);\n return true;\n}\n\nexport function syncHunkNoEOFCRFromFullFile(\n diff: FileDiffMetadata,\n hunkIndex: number\n): void {\n const hunk = diff.hunks[hunkIndex];\n if (hunk == null) {\n return;\n }\n\n const isLastHunk = hunkIndex === diff.hunks.length - 1;\n if (!isLastHunk) {\n hunk.noEOFCRAdditions = false;\n hunk.noEOFCRDeletions = false;\n return;\n }\n\n const lastAdditionLine = diff.additionLines.at(-1);\n const lastDeletionLine = diff.deletionLines.at(-1);\n hunk.noEOFCRAdditions =\n lastAdditionLine != null &&\n lastAdditionLine !== '' &&\n !lastAdditionLine.endsWith('\\n');\n hunk.noEOFCRDeletions =\n lastDeletionLine != null &&\n lastDeletionLine !== '' &&\n !lastDeletionLine.endsWith('\\n');\n}\n\nfunction applyReparsedHunk(target: Hunk, parsed: Hunk): void {\n const additionOffset = target.additionLineIndex;\n const deletionOffset = target.deletionLineIndex;\n\n target.hunkContent = parsed.hunkContent.map((content) =>\n offsetHunkContent(content, additionOffset, deletionOffset)\n );\n target.additionLineIndex = additionOffset + parsed.additionLineIndex;\n target.additionStart = target.additionStart + parsed.additionLineIndex;\n target.additionCount = parsed.additionCount;\n target.additionLines = parsed.additionLines;\n if (parsed.deletionLineIndex >= 0) {\n target.deletionLineIndex = deletionOffset + parsed.deletionLineIndex;\n target.deletionStart = target.deletionStart + parsed.deletionLineIndex;\n }\n target.deletionCount = parsed.deletionCount;\n target.deletionLines = parsed.deletionLines;\n target.noEOFCRAdditions = parsed.noEOFCRAdditions;\n target.noEOFCRDeletions = parsed.noEOFCRDeletions;\n\n recomputeHunkRenderLineCounts(target);\n}\n\nexport function offsetHunkContent(\n content: HunkContent,\n additionOffset: number,\n deletionOffset: number\n): HunkContent {\n return {\n ...content,\n additionLineIndex: content.additionLineIndex + additionOffset,\n deletionLineIndex: content.deletionLineIndex + deletionOffset,\n };\n}\n\nexport function recomputeHunkRenderLineCounts(hunk: Hunk): void {\n let splitLineCount = 0;\n let unifiedLineCount = 0;\n\n for (const content of hunk.hunkContent) {\n if (content.type === 'context') {\n splitLineCount += content.lines;\n unifiedLineCount += content.lines;\n } else {\n splitLineCount += Math.max(content.additions, content.deletions);\n unifiedLineCount += content.additions + content.deletions;\n }\n }\n\n hunk.splitLineCount = splitLineCount;\n hunk.unifiedLineCount = unifiedLineCount;\n}\n\nexport function recomputeDiffRenderLineCounts(\n diff: Pick<\n FileDiffMetadata,\n 'hunks' | 'splitLineCount' | 'unifiedLineCount' | 'additionLines'\n >\n): void {\n let splitTotal = 0;\n let unifiedTotal = 0;\n let lastHunkAdditionEnd = 0;\n\n for (const hunk of diff.hunks) {\n hunk.collapsedBefore = Math.max(\n getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount) -\n lastHunkAdditionEnd,\n 0\n );\n hunk.splitLineStart = splitTotal + hunk.collapsedBefore;\n hunk.unifiedLineStart = unifiedTotal + hunk.collapsedBefore;\n\n recomputeHunkRenderLineCounts(hunk);\n\n splitTotal += hunk.collapsedBefore + hunk.splitLineCount;\n unifiedTotal += hunk.collapsedBefore + hunk.unifiedLineCount;\n lastHunkAdditionEnd = getHunkSideEndBoundary(\n hunk.additionStart,\n hunk.additionCount\n );\n }\n\n if (diff.hunks.length > 0) {\n const lastHunk = diff.hunks[diff.hunks.length - 1];\n const collapsedAfter = Math.max(\n diff.additionLines.length -\n getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount),\n 0\n );\n splitTotal += collapsedAfter;\n unifiedTotal += collapsedAfter;\n }\n\n diff.splitLineCount = splitTotal;\n diff.unifiedLineCount = unifiedTotal;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"updateDiffHunks.js","names":[],"sources":["../../src/utils/updateDiffHunks.ts"],"sourcesContent":["import type { CreatePatchOptionsNonabortable } from 'diff';\n\nimport type {\n ChangeContent,\n ContextContent,\n FileDiffMetadata,\n Hunk,\n} from '../types';\nimport { cleanLastNewline } from './cleanLastNewline';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\nimport { parseDiffFromFile } from './parseDiffFromFile';\nimport { hasTrailingContextMismatch } from './virtualDiffLayout';\n\ntype HunkContent = ContextContent | ChangeContent;\n\ntype HunkMetadataUpdate = Pick<\n FileDiffMetadata,\n 'hunks' | 'splitLineCount' | 'unifiedLineCount' | 'type'\n>;\n\ntype FullDiffHunkUpdate = HunkMetadataUpdate &\n Pick<\n FileDiffMetadata,\n | 'additionLines'\n | 'deletionLines'\n | 'additionCharacterCount'\n | 'deletionCharacterCount'\n >;\n\n/** Rebuilds all hunk metadata from the current deletion/addition line arrays. */\nexport function recomputeDiffHunks(\n diff: FileDiffMetadata,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n const recomputed = parseDiffFromFile(\n {\n name: diff.prevName ?? diff.name,\n contents: diff.deletionLines.join(''),\n },\n {\n name: diff.name,\n contents: diff.additionLines.join(''),\n lang: diff.lang,\n },\n parseDiffOptions\n );\n return {\n hunks: recomputed.hunks,\n splitLineCount: recomputed.splitLineCount,\n unifiedLineCount: recomputed.unifiedLineCount,\n additionLines: recomputed.additionLines,\n deletionLines: recomputed.deletionLines,\n additionCharacterCount: recomputed.additionCharacterCount,\n deletionCharacterCount: recomputed.deletionCharacterCount,\n type: recomputed.type,\n };\n}\n\n// Builds placeholder addition contents that diff as one top-aligned change row per\n// line. Bare `\\\\n` sentinels align as context against the first deletion lines,\n// which pushes the real addition rows down in split view.\nfunction buildTopAlignedAdditionSentinel(\n lineCount: number,\n deletionContents: string\n): string {\n const count = Math.max(lineCount, 1);\n let sentinel = Array.from(\n { length: count },\n (_, index) => `${' '.repeat(index + 1)}\\n`\n ).join('');\n if (sentinel === deletionContents) {\n sentinel = Array.from(\n { length: count },\n (_, index) => `\\u0000${' '.repeat(index)}\\n`\n ).join('');\n }\n return sentinel;\n}\n\nfunction hasOnlyBlankAdditionContents(additionLines: string[]): boolean {\n for (const line of additionLines) {\n if (line.trim().length > 0) {\n return false;\n }\n }\n return true;\n}\n\n// After delete-all the editable side is blank and much shorter than the deletion\n// side. A normal recompute can still treat newline-only additions as context and\n// render the first editable row deep in split view instead of at the top.\nexport function shouldTopAlignAdditionRecompute(\n diff: FileDiffMetadata,\n additionLines: string[]\n): boolean {\n return (\n additionLines.length > 0 &&\n additionLines.length < diff.deletionLines.length &&\n hasOnlyBlankAdditionContents(additionLines)\n );\n}\n\n// Rebuilds hunk metadata while keeping the editable addition rows top-aligned in\n// split view. The sentinel only shapes hunks; the caller's addition lines are\n// preserved so the editor document stays the source of truth.\nexport function recomputeTopAlignedAdditionDiff(\n diff: FileDiffMetadata,\n additionLines: string[],\n additionCharacterCount: number,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n const deletionContents = diff.deletionLines.join('');\n const additionSentinel = buildTopAlignedAdditionSentinel(\n additionLines.length,\n deletionContents\n );\n const recomputed = parseDiffFromFile(\n {\n name: diff.prevName ?? diff.name,\n contents: deletionContents,\n },\n {\n name: diff.name,\n contents: additionSentinel,\n lang: diff.lang,\n },\n parseDiffOptions\n );\n return {\n hunks: recomputed.hunks,\n splitLineCount: recomputed.splitLineCount,\n unifiedLineCount: recomputed.unifiedLineCount,\n additionLines,\n deletionLines: recomputed.deletionLines,\n additionCharacterCount,\n deletionCharacterCount: recomputed.deletionCharacterCount,\n type: recomputed.type,\n };\n}\n\n// Rebuilds hunk metadata when the editable side has been emptied of all text.\n//\n// The editor always keeps one (empty) line for an empty document, but an empty\n// string splits into zero addition lines, so a normal recompute produces a diff\n// with no addition rows at all. Rendering that leaves the attached editor with\n// no line element to host its caret.\nexport function recomputeEmptyDocumentDiff(\n diff: FileDiffMetadata,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n return recomputeTopAlignedAdditionDiff(diff, [''], 0, parseDiffOptions);\n}\n\n/** Rebuilds diff hunks after an edit, top-aligning sparse addition sides when needed. */\nexport function recomputeDiffHunksForEdit(\n diff: FileDiffMetadata,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): FullDiffHunkUpdate {\n if (diff.additionLines.length === 0) {\n return recomputeEmptyDocumentDiff(diff, parseDiffOptions);\n }\n if (shouldTopAlignAdditionRecompute(diff, diff.additionLines)) {\n return recomputeTopAlignedAdditionDiff(\n diff,\n diff.additionLines,\n diff.additionCharacterCount,\n parseDiffOptions\n );\n }\n const additionLines = diff.additionLines;\n const recomputed = recomputeDiffHunks(diff, parseDiffOptions);\n preserveTrailingEditorBlankLine(recomputed, additionLines);\n return recomputed;\n}\n\nfunction hasTrailingEditorBlankLine(additionLines: string[]): boolean {\n return additionLines.length > 1 && additionLines.at(-1) === '';\n}\n\n// Re-adds the editor's phantom trailing empty line (a document ending in a\n// newline exposes one extra empty line) as an addition row when the last\n// hunk's final change block can absorb it, so the caret keeps a rendered row.\nexport function preserveTrailingEditorBlankLine(\n recomputed: Pick<\n FullDiffHunkUpdate,\n 'hunks' | 'additionLines' | 'splitLineCount' | 'unifiedLineCount'\n >,\n additionLines: string[]\n): void {\n if (!hasTrailingEditorBlankLine(additionLines)) {\n return;\n }\n const extraLineCount = additionLines.length - recomputed.additionLines.length;\n if (extraLineCount <= 0) {\n return;\n }\n const extraAdditionLineIndex = recomputed.additionLines.length;\n\n const lastHunk = recomputed.hunks.at(-1);\n if (lastHunk == null) {\n return;\n }\n\n const lastHunkAdditionEnd = getHunkSideEndBoundary(\n lastHunk.additionStart,\n lastHunk.additionCount\n );\n if (lastHunkAdditionEnd !== extraAdditionLineIndex) {\n return;\n }\n\n for (const content of lastHunk.hunkContent) {\n if (\n content.type === 'change' &&\n content.additions < content.deletions &&\n content.additionLineIndex + content.additions === extraAdditionLineIndex\n ) {\n recomputed.additionLines = additionLines;\n content.additions += extraLineCount;\n lastHunk.additionCount += extraLineCount;\n lastHunk.additionLines += extraLineCount;\n recomputeDiffRenderLineCounts(recomputed);\n return;\n }\n }\n}\n\n/** Updates hunk metadata after addition lines change; re-parses affected hunks only. */\nexport function updateDiffHunks(\n diff: FileDiffMetadata,\n changedAdditionLineIndexes: Iterable<number>,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): HunkMetadataUpdate {\n if (diff.isPartial) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n if (diff.deletionLines.length !== diff.additionLines.length) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n const changedLines = Array.from(changedAdditionLineIndexes);\n if (changedLines.length === 0) {\n return applyHunkUpdateResult(diff, {\n hunks: diff.hunks,\n splitLineCount: diff.splitLineCount,\n unifiedLineCount: diff.unifiedLineCount,\n type: diff.type,\n });\n }\n for (const line of changedLines) {\n const additionLine = diff.additionLines[line];\n const deletionLine = diff.deletionLines[line];\n if (additionLine == null || deletionLine == null) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n // Restoring a line to the old side can merge/split hunks across context windows.\n if (cleanLastNewline(additionLine) === cleanLastNewline(deletionLine)) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n }\n\n const affectedHunkIndexes = getAffectedHunkIndexes(diff, changedLines);\n if (affectedHunkIndexes.size === 0) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n for (const hunkIndex of affectedHunkIndexes) {\n const updated = reparseHunkRegion(diff, hunkIndex, parseDiffOptions);\n if (!updated) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n }\n\n recomputeDiffRenderLineCounts(diff);\n\n if (hasTrailingContextMismatch(diff)) {\n return applyHunkUpdateResult(\n diff,\n recomputeDiffHunks(diff, parseDiffOptions)\n );\n }\n\n return applyHunkUpdateResult(diff, {\n hunks: diff.hunks,\n splitLineCount: diff.splitLineCount,\n unifiedLineCount: diff.unifiedLineCount,\n type: diff.type,\n });\n}\n\nfunction applyHunkUpdateResult<T extends HunkMetadataUpdate>(\n diff: FileDiffMetadata,\n result: T\n): T {\n Object.assign(diff, result);\n return result;\n}\n\nfunction getAffectedHunkIndexes(\n diff: FileDiffMetadata,\n changedAdditionLineIndexes: Iterable<number>\n): Set<number> {\n const indexes = new Set<number>();\n for (const line of changedAdditionLineIndexes) {\n const hunkIndex = findHunkIndexForAdditionLine(diff, line);\n if (hunkIndex == null) {\n return new Set();\n }\n indexes.add(hunkIndex);\n }\n return indexes;\n}\n\nfunction findHunkIndexForAdditionLine(\n diff: FileDiffMetadata,\n line: number\n): number | undefined {\n for (const [hunkIndex, hunk] of diff.hunks.entries()) {\n const end = hunk.additionLineIndex + hunk.additionCount;\n if (line >= hunk.additionLineIndex && line < end) {\n return hunkIndex;\n }\n }\n return undefined;\n}\n\nfunction reparseHunkRegion(\n diff: FileDiffMetadata,\n hunkIndex: number,\n parseDiffOptions?: CreatePatchOptionsNonabortable\n): boolean {\n const hunk = diff.hunks[hunkIndex];\n if (hunk == null) {\n return false;\n }\n\n const deletionSlice = diff.deletionLines.slice(\n hunk.deletionLineIndex,\n hunk.deletionLineIndex + hunk.deletionCount\n );\n const additionSlice = diff.additionLines.slice(\n hunk.additionLineIndex,\n hunk.additionLineIndex + hunk.additionCount\n );\n\n const reparsed = parseDiffFromFile(\n {\n name: diff.prevName ?? diff.name,\n contents: deletionSlice.join(''),\n },\n {\n name: diff.name,\n contents: additionSlice.join(''),\n lang: diff.lang,\n },\n { ...parseDiffOptions, context: 0 }\n );\n\n const reparsedHunk = reparsed.hunks[0];\n if (reparsedHunk == null || reparsed.hunks.length !== 1) {\n return false;\n }\n\n applyReparsedHunk(hunk, reparsedHunk);\n syncHunkNoEOFCRFromFullFile(diff, hunkIndex);\n return true;\n}\n\nexport function syncHunkNoEOFCRFromFullFile(\n diff: FileDiffMetadata,\n hunkIndex: number\n): void {\n const hunk = diff.hunks[hunkIndex];\n if (hunk == null) {\n return;\n }\n\n const isLastHunk = hunkIndex === diff.hunks.length - 1;\n if (!isLastHunk) {\n hunk.noEOFCRAdditions = false;\n hunk.noEOFCRDeletions = false;\n return;\n }\n\n const lastAdditionLine = diff.additionLines.at(-1);\n const lastDeletionLine = diff.deletionLines.at(-1);\n hunk.noEOFCRAdditions =\n lastAdditionLine != null &&\n lastAdditionLine !== '' &&\n !lastAdditionLine.endsWith('\\n');\n hunk.noEOFCRDeletions =\n lastDeletionLine != null &&\n lastDeletionLine !== '' &&\n !lastDeletionLine.endsWith('\\n');\n}\n\nfunction applyReparsedHunk(target: Hunk, parsed: Hunk): void {\n const additionOffset = target.additionLineIndex;\n const deletionOffset = target.deletionLineIndex;\n\n target.hunkContent = parsed.hunkContent.map((content) =>\n offsetHunkContent(content, additionOffset, deletionOffset)\n );\n target.additionLineIndex = additionOffset + parsed.additionLineIndex;\n target.additionStart = target.additionStart + parsed.additionLineIndex;\n target.additionCount = parsed.additionCount;\n target.additionLines = parsed.additionLines;\n if (parsed.deletionLineIndex >= 0) {\n target.deletionLineIndex = deletionOffset + parsed.deletionLineIndex;\n target.deletionStart = target.deletionStart + parsed.deletionLineIndex;\n }\n target.deletionCount = parsed.deletionCount;\n target.deletionLines = parsed.deletionLines;\n target.noEOFCRAdditions = parsed.noEOFCRAdditions;\n target.noEOFCRDeletions = parsed.noEOFCRDeletions;\n\n recomputeHunkRenderLineCounts(target);\n}\n\nexport function offsetHunkContent(\n content: HunkContent,\n additionOffset: number,\n deletionOffset: number\n): HunkContent {\n return {\n ...content,\n additionLineIndex: content.additionLineIndex + additionOffset,\n deletionLineIndex: content.deletionLineIndex + deletionOffset,\n };\n}\n\nexport function recomputeHunkRenderLineCounts(hunk: Hunk): void {\n let splitLineCount = 0;\n let unifiedLineCount = 0;\n\n for (const content of hunk.hunkContent) {\n if (content.type === 'context') {\n splitLineCount += content.lines;\n unifiedLineCount += content.lines;\n } else {\n splitLineCount += Math.max(content.additions, content.deletions);\n unifiedLineCount += content.additions + content.deletions;\n }\n }\n\n hunk.splitLineCount = splitLineCount;\n hunk.unifiedLineCount = unifiedLineCount;\n}\n\nexport function recomputeDiffRenderLineCounts(\n diff: Pick<\n FileDiffMetadata,\n 'hunks' | 'splitLineCount' | 'unifiedLineCount' | 'additionLines'\n >\n): void {\n let splitTotal = 0;\n let unifiedTotal = 0;\n let lastHunkAdditionEnd = 0;\n\n for (const hunk of diff.hunks) {\n hunk.collapsedBefore = Math.max(\n getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount) -\n lastHunkAdditionEnd,\n 0\n );\n hunk.splitLineStart = splitTotal + hunk.collapsedBefore;\n hunk.unifiedLineStart = unifiedTotal + hunk.collapsedBefore;\n\n recomputeHunkRenderLineCounts(hunk);\n\n splitTotal += hunk.collapsedBefore + hunk.splitLineCount;\n unifiedTotal += hunk.collapsedBefore + hunk.unifiedLineCount;\n lastHunkAdditionEnd = getHunkSideEndBoundary(\n hunk.additionStart,\n hunk.additionCount\n );\n }\n\n if (diff.hunks.length > 0) {\n const lastHunk = diff.hunks[diff.hunks.length - 1];\n const collapsedAfter = Math.max(\n diff.additionLines.length -\n getHunkSideEndBoundary(lastHunk.additionStart, lastHunk.additionCount),\n 0\n );\n splitTotal += collapsedAfter;\n unifiedTotal += collapsedAfter;\n }\n\n diff.splitLineCount = splitTotal;\n diff.unifiedLineCount = unifiedTotal;\n}\n"],"mappings":"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"}
|
|
@@ -26,6 +26,7 @@ declare class WorkerPoolManager {
|
|
|
26
26
|
private nextRequestId;
|
|
27
27
|
private themeSubscribers;
|
|
28
28
|
private workersFailed;
|
|
29
|
+
private terminated;
|
|
29
30
|
private statSubscribers;
|
|
30
31
|
private fileCache;
|
|
31
32
|
private diffCache;
|
|
@@ -33,8 +34,16 @@ declare class WorkerPoolManager {
|
|
|
33
34
|
private lifecycleGeneration;
|
|
34
35
|
constructor(options: WorkerPoolOptions, { langs, theme, useTokenTransformer, lineDiffType, maxLineDiffLength, tokenizeMaxLineLength, preferredHighlighter }: WorkerInitializationRenderOptions);
|
|
35
36
|
isWorkingPool(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Whether a file or diff fits within `mainThreadMaxCharacters`, so it
|
|
39
|
+
* highlights on the main thread instead of a worker. Files count `contents`;
|
|
40
|
+
* diffs count both sides.
|
|
41
|
+
*/
|
|
42
|
+
shouldHighlightOnMainThread(fileOrDiff: FileContents | FileDiffMetadata): boolean;
|
|
36
43
|
getFileResultCache(file: FileContents): RenderFileResult | undefined;
|
|
37
44
|
getDiffResultCache(diff: FileDiffMetadata): RenderDiffResult | undefined;
|
|
45
|
+
setFileResultCache(cacheKey: string | undefined, { result, options }: RenderFileResult): boolean;
|
|
46
|
+
setDiffResultCache(cacheKey: string | undefined, { result, options }: RenderDiffResult): boolean;
|
|
38
47
|
inspectCaches(): GetCachesResult;
|
|
39
48
|
evictFileFromCache(cacheKey: string): boolean;
|
|
40
49
|
evictDiffFromCache(cacheKey: string): boolean;
|
|
@@ -65,10 +74,13 @@ declare class WorkerPoolManager {
|
|
|
65
74
|
private drainQueue;
|
|
66
75
|
highlightFileAST(instance: FileRendererInstance, file: FileContents): void;
|
|
67
76
|
primeFileHighlightCache(file: FileContents): Promise<void>;
|
|
77
|
+
private shouldPrimeFileHighlightCache;
|
|
68
78
|
private getOrCreateFileHighlightCacheTask;
|
|
69
79
|
getPlainFileAST(file: FileContents, startingLine: number, totalLines: number, lines?: string[]): ThemedFileResult | undefined;
|
|
70
80
|
highlightDiffAST(instance: DiffRendererInstance, diff: FileDiffMetadata): void;
|
|
71
81
|
primeDiffHighlightCache(diff: FileDiffMetadata): Promise<void>;
|
|
82
|
+
private shouldPrimeDiffHighlightCache;
|
|
83
|
+
private primeHighlightCacheOnMainThread;
|
|
72
84
|
private getOrCreateDiffHighlightCacheTask;
|
|
73
85
|
getPlainDiffAST(diff: FileDiffMetadata, startingLine: number, totalLines: number, expandedHunks?: Map<number, HunkExpansionRegion> | true, collapsedContextThreshold?: number): ThemedDiffResult | undefined;
|
|
74
86
|
terminate(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerPoolManager.d.ts","names":[],"sources":["../../src/worker/WorkerPoolManager.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"WorkerPoolManager.d.ts","names":[],"sources":["../../src/worker/WorkerPoolManager.ts"],"mappings":";;;;UAmFU;EACR,WAAW,eAAe;EAC1B,WAAW,eAAe;;UAYlB;EACR;;KAKG,qBAAqB,uBAAuB;cAEpC;UAkCD;mBAjCO;UACT;UACA;UACA;UACA;UACA;UAEA;UACA;UAIA;UAGA;UACA;UAKA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UAEA;EAER,YACU,SAAS,qBAEf,OACA,OACA,qBACA,cACA,mBACA,uBACA,wBACC;EAeE;;;;;;EASA,4BACL,YAAY,eAAe;EAUtB,mBAAmB,MAAM,eAAe;EAMxC,mBACL,MAAM,mBACL;EAQI,mBACL,gCACE,QAAQ,WAAW;EAehB,mBACL,gCACE,QAAQ,WAAW;EAahB,iBAAiB;EAKjB,mBAAmB;EAQnB,mBAAmB;EAQpB,mBACJ,OACA,qBACA,cACA,mBACA,yBACC,QAAQ,0BAA0B;EAmF9B,2BAA2B;EAI3B,wBAAwB;EAMxB,wBAAwB;UAIjB;EA6CP,wBAAwB,UAAU;EASlC,0BAA0B,UAAU;EAKpC,uBACL,WAAW,OAAO;UASZ;UAKA;EAWD,aAAa,UAAU;EAkBvB;EAIM,WAAW,YAAW,uBAA4B;UAwFjD;UAiBA;;;;;;;;;UAgGN;UA8BA;EA2BD,iBACL,UAAU,sBACV,MAAM;EAqBD,wBAAwB,MAAM,eAAe;UAgC5C;UAkBA;EA2BD,gBACL,MAAM,cACN,sBACA,oBACA,mBACC;EAgBI,iBACL,UAAU,sBACV,MAAM;EAqBD,wBAAwB,MAAM,mBAAmB;UAgChD;UAuBA;UA0BA;EA2BD,gBACL,MAAM,kBACN,sBACA,oBACA,gBAAgB,YAAY,6BAC5B,qCACC;EAiBI;UAqBC;UAIA;UAUA;UAWA;EAOD,YAAY;UAwBX;UA+DA;UA0CA;UAcM;UA0DN;UAsHA;UACA;UAMA;UAYA;UAqBA;UAmCA;UAeA;UAUA;UA8BA;UAOA;UAOA;UAWA;UASA;UAgBA;UAeA;UAWA;UAUA;UAOA;UAMA;UAOA;UAOA;UAkBA;UAQA;UASA;UAMA;UAQA;UAYA;UAYA;UAQA;UAiBA;UAiBA;UAKA;UAIC;UAWD"}
|
|
@@ -41,6 +41,7 @@ var WorkerPoolManager = class {
|
|
|
41
41
|
nextRequestId = 0;
|
|
42
42
|
themeSubscribers = /* @__PURE__ */ new Set();
|
|
43
43
|
workersFailed = false;
|
|
44
|
+
terminated = false;
|
|
44
45
|
statSubscribers = /* @__PURE__ */ new Set();
|
|
45
46
|
fileCache;
|
|
46
47
|
diffCache;
|
|
@@ -61,7 +62,16 @@ var WorkerPoolManager = class {
|
|
|
61
62
|
this.queueInitialization(langs);
|
|
62
63
|
}
|
|
63
64
|
isWorkingPool() {
|
|
64
|
-
return !this.workersFailed;
|
|
65
|
+
return !this.workersFailed && !this.terminated;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether a file or diff fits within `mainThreadMaxCharacters`, so it
|
|
69
|
+
* highlights on the main thread instead of a worker. Files count `contents`;
|
|
70
|
+
* diffs count both sides.
|
|
71
|
+
*/
|
|
72
|
+
shouldHighlightOnMainThread(fileOrDiff) {
|
|
73
|
+
const { mainThreadMaxCharacters = -1 } = this.options;
|
|
74
|
+
return ("contents" in fileOrDiff ? fileOrDiff.contents.length : fileOrDiff.deletionCharacterCount + fileOrDiff.additionCharacterCount) <= mainThreadMaxCharacters;
|
|
65
75
|
}
|
|
66
76
|
getFileResultCache(file) {
|
|
67
77
|
return file.cacheKey != null ? this.fileCache.get(file.cacheKey) : void 0;
|
|
@@ -69,6 +79,24 @@ var WorkerPoolManager = class {
|
|
|
69
79
|
getDiffResultCache(diff) {
|
|
70
80
|
return diff.cacheKey != null ? this.diffCache.get(diff.cacheKey) : void 0;
|
|
71
81
|
}
|
|
82
|
+
setFileResultCache(cacheKey, { result, options }) {
|
|
83
|
+
if (cacheKey == null || !areFileRenderOptionsEqual(options, this.getFileRenderOptions())) return false;
|
|
84
|
+
this.fileCache.set(cacheKey, {
|
|
85
|
+
result,
|
|
86
|
+
options
|
|
87
|
+
});
|
|
88
|
+
this.queueBroadcastStateChanges();
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
setDiffResultCache(cacheKey, { result, options }) {
|
|
92
|
+
if (cacheKey == null || !areDiffRenderOptionsEqual(options, this.getDiffRenderOptions())) return false;
|
|
93
|
+
this.diffCache.set(cacheKey, {
|
|
94
|
+
result,
|
|
95
|
+
options
|
|
96
|
+
});
|
|
97
|
+
this.queueBroadcastStateChanges();
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
72
100
|
inspectCaches() {
|
|
73
101
|
const { fileCache, diffCache } = this;
|
|
74
102
|
return {
|
|
@@ -102,7 +130,11 @@ var WorkerPoolManager = class {
|
|
|
102
130
|
maxLineDiffLength,
|
|
103
131
|
tokenizeMaxLineLength
|
|
104
132
|
};
|
|
105
|
-
if (!this.isInitialized())
|
|
133
|
+
if (!this.isInitialized()) try {
|
|
134
|
+
await this.initialize();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (!this.workersFailed) throw error;
|
|
137
|
+
}
|
|
106
138
|
if (!isCurrentRequest() || areDiffRenderOptionsEqual(newRenderOptions, this.renderOptions)) return;
|
|
107
139
|
const themeNames = getThemes(theme);
|
|
108
140
|
let resolvedThemes = [];
|
|
@@ -222,6 +254,7 @@ var WorkerPoolManager = class {
|
|
|
222
254
|
if (getHighlighterIfLoaded({ theme: this.renderOptions.theme }) == null) await this.loadSharedHighlighter(getThemes(this.renderOptions.theme), ["text", ...languages]);
|
|
223
255
|
return;
|
|
224
256
|
} else if (this.initialized === false) {
|
|
257
|
+
this.terminated = false;
|
|
225
258
|
const { lifecycleGeneration } = this;
|
|
226
259
|
const initialization = new Promise((resolve, reject) => {
|
|
227
260
|
(async () => {
|
|
@@ -245,8 +278,6 @@ var WorkerPoolManager = class {
|
|
|
245
278
|
return;
|
|
246
279
|
}
|
|
247
280
|
this.initialized = true;
|
|
248
|
-
this.diffCache.clear();
|
|
249
|
-
this.fileCache.clear();
|
|
250
281
|
this.drainQueue();
|
|
251
282
|
this.queueBroadcastStateChanges();
|
|
252
283
|
resolve();
|
|
@@ -377,7 +408,7 @@ var WorkerPoolManager = class {
|
|
|
377
408
|
i++;
|
|
378
409
|
continue;
|
|
379
410
|
}
|
|
380
|
-
const langs =
|
|
411
|
+
const langs = getLangsFromRequest(task.request);
|
|
381
412
|
const availableWorker = this.getAvailableWorker(langs);
|
|
382
413
|
if (availableWorker == null) break;
|
|
383
414
|
this.queuedTasks.splice(i, 1);
|
|
@@ -396,27 +427,43 @@ var WorkerPoolManager = class {
|
|
|
396
427
|
}
|
|
397
428
|
primeFileHighlightCache(file) {
|
|
398
429
|
if (!this.isWorkingPool()) return Promise.reject(/* @__PURE__ */ new Error("WorkerPoolManager.primeFileHighlightCache: worker pool is not working"));
|
|
430
|
+
if (!this.shouldPrimeFileHighlightCache(file)) return Promise.resolve();
|
|
431
|
+
if (this.shouldHighlightOnMainThread(file)) {
|
|
432
|
+
const options = this.getFileRenderOptions();
|
|
433
|
+
return this.primeHighlightCacheOnMainThread(getLangsFromRequest({
|
|
434
|
+
type: "file",
|
|
435
|
+
file
|
|
436
|
+
}), options.theme, (highlighter) => this.setFileResultCache(file.cacheKey, {
|
|
437
|
+
result: renderFileWithHighlighter(file, highlighter, options),
|
|
438
|
+
options
|
|
439
|
+
}));
|
|
440
|
+
}
|
|
399
441
|
const task = this.getOrCreateFileHighlightCacheTask(file);
|
|
400
442
|
return task != null ? this.createRenderTaskCallbacks(task) : Promise.resolve();
|
|
401
443
|
}
|
|
402
|
-
|
|
444
|
+
shouldPrimeFileHighlightCache(file) {
|
|
403
445
|
if (file.cacheKey == null) {
|
|
404
446
|
console.warn(`WorkerPoolManager.primeFileHighlightCache: priming highlight cache requires file.cacheKey; skipping "${file.name}".`);
|
|
405
|
-
return;
|
|
447
|
+
return false;
|
|
406
448
|
}
|
|
407
449
|
const cachedResult = this.getFileResultCache(file);
|
|
450
|
+
return !isFilePlainText(file) && (cachedResult == null || !areFileRenderOptionsEqual(cachedResult.options, this.getFileRenderOptions()));
|
|
451
|
+
}
|
|
452
|
+
getOrCreateFileHighlightCacheTask(file) {
|
|
408
453
|
const highlightKey = this.getFileHighlightKey(file);
|
|
409
|
-
if (highlightKey == null
|
|
454
|
+
if (highlightKey == null) return;
|
|
410
455
|
const existingTask = this.getTaskByHighlightKey(highlightKey);
|
|
411
456
|
if (existingTask != null) {
|
|
457
|
+
if (existingTask.type !== "file") throw new Error("WorkerPoolManager.getOrCreateFileHighlightCacheTask: Invalid task type");
|
|
412
458
|
existingTask.primeCache = true;
|
|
413
|
-
return existingTask
|
|
459
|
+
return existingTask;
|
|
414
460
|
} else {
|
|
415
461
|
const task = this.submitCacheTask({
|
|
416
462
|
type: "file",
|
|
417
463
|
file
|
|
418
464
|
}, highlightKey);
|
|
419
|
-
|
|
465
|
+
if (task.type !== "file") throw new Error("WorkerPoolManager.getOrCreateFileHighlightCacheTask: Invalid task created");
|
|
466
|
+
return task;
|
|
420
467
|
}
|
|
421
468
|
}
|
|
422
469
|
getPlainFileAST(file, startingLine, totalLines, lines) {
|
|
@@ -442,27 +489,58 @@ var WorkerPoolManager = class {
|
|
|
442
489
|
}
|
|
443
490
|
primeDiffHighlightCache(diff) {
|
|
444
491
|
if (!this.isWorkingPool()) return Promise.reject(/* @__PURE__ */ new Error("WorkerPoolManager.primeDiffHighlightCache: worker pool is not working"));
|
|
492
|
+
if (!this.shouldPrimeDiffHighlightCache(diff)) return Promise.resolve();
|
|
493
|
+
if (this.shouldHighlightOnMainThread(diff)) {
|
|
494
|
+
const options = this.getDiffRenderOptions();
|
|
495
|
+
return this.primeHighlightCacheOnMainThread(getLangsFromRequest({
|
|
496
|
+
type: "diff",
|
|
497
|
+
diff
|
|
498
|
+
}), options.theme, (highlighter) => this.setDiffResultCache(diff.cacheKey, {
|
|
499
|
+
result: renderDiffWithHighlighter(diff, highlighter, options),
|
|
500
|
+
options
|
|
501
|
+
}));
|
|
502
|
+
}
|
|
445
503
|
const task = this.getOrCreateDiffHighlightCacheTask(diff);
|
|
446
504
|
return task != null ? this.createRenderTaskCallbacks(task) : Promise.resolve();
|
|
447
505
|
}
|
|
448
|
-
|
|
506
|
+
shouldPrimeDiffHighlightCache(diff) {
|
|
449
507
|
if (diff.cacheKey == null) {
|
|
450
508
|
console.warn(`WorkerPoolManager.primeDiffHighlightCache: priming highlight cache requires diff.cacheKey; skipping "${diff.prevName ?? diff.name}" -> "${diff.name}".`);
|
|
451
|
-
return;
|
|
509
|
+
return false;
|
|
452
510
|
}
|
|
453
511
|
const cachedResult = this.getDiffResultCache(diff);
|
|
512
|
+
return !isDiffPlainText(diff) && (cachedResult == null || !areDiffRenderOptionsEqual(cachedResult.options, this.getDiffRenderOptions()));
|
|
513
|
+
}
|
|
514
|
+
primeHighlightCacheOnMainThread(langs, theme, highlightAndCacheResult) {
|
|
515
|
+
function highlightAndCacheIfLoaded() {
|
|
516
|
+
const highlighter = getHighlighterIfLoaded({
|
|
517
|
+
theme,
|
|
518
|
+
langs
|
|
519
|
+
});
|
|
520
|
+
return highlighter != null && highlightAndCacheResult(highlighter);
|
|
521
|
+
}
|
|
522
|
+
if (highlightAndCacheIfLoaded()) return Promise.resolve();
|
|
523
|
+
const { lifecycleGeneration } = this;
|
|
524
|
+
return this.loadSharedHighlighter(getThemes(theme), ["text", ...langs]).then(() => {
|
|
525
|
+
if (!this.isCurrentLifecycle(lifecycleGeneration)) throw new WorkerPoolTerminatedError();
|
|
526
|
+
if (!highlightAndCacheIfLoaded()) throw new WorkerPoolTaskCanceledError();
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
getOrCreateDiffHighlightCacheTask(diff) {
|
|
454
530
|
const highlightKey = this.getDiffHighlightKey(diff);
|
|
455
|
-
if (highlightKey == null
|
|
531
|
+
if (highlightKey == null) return;
|
|
456
532
|
const existingTask = this.getTaskByHighlightKey(highlightKey);
|
|
457
533
|
if (existingTask != null) {
|
|
534
|
+
if (existingTask.type !== "diff") throw new Error("WorkerPoolManager.getOrCreateDiffHighlightCacheTask: Invalid task type");
|
|
458
535
|
existingTask.primeCache = true;
|
|
459
|
-
return existingTask
|
|
536
|
+
return existingTask;
|
|
460
537
|
} else {
|
|
461
538
|
const task = this.submitCacheTask({
|
|
462
539
|
type: "diff",
|
|
463
540
|
diff
|
|
464
541
|
}, highlightKey);
|
|
465
|
-
|
|
542
|
+
if (task.type !== "diff") throw new Error("WorkerPoolManager.getOrCreateDiffHighlightCacheTask: Invalid task created");
|
|
543
|
+
return task;
|
|
466
544
|
}
|
|
467
545
|
}
|
|
468
546
|
getPlainDiffAST(diff, startingLine, totalLines, expandedHunks, collapsedContextThreshold) {
|
|
@@ -494,6 +572,7 @@ var WorkerPoolManager = class {
|
|
|
494
572
|
this.activeTaskById.clear();
|
|
495
573
|
this.initialized = false;
|
|
496
574
|
this.workersFailed = false;
|
|
575
|
+
this.terminated = true;
|
|
497
576
|
this.queueBroadcastStateChanges();
|
|
498
577
|
}
|
|
499
578
|
isCurrentLifecycle(lifecycleGeneration) {
|
|
@@ -914,16 +993,15 @@ var WorkerPoolManager = class {
|
|
|
914
993
|
function shouldSyncCustomExtensions(request) {
|
|
915
994
|
return request.type === "initialize" || request.type === "file" || request.type === "diff";
|
|
916
995
|
}
|
|
917
|
-
function
|
|
996
|
+
function getLangsFromRequest(request) {
|
|
918
997
|
const langs = /* @__PURE__ */ new Set();
|
|
919
|
-
|
|
920
|
-
switch (task.type) {
|
|
998
|
+
switch (request.type) {
|
|
921
999
|
case "file":
|
|
922
|
-
langs.add(
|
|
1000
|
+
langs.add(request.file.lang ?? getFiletypeFromFileName(request.file.name));
|
|
923
1001
|
break;
|
|
924
1002
|
case "diff":
|
|
925
|
-
langs.add(
|
|
926
|
-
langs.add(
|
|
1003
|
+
langs.add(request.diff.lang ?? getFiletypeFromFileName(request.diff.name));
|
|
1004
|
+
langs.add(request.diff.lang ?? getFiletypeFromFileName(request.diff.prevName ?? "-"));
|
|
927
1005
|
}
|
|
928
1006
|
langs.delete("text");
|
|
929
1007
|
return Array.from(langs);
|