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;
};