Use better diff algorithm

This commit is contained in:
Silvano Cerza 2025-02-20 18:41:16 +01:00
parent a0f2439b1f
commit fd100345a3

View file

@ -9,40 +9,75 @@ export interface DiffChunk {
function diff(oldText: string, newText: string): DiffChunk[] {
const oldLines = oldText.split("\n");
const newLines = newText.split("\n");
const result: DiffChunk[] = [];
for (let i = 0; i < Math.max(oldLines.length, newLines.length); i++) {
const oldLine = oldLines[i];
const newLine = newLines[i];
let matrix = Array(oldLines.length + 1)
.fill(null)
.map(() => Array(newLines.length + 1).fill(0));
if (!oldLine && newLine) {
result.push({
for (let i = 1; i <= oldLines.length; i++) matrix[i][0] = i;
for (let j = 1; j <= newLines.length; j++) matrix[0][j] = j;
for (let i = 1; i <= oldLines.length; i++) {
for (let j = 1; j <= newLines.length; j++) {
if (oldLines[i - 1] === newLines[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1, // deletion
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j - 1] + 1, // substitution
);
}
}
}
const chunks: DiffChunk[] = [];
let i = oldLines.length;
let j = newLines.length;
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
i--;
j--;
continue;
}
const deletion = i > 0 ? matrix[i - 1][j] : Infinity;
const insertion = j > 0 ? matrix[i][j - 1] : Infinity;
const substitution = i > 0 && j > 0 ? matrix[i - 1][j - 1] : Infinity;
if (substitution <= deletion && substitution <= insertion) {
chunks.unshift({
type: "modify",
startLeftLine: i,
endLeftLine: i + 1,
startRightLine: j,
endRightLine: j + 1,
});
i--;
j--;
} else if (deletion <= insertion) {
chunks.unshift({
type: "remove",
startLeftLine: i,
endLeftLine: i + 1,
startRightLine: j + 1,
endRightLine: j + 1,
});
i--;
} else {
chunks.unshift({
type: "add",
startLeftLine: i + 1,
endLeftLine: i + 1,
startRightLine: i + 1,
endRightLine: i + 2,
});
} else if (oldLine && !newLine) {
result.push({
type: "remove",
startLeftLine: i + 1,
endLeftLine: i + 2,
startRightLine: i + 1,
endRightLine: i + 1,
});
} else if (oldLine !== newLine) {
result.push({
type: "modify",
startLeftLine: i + 1,
endLeftLine: i + 2,
startRightLine: i + 1,
endRightLine: i + 2,
startRightLine: j,
endRightLine: j + 1,
});
j--;
}
}
// return result;
return mergeDiffs(result);
return mergeDiffs(chunks);
}
function mergeDiffs(chunks: DiffChunk[]): DiffChunk[] {