refactor: Separate matching in line-by-line algorithm
This commit is contained in:
parent
a25d06a8d7
commit
d8e0a99070
5 changed files with 141 additions and 226 deletions
|
|
@ -89,23 +89,23 @@ const htmlLineExample1 =
|
||||||
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
|
' <div class="d2h-code-line d2h-info">@@ -1 +1 @@</div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
"</tr><tr>\n" +
|
"</tr><tr>\n" +
|
||||||
' <td class="d2h-code-linenumber d2h-del">\n' +
|
' <td class="d2h-code-linenumber d2h-del d2h-change">\n' +
|
||||||
' <div class="line-num1">1</div>\n' +
|
' <div class="line-num1">1</div>\n' +
|
||||||
'<div class="line-num2"></div>\n' +
|
'<div class="line-num2"></div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
' <td class="d2h-del">\n' +
|
' <td class="d2h-del d2h-change">\n' +
|
||||||
' <div class="d2h-code-line d2h-del">\n' +
|
' <div class="d2h-code-line d2h-del d2h-change">\n' +
|
||||||
' <span class="d2h-code-line-prefix">-</span>\n' +
|
' <span class="d2h-code-line-prefix">-</span>\n' +
|
||||||
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
|
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
"</tr><tr>\n" +
|
"</tr><tr>\n" +
|
||||||
' <td class="d2h-code-linenumber d2h-ins">\n' +
|
' <td class="d2h-code-linenumber d2h-ins d2h-change">\n' +
|
||||||
' <div class="line-num1"></div>\n' +
|
' <div class="line-num1"></div>\n' +
|
||||||
'<div class="line-num2">1</div>\n' +
|
'<div class="line-num2">1</div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
' <td class="d2h-ins">\n' +
|
' <td class="d2h-ins d2h-change">\n' +
|
||||||
' <div class="d2h-code-line d2h-ins">\n' +
|
' <div class="d2h-code-line d2h-ins d2h-change">\n' +
|
||||||
' <span class="d2h-code-line-prefix">+</span>\n' +
|
' <span class="d2h-code-line-prefix">+</span>\n' +
|
||||||
' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' +
|
' <span class="d2h-code-line-ctn"><ins>test1</ins></span>\n' +
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
|
|
@ -446,23 +446,23 @@ describe("Diff2Html", () => {
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
"</tr><tr>\n" +
|
"</tr><tr>\n" +
|
||||||
' <td class="d2h-code-linenumber d2h-del">\n' +
|
' <td class="d2h-code-linenumber d2h-del d2h-change">\n' +
|
||||||
' <div class="line-num1">14</div>\n' +
|
' <div class="line-num1">14</div>\n' +
|
||||||
'<div class="line-num2"></div>\n' +
|
'<div class="line-num2"></div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
' <td class="d2h-del">\n' +
|
' <td class="d2h-del d2h-change">\n' +
|
||||||
' <div class="d2h-code-line d2h-del">\n' +
|
' <div class="d2h-code-line d2h-del d2h-change">\n' +
|
||||||
' <span class="d2h-code-line-prefix">-</span>\n' +
|
' <span class="d2h-code-line-prefix">-</span>\n' +
|
||||||
' <span class="d2h-code-line-ctn"> - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)</span>\n' +
|
' <span class="d2h-code-line-ctn"> - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)</span>\n' +
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
"</tr><tr>\n" +
|
"</tr><tr>\n" +
|
||||||
' <td class="d2h-code-linenumber d2h-ins">\n' +
|
' <td class="d2h-code-linenumber d2h-ins d2h-change">\n' +
|
||||||
' <div class="line-num1"></div>\n' +
|
' <div class="line-num1"></div>\n' +
|
||||||
'<div class="line-num2">13</div>\n' +
|
'<div class="line-num2">13</div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
' <td class="d2h-ins">\n' +
|
' <td class="d2h-ins d2h-change">\n' +
|
||||||
' <div class="d2h-code-line d2h-ins">\n' +
|
' <div class="d2h-code-line d2h-ins d2h-change">\n' +
|
||||||
' <span class="d2h-code-line-prefix">+</span>\n' +
|
' <span class="d2h-code-line-prefix">+</span>\n' +
|
||||||
' <span class="d2h-code-line-ctn"><ins>4</ins> - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)</span>\n' +
|
' <span class="d2h-code-line-ctn"><ins>4</ins> - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)</span>\n' +
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
|
|
@ -519,7 +519,7 @@ describe("Diff2Html", () => {
|
||||||
"</div>";
|
"</div>";
|
||||||
|
|
||||||
const result = html(diffExample2, { drawFileList: false });
|
const result = html(diffExample2, { drawFileList: false });
|
||||||
expect(htmlExample2).toEqual(result);
|
expect(result).toEqual(htmlExample2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import LineByLineRenderer from "../line-by-line-renderer";
|
import LineByLineRenderer from "../line-by-line-renderer";
|
||||||
import HoganJsUtils from "../hoganjs-utils";
|
import HoganJsUtils from "../hoganjs-utils";
|
||||||
import { LineType, DiffLine, DiffFile, LineMatchingType } from "../types";
|
import { LineType, DiffFile, LineMatchingType } from "../types";
|
||||||
import { CSSLineClass } from "../render-utils";
|
import { CSSLineClass } from "../render-utils";
|
||||||
|
|
||||||
describe("LineByLineRenderer", () => {
|
describe("LineByLineRenderer", () => {
|
||||||
|
|
@ -26,7 +26,7 @@ describe("LineByLineRenderer", () => {
|
||||||
it("should work for insertions", () => {
|
it("should work for insertions", () => {
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||||
let fileHtml = lineByLineRenderer.makeLineHtml(false, CSSLineClass.INSERTS, "test", undefined, 30, "+");
|
let fileHtml = lineByLineRenderer.makeLineHtml(CSSLineClass.INSERTS, "+", "test", undefined, 30);
|
||||||
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
||||||
const expected =
|
const expected =
|
||||||
"<tr>\n" +
|
"<tr>\n" +
|
||||||
|
|
@ -48,7 +48,7 @@ describe("LineByLineRenderer", () => {
|
||||||
it("should work for deletions", () => {
|
it("should work for deletions", () => {
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||||
let fileHtml = lineByLineRenderer.makeLineHtml(false, CSSLineClass.DELETES, "test", 30, undefined, "-");
|
let fileHtml = lineByLineRenderer.makeLineHtml(CSSLineClass.DELETES, "-", "test", 30, undefined);
|
||||||
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
||||||
const expected =
|
const expected =
|
||||||
"<tr>\n" +
|
"<tr>\n" +
|
||||||
|
|
@ -70,7 +70,7 @@ describe("LineByLineRenderer", () => {
|
||||||
it("should convert indents into non breakin spaces (2 white spaces)", () => {
|
it("should convert indents into non breakin spaces (2 white spaces)", () => {
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||||
let fileHtml = lineByLineRenderer.makeLineHtml(false, CSSLineClass.INSERTS, " test", undefined, 30, "+");
|
let fileHtml = lineByLineRenderer.makeLineHtml(CSSLineClass.INSERTS, "+", " test", undefined, 30);
|
||||||
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
||||||
const expected =
|
const expected =
|
||||||
"<tr>\n" +
|
"<tr>\n" +
|
||||||
|
|
@ -92,7 +92,7 @@ describe("LineByLineRenderer", () => {
|
||||||
it("should convert indents into non breakin spaces (4 white spaces)", () => {
|
it("should convert indents into non breakin spaces (4 white spaces)", () => {
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||||
let fileHtml = lineByLineRenderer.makeLineHtml(false, CSSLineClass.INSERTS, " test", undefined, 30, "+");
|
let fileHtml = lineByLineRenderer.makeLineHtml(CSSLineClass.INSERTS, "+", " test", undefined, 30);
|
||||||
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
||||||
const expected =
|
const expected =
|
||||||
"<tr>\n" +
|
"<tr>\n" +
|
||||||
|
|
@ -114,7 +114,7 @@ describe("LineByLineRenderer", () => {
|
||||||
it("should preserve tabs", () => {
|
it("should preserve tabs", () => {
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||||
let fileHtml = lineByLineRenderer.makeLineHtml(false, CSSLineClass.INSERTS, "\ttest", undefined, 30, "+");
|
let fileHtml = lineByLineRenderer.makeLineHtml(CSSLineClass.INSERTS, "+", "\ttest", undefined, 30);
|
||||||
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
fileHtml = fileHtml.replace(/\n\n+/g, "\n");
|
||||||
const expected =
|
const expected =
|
||||||
"<tr>\n" +
|
"<tr>\n" +
|
||||||
|
|
@ -473,58 +473,6 @@ describe("LineByLineRenderer", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("_processLines", () => {
|
|
||||||
it("should work for simple block header", () => {
|
|
||||||
const hoganUtils = new HoganJsUtils({});
|
|
||||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
|
||||||
const oldLines: DiffLine[] = [
|
|
||||||
{
|
|
||||||
content: "-test",
|
|
||||||
type: LineType.DELETE,
|
|
||||||
oldNumber: 1,
|
|
||||||
newNumber: undefined
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const newLines: DiffLine[] = [
|
|
||||||
{
|
|
||||||
content: "+test1r",
|
|
||||||
type: LineType.INSERT,
|
|
||||||
oldNumber: undefined,
|
|
||||||
newNumber: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const html = lineByLineRenderer.processLines(false, oldLines, newLines);
|
|
||||||
|
|
||||||
const expected =
|
|
||||||
"<tr>\n" +
|
|
||||||
' <td class="d2h-code-linenumber d2h-del">\n' +
|
|
||||||
' <div class="line-num1">1</div>\n' +
|
|
||||||
'<div class="line-num2"></div>\n' +
|
|
||||||
" </td>\n" +
|
|
||||||
' <td class="d2h-del">\n' +
|
|
||||||
' <div class="d2h-code-line d2h-del">\n' +
|
|
||||||
' <span class="d2h-code-line-prefix">-</span>\n' +
|
|
||||||
' <span class="d2h-code-line-ctn">test</span>\n' +
|
|
||||||
" </div>\n" +
|
|
||||||
" </td>\n" +
|
|
||||||
"</tr><tr>\n" +
|
|
||||||
' <td class="d2h-code-linenumber d2h-ins">\n' +
|
|
||||||
' <div class="line-num1"></div>\n' +
|
|
||||||
'<div class="line-num2">1</div>\n' +
|
|
||||||
" </td>\n" +
|
|
||||||
' <td class="d2h-ins">\n' +
|
|
||||||
' <div class="d2h-code-line d2h-ins">\n' +
|
|
||||||
' <span class="d2h-code-line-prefix">+</span>\n' +
|
|
||||||
' <span class="d2h-code-line-ctn">test1r</span>\n' +
|
|
||||||
" </div>\n" +
|
|
||||||
" </td>\n" +
|
|
||||||
"</tr>";
|
|
||||||
|
|
||||||
expect(html).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("_generateFileHtml", () => {
|
describe("_generateFileHtml", () => {
|
||||||
it("should work for simple file", () => {
|
it("should work for simple file", () => {
|
||||||
const hoganUtils = new HoganJsUtils({});
|
const hoganUtils = new HoganJsUtils({});
|
||||||
|
|
@ -595,23 +543,23 @@ describe("LineByLineRenderer", () => {
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
"</tr><tr>\n" +
|
"</tr><tr>\n" +
|
||||||
' <td class="d2h-code-linenumber d2h-del">\n' +
|
' <td class="d2h-code-linenumber d2h-del d2h-change">\n' +
|
||||||
' <div class="line-num1">2</div>\n' +
|
' <div class="line-num1">2</div>\n' +
|
||||||
'<div class="line-num2"></div>\n' +
|
'<div class="line-num2"></div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
' <td class="d2h-del">\n' +
|
' <td class="d2h-del d2h-change">\n' +
|
||||||
' <div class="d2h-code-line d2h-del">\n' +
|
' <div class="d2h-code-line d2h-del d2h-change">\n' +
|
||||||
' <span class="d2h-code-line-prefix">-</span>\n' +
|
' <span class="d2h-code-line-prefix">-</span>\n' +
|
||||||
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
|
' <span class="d2h-code-line-ctn"><del>test</del></span>\n' +
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
"</tr><tr>\n" +
|
"</tr><tr>\n" +
|
||||||
' <td class="d2h-code-linenumber d2h-ins">\n' +
|
' <td class="d2h-code-linenumber d2h-ins d2h-change">\n' +
|
||||||
' <div class="line-num1"></div>\n' +
|
' <div class="line-num1"></div>\n' +
|
||||||
'<div class="line-num2">2</div>\n' +
|
'<div class="line-num2">2</div>\n' +
|
||||||
" </td>\n" +
|
" </td>\n" +
|
||||||
' <td class="d2h-ins">\n' +
|
' <td class="d2h-ins d2h-change">\n' +
|
||||||
' <div class="d2h-code-line d2h-ins">\n' +
|
' <div class="d2h-code-line d2h-ins d2h-change">\n' +
|
||||||
' <span class="d2h-code-line-prefix">+</span>\n' +
|
' <span class="d2h-code-line-prefix">+</span>\n' +
|
||||||
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
|
' <span class="d2h-code-line-ctn"><ins>test1r</ins></span>\n' +
|
||||||
" </div>\n" +
|
" </div>\n" +
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import HoganJsUtils from "./hoganjs-utils";
|
import HoganJsUtils from "./hoganjs-utils";
|
||||||
import * as Rematch from "./rematch";
|
import * as Rematch from "./rematch";
|
||||||
import * as renderUtils from "./render-utils";
|
import * as renderUtils from "./render-utils";
|
||||||
import { DiffFile, DiffLine, LineType } from "./types";
|
import { DiffFile, DiffLine, LineType, DiffBlock } from "./types";
|
||||||
|
|
||||||
export interface LineByLineRendererConfig extends renderUtils.RenderConfig {
|
export interface LineByLineRendererConfig extends renderUtils.RenderConfig {
|
||||||
renderNothingWhenEmpty?: boolean;
|
renderNothingWhenEmpty?: boolean;
|
||||||
|
|
@ -79,7 +79,6 @@ export default class LineByLineRenderer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
|
||||||
generateFileHtml(file: DiffFile): string {
|
generateFileHtml(file: DiffFile): string {
|
||||||
const matcher = Rematch.newMatcherFn(
|
const matcher = Rematch.newMatcherFn(
|
||||||
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content)
|
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content)
|
||||||
|
|
@ -93,58 +92,79 @@ export default class LineByLineRenderer {
|
||||||
lineClass: "d2h-code-linenumber",
|
lineClass: "d2h-code-linenumber",
|
||||||
contentClass: "d2h-code-line"
|
contentClass: "d2h-code-line"
|
||||||
});
|
});
|
||||||
let oldLines: DiffLine[] = [];
|
|
||||||
let newLines: DiffLine[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < block.lines.length; i++) {
|
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
|
||||||
const diffLine = block.lines[i];
|
if (oldLines.length && newLines.length && !contextLines.length) {
|
||||||
const { prefix, content } = renderUtils.deconstructLine(diffLine.content, file.isCombined);
|
lines += this.applyRematchMatching(oldLines, newLines, matcher)
|
||||||
|
.map(([oldLines, newLines]) => this.applyLineDiff(file, oldLines, newLines))
|
||||||
if (
|
.join("");
|
||||||
diffLine.type !== LineType.INSERT &&
|
} else if (oldLines.length || newLines.length || contextLines.length) {
|
||||||
(newLines.length > 0 || (diffLine.type !== LineType.DELETE && oldLines.length > 0))
|
lines += (contextLines || [])
|
||||||
) {
|
.concat((oldLines || []).concat(newLines || []))
|
||||||
lines += this.processChangeBlock(file, oldLines, newLines, matcher);
|
.map(line => {
|
||||||
oldLines = [];
|
const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined);
|
||||||
newLines = [];
|
return this.makeLineHtml(
|
||||||
}
|
renderUtils.toCSSClass(line.type),
|
||||||
|
prefix,
|
||||||
if (diffLine.type === LineType.CONTEXT || (diffLine.type === LineType.INSERT && !oldLines.length)) {
|
|
||||||
lines += this.makeLineHtml(
|
|
||||||
file.isCombined,
|
|
||||||
renderUtils.toCSSClass(diffLine.type),
|
|
||||||
content,
|
content,
|
||||||
diffLine.oldNumber,
|
line.oldNumber,
|
||||||
diffLine.newNumber,
|
line.newNumber
|
||||||
prefix
|
|
||||||
);
|
);
|
||||||
} else if (diffLine.type === LineType.DELETE) {
|
})
|
||||||
oldLines.push(diffLine);
|
.join("");
|
||||||
} else if (diffLine.type === LineType.INSERT && Boolean(oldLines.length)) {
|
|
||||||
newLines.push(diffLine);
|
|
||||||
} else {
|
} else {
|
||||||
console.error("Unknown state in html line-by-line generator");
|
console.error("Unknown state reached while processing groups of lines", contextLines, oldLines, newLines);
|
||||||
lines += this.processChangeBlock(file, oldLines, newLines, matcher);
|
|
||||||
oldLines = [];
|
|
||||||
newLines = [];
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
lines += this.processChangeBlock(file, oldLines, newLines, matcher);
|
|
||||||
oldLines = [];
|
|
||||||
newLines = [];
|
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
})
|
})
|
||||||
.join("\n");
|
.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
processChangeBlock(
|
applyLineGroupping(block: DiffBlock): DiffLine[][][] {
|
||||||
file: DiffFile,
|
const blockLinesGroups: DiffLine[][][] = [];
|
||||||
|
|
||||||
|
let oldLines: DiffLine[] = [];
|
||||||
|
let newLines: DiffLine[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < block.lines.length; i++) {
|
||||||
|
const diffLine = block.lines[i];
|
||||||
|
|
||||||
|
if (
|
||||||
|
(diffLine.type !== LineType.INSERT && newLines.length) ||
|
||||||
|
(diffLine.type === LineType.CONTEXT && oldLines.length > 0)
|
||||||
|
) {
|
||||||
|
blockLinesGroups.push([[], oldLines, newLines]);
|
||||||
|
oldLines = [];
|
||||||
|
newLines = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diffLine.type === LineType.CONTEXT) {
|
||||||
|
blockLinesGroups.push([[diffLine], [], []]);
|
||||||
|
} else if (diffLine.type === LineType.INSERT && oldLines.length === 0) {
|
||||||
|
blockLinesGroups.push([[], [], [diffLine]]);
|
||||||
|
} else if (diffLine.type === LineType.INSERT && oldLines.length > 0) {
|
||||||
|
newLines.push(diffLine);
|
||||||
|
} else if (diffLine.type === LineType.DELETE) {
|
||||||
|
oldLines.push(diffLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldLines.length || newLines.length) {
|
||||||
|
blockLinesGroups.push([[], oldLines, newLines]);
|
||||||
|
oldLines = [];
|
||||||
|
newLines = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockLinesGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyRematchMatching(
|
||||||
oldLines: DiffLine[],
|
oldLines: DiffLine[],
|
||||||
newLines: DiffLine[],
|
newLines: DiffLine[],
|
||||||
matcher: Rematch.MatcherFn<DiffLine>
|
matcher: Rematch.MatcherFn<DiffLine>
|
||||||
): string {
|
): DiffLine[][][] {
|
||||||
const comparisons = oldLines.length * newLines.length;
|
const comparisons = oldLines.length * newLines.length;
|
||||||
const maxLineSizeInBlock = Math.max.apply(
|
const maxLineSizeInBlock = Math.max.apply(
|
||||||
null,
|
null,
|
||||||
|
|
@ -155,17 +175,14 @@ export default class LineByLineRenderer {
|
||||||
maxLineSizeInBlock < this.config.maxLineSizeInBlockForComparison &&
|
maxLineSizeInBlock < this.config.maxLineSizeInBlockForComparison &&
|
||||||
(this.config.matching === "lines" || this.config.matching === "words");
|
(this.config.matching === "lines" || this.config.matching === "words");
|
||||||
|
|
||||||
const [matches, insertType, deleteType] = doMatching
|
const matches = doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
|
||||||
? [matcher(oldLines, newLines), renderUtils.CSSLineClass.INSERT_CHANGES, renderUtils.CSSLineClass.DELETE_CHANGES]
|
|
||||||
: [[[oldLines, newLines]], renderUtils.CSSLineClass.INSERTS, renderUtils.CSSLineClass.DELETES];
|
|
||||||
|
|
||||||
let lines = "";
|
return matches;
|
||||||
matches.forEach(match => {
|
}
|
||||||
oldLines = match[0];
|
|
||||||
newLines = match[1];
|
|
||||||
|
|
||||||
let processedOldLines = "";
|
applyLineDiff(file: DiffFile, oldLines: DiffLine[], newLines: DiffLine[]): string {
|
||||||
let processedNewLines = "";
|
let oldLinesHtml = "";
|
||||||
|
let newLinesHtml = "";
|
||||||
|
|
||||||
const common = Math.min(oldLines.length, newLines.length);
|
const common = Math.min(oldLines.length, newLines.length);
|
||||||
|
|
||||||
|
|
@ -176,94 +193,54 @@ export default class LineByLineRenderer {
|
||||||
|
|
||||||
const diff = renderUtils.diffHighlight(oldLine.content, newLine.content, file.isCombined, this.config);
|
const diff = renderUtils.diffHighlight(oldLine.content, newLine.content, file.isCombined, this.config);
|
||||||
|
|
||||||
processedOldLines += this.makeLineHtml(
|
oldLinesHtml += this.makeLineHtml(
|
||||||
file.isCombined,
|
renderUtils.CSSLineClass.DELETE_CHANGES,
|
||||||
deleteType,
|
diff.oldLine.prefix,
|
||||||
diff.oldLine.content,
|
diff.oldLine.content,
|
||||||
oldLine.oldNumber,
|
oldLine.oldNumber,
|
||||||
oldLine.newNumber,
|
|
||||||
diff.oldLine.prefix
|
|
||||||
);
|
|
||||||
processedNewLines += this.makeLineHtml(
|
|
||||||
file.isCombined,
|
|
||||||
insertType,
|
|
||||||
diff.newLine.content,
|
|
||||||
newLine.oldNumber,
|
|
||||||
newLine.newNumber,
|
|
||||||
diff.newLine.prefix
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines += processedOldLines + processedNewLines;
|
|
||||||
lines += this.processLines(file.isCombined, oldLines.slice(common), newLines.slice(common));
|
|
||||||
});
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
|
||||||
makeLineHtml(
|
|
||||||
isCombined: boolean,
|
|
||||||
type: renderUtils.CSSLineClass,
|
|
||||||
content: string,
|
|
||||||
oldNumber?: number,
|
|
||||||
newNumber?: number,
|
|
||||||
possiblePrefix?: string
|
|
||||||
): string {
|
|
||||||
const lineNumberTemplate = this.hoganUtils.render(baseTemplatesPath, "numbers", {
|
|
||||||
oldNumber: oldNumber || "",
|
|
||||||
newNumber: newNumber || ""
|
|
||||||
});
|
|
||||||
|
|
||||||
let lineWithoutPrefix = content;
|
|
||||||
let prefix = possiblePrefix;
|
|
||||||
|
|
||||||
if (!prefix) {
|
|
||||||
const lineWithPrefix = renderUtils.deconstructLine(content, isCombined);
|
|
||||||
prefix = lineWithPrefix.prefix;
|
|
||||||
lineWithoutPrefix = lineWithPrefix.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prefix === " ") {
|
|
||||||
prefix = " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.hoganUtils.render(genericTemplatesPath, "line", {
|
|
||||||
type: type,
|
|
||||||
lineClass: "d2h-code-linenumber",
|
|
||||||
contentClass: "d2h-code-line",
|
|
||||||
prefix: prefix,
|
|
||||||
content: lineWithoutPrefix,
|
|
||||||
lineNumber: lineNumberTemplate
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make this private after improving tests
|
|
||||||
processLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): string {
|
|
||||||
let lines = "";
|
|
||||||
|
|
||||||
for (let i = 0; i < oldLines.length; i++) {
|
|
||||||
const oldLine = oldLines[i];
|
|
||||||
lines += this.makeLineHtml(
|
|
||||||
isCombined,
|
|
||||||
renderUtils.toCSSClass(oldLine.type),
|
|
||||||
oldLine.content,
|
|
||||||
oldLine.oldNumber,
|
|
||||||
oldLine.newNumber
|
oldLine.newNumber
|
||||||
);
|
);
|
||||||
}
|
newLinesHtml += this.makeLineHtml(
|
||||||
|
renderUtils.CSSLineClass.INSERT_CHANGES,
|
||||||
for (let j = 0; j < newLines.length; j++) {
|
diff.newLine.prefix,
|
||||||
const newLine = newLines[j];
|
diff.newLine.content,
|
||||||
lines += this.makeLineHtml(
|
|
||||||
isCombined,
|
|
||||||
renderUtils.toCSSClass(newLine.type),
|
|
||||||
newLine.content,
|
|
||||||
newLine.oldNumber,
|
newLine.oldNumber,
|
||||||
newLine.newNumber
|
newLine.newNumber
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
const remainingLines = oldLines
|
||||||
|
.slice(common)
|
||||||
|
.concat(newLines.slice(common))
|
||||||
|
.map(line => {
|
||||||
|
const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined);
|
||||||
|
return this.makeLineHtml(renderUtils.toCSSClass(line.type), prefix, content, line.oldNumber, line.newNumber);
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
return oldLinesHtml + newLinesHtml + remainingLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make this private after improving tests
|
||||||
|
makeLineHtml(
|
||||||
|
type: renderUtils.CSSLineClass,
|
||||||
|
prefix: string,
|
||||||
|
content: string,
|
||||||
|
oldNumber?: number,
|
||||||
|
newNumber?: number
|
||||||
|
): string {
|
||||||
|
const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, "numbers", {
|
||||||
|
oldNumber: oldNumber || "",
|
||||||
|
newNumber: newNumber || ""
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.hoganUtils.render(genericTemplatesPath, "line", {
|
||||||
|
type: type,
|
||||||
|
lineClass: "d2h-code-linenumber",
|
||||||
|
contentClass: "d2h-code-line",
|
||||||
|
prefix: prefix === " " ? " " : prefix,
|
||||||
|
content: content,
|
||||||
|
lineNumber: lineNumberHtml
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -240,19 +240,13 @@ export function diffHighlight(
|
||||||
|
|
||||||
const changedWords: jsDiff.Change[] = [];
|
const changedWords: jsDiff.Change[] = [];
|
||||||
if (diffStyle === "word" && matching === "words") {
|
if (diffStyle === "word" && matching === "words") {
|
||||||
let treshold = 0.25;
|
|
||||||
|
|
||||||
if (typeof matchWordsThreshold !== "undefined") {
|
|
||||||
treshold = matchWordsThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
const removed = diff.filter(element => element.removed);
|
const removed = diff.filter(element => element.removed);
|
||||||
const added = diff.filter(element => element.added);
|
const added = diff.filter(element => element.added);
|
||||||
const chunks = matcher(added, removed);
|
const chunks = matcher(added, removed);
|
||||||
chunks.forEach(chunk => {
|
chunks.forEach(chunk => {
|
||||||
if (chunk[0].length === 1 && chunk[1].length === 1) {
|
if (chunk[0].length === 1 && chunk[1].length === 1) {
|
||||||
const dist = distance(chunk[0][0], chunk[1][0]);
|
const dist = distance(chunk[0][0], chunk[1][0]);
|
||||||
if (dist < treshold) {
|
if (dist < matchWordsThreshold) {
|
||||||
changedWords.push(chunk[0][0]);
|
changedWords.push(chunk[0][0]);
|
||||||
changedWords.push(chunk[1][0]);
|
changedWords.push(chunk[1][0]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -331,15 +331,11 @@ export default class SideBySideRenderer {
|
||||||
lineWithoutPrefix = lineWithPrefix.content;
|
lineWithoutPrefix = lineWithPrefix.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefix === " ") {
|
|
||||||
prefix = " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.hoganUtils.render(genericTemplatesPath, "line", {
|
return this.hoganUtils.render(genericTemplatesPath, "line", {
|
||||||
type: preparedType,
|
type: preparedType,
|
||||||
lineClass: lineClass,
|
lineClass: lineClass,
|
||||||
contentClass: contentClass,
|
contentClass: contentClass,
|
||||||
prefix: prefix,
|
prefix: prefix === " " ? " " : prefix,
|
||||||
content: lineWithoutPrefix,
|
content: lineWithoutPrefix,
|
||||||
lineNumber: number
|
lineNumber: number
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue