import { addContentHighlightBGName, delContentHighlightBGName, getSymbol } from "@git-diff-view/utils"; import { escapeHtml } from "../escape-html"; import { processTransformTemplateContent, isTransformEnabled } from "./transform"; import type { DiffFile } from "../diff-file"; import type { DiffLine } from "./diff-line"; import type { SyntaxLine } from "@git-diff-view/lowlight"; let enableFastDiffTemplate = false; export const getEnableFastDiffTemplate = () => enableFastDiffTemplate; export const setEnableFastDiffTemplate = (enable: boolean) => { enableFastDiffTemplate = enable; }; export const resetEnableFastDiffTemplate = () => { enableFastDiffTemplate = false; }; export const defaultTransform = (content: string) => escapeHtml(content).replace(/\n/g, "").replace(/\r/g, ""); export const getPlainDiffTemplate = ({ diffLine, rawLine, operator, }: { diffLine: DiffLine; rawLine: string; operator: "add" | "del"; }) => { if (diffLine.plainTemplate && diffLine.plainTemplateMode === "relative") return; const changes = diffLine.changes; if (!changes || !changes.hasLineChange || !rawLine) return; const transform = isTransformEnabled() ? processTransformTemplateContent : defaultTransform; const range = changes.range; const str1 = rawLine.slice(0, range.location); const str2 = rawLine.slice(range.location, range.location + range.length); const str3 = rawLine.slice(range.location + range.length); const isLast = str2.includes("\n"); const isNewLineSymbolChanged = changes.newLineSymbol; let template = ``; template += transform(str1); template += ``; template += isLast ? `${transform(str2)}${getSymbol(isNewLineSymbolChanged)}` : transform(str2); template += ``; template += transform(str3); template += ``; diffLine.plainTemplate = template; diffLine.plainTemplateMode = "relative"; }; export const getPlainDiffTemplateByFastDiff = ({ diffLine, rawLine, operator, }: { diffLine: DiffLine; rawLine: string; operator: "add" | "del"; }) => { if (diffLine.plainTemplate && diffLine.plainTemplateMode === "fast-diff") return; const changes = diffLine.diffChanges; if (!changes || !changes.hasLineChange || !rawLine) return; const transform = isTransformEnabled() ? processTransformTemplateContent : defaultTransform; let template = ``; changes.range.forEach(({ type, str, startIndex, endIndex }, index, array) => { const isLatest = index === array.length - 1; if (type === 0) { template += `${transform(str)}`; template += isLatest && changes.newLineSymbol ? `${getSymbol(changes.newLineSymbol)}` : ""; template += ``; } else { template += ``; template += `${transform(str)}`; template += isLatest && changes.newLineSymbol ? `${getSymbol(changes.newLineSymbol)}` : ""; template += ``; } }); diffLine.plainTemplate = template; diffLine.plainTemplateMode = "fast-diff"; }; export const getSyntaxDiffTemplate = ({ diffFile, diffLine, syntaxLine, operator, }: { diffFile: DiffFile; diffLine: DiffLine; syntaxLine: SyntaxLine; operator: "add" | "del"; }) => { if (!syntaxLine) return; if ( diffLine.syntaxTemplate && diffLine.syntaxTemplateMode === "relative" && diffLine.syntaxTemplateName === diffFile._getHighlighterName() && diffFile._getHighlighterType() === "class" ) return; const changes = diffLine.changes; if (!changes || !changes.hasLineChange) return; const transform = isTransformEnabled() ? processTransformTemplateContent : defaultTransform; const range = changes.range; let template = ``; syntaxLine?.nodeList?.forEach(({ node, wrapper }) => { if (node.endIndex < range.location || range.location + range.length < node.startIndex) { template += `${transform(node.value)}`; } else { const index1 = range.location - node.startIndex; const index2 = index1 < 0 ? 0 : index1; const str1 = node.value.slice(0, index2); const str2 = node.value.slice(index2, index1 + range.length); const str3 = node.value.slice(index1 + range.length); const isStart = str1.length || range.location === node.startIndex; const isEnd = str3.length || node.endIndex === range.location + range.length - 1; const isLast = str2.includes("\n"); template += `${transform(str1)}${ isLast ? `${transform(str2)}${getSymbol(changes.newLineSymbol)}` : transform(str2) }${transform(str3)}`; } }); template += ""; diffLine.syntaxTemplate = template; diffLine.syntaxTemplateMode = "relative"; diffLine.syntaxTemplateName = diffFile._getHighlighterName(); }; export const getSyntaxDiffTemplateByFastDiff = ({ diffFile, diffLine, syntaxLine, operator, }: { diffFile: DiffFile; diffLine: DiffLine; syntaxLine: SyntaxLine; operator: "add" | "del"; }) => { if (!syntaxLine) return; if ( diffLine.syntaxTemplate && diffLine.syntaxTemplateMode === "fast-diff" && diffLine.syntaxTemplateName === diffFile._getHighlighterName() && diffFile._getHighlighterType() === "class" ) return; const changes = diffLine.diffChanges; const _changes = diffLine._diffChanges; if (!changes || !changes.hasLineChange) return; const transform = isTransformEnabled() ? processTransformTemplateContent : defaultTransform; let template = ""; const allRange = changes?.range?.filter((item) => item.type !== 0) || []; const _allRange = _changes?.range?.filter((item) => item.type !== 0) || []; let rangeIndex = 0; syntaxLine?.nodeList?.forEach(({ node, wrapper }, index, array) => { template += ``; let range = allRange[rangeIndex]; const noDiff = allRange.length === 0 && _allRange.length === 0; const isLastNode = index === array.length - 1; for (let i = 0; i < node.value.length; i++) { const index = node.startIndex + i; const value = node.value[i]; const isLastStr = i === node.value.length - 1; const isEndStr = isLastNode && i === node.value.length - 1; if (range) { // before start if (index < range.startIndex) { template += transform(value); // start of range } else if (index === range.startIndex) { // current range all in the same node const isInSameNode = range.endIndex <= node.endIndex; if (isInSameNode) { template += ``; } else { template += ``; } template += transform(value); if (isLastStr) { template += ``; } else if (range.startIndex === range.endIndex) { template += ``; } if (range.endIndex === index) { rangeIndex++; range = allRange[rangeIndex]; } // inside range } else if (index < range.endIndex) { if (i === 0) { // current range all in the same node const isInSameNode = range.startIndex >= node.startIndex && range.endIndex <= node.endIndex; // current range end is in the same node const isEndInSameNode = range.endIndex <= node.endIndex; template += isInSameNode ? `` : isEndInSameNode ? `` : // current range crosses the node boundary ``; } template += transform(value); if (isLastStr) { template += ``; } // end of range } else if (index === range.endIndex) { // current range all in the same node const isInSameNode = range.startIndex >= node.startIndex; if (isInSameNode) { template += transform(value); } else { if (i === 0) { template += ``; } template += transform(value); } template += ``; rangeIndex++; range = allRange[rangeIndex]; // after range } } else { template += transform(value); if (noDiff && isEndStr && changes.newLineSymbol) { template += ``; template += `${getSymbol(changes.newLineSymbol)}`; } } } template += ``; }); diffLine.syntaxTemplate = template; diffLine.syntaxTemplateMode = "fast-diff"; diffLine.syntaxTemplateName = diffFile._getHighlighterName(); }; export const getSyntaxLineTemplate = (line: SyntaxLine) => { let template = ""; const transform = isTransformEnabled() ? processTransformTemplateContent : defaultTransform; line?.nodeList?.forEach(({ node, wrapper }) => { template += `${transform(node.value)}`; }); return template; }; export const getPlainLineTemplate = (line: string) => { if (!line) return ""; const transform = isTransformEnabled() ? processTransformTemplateContent : defaultTransform; const template = transform(line); return template; };