Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

/**
* Modified by Piotr Kaminski.
* Modified by Piotr Kaminski and Sergei Vorobev.
*/

/**
Expand Down Expand Up @@ -131,13 +131,21 @@ diff.prototype.diff_main = function(text1, text2, opt_checklines,
var checklines = opt_checklines;

// Trim off common prefix (speedup).
var commonlength = this.diff_commonPrefix(text1, text2);
if (checklines) {
var commonlength = this.diff_commonPrefix_newLine(text1, text2);
} else {
var commonlength = this.diff_commonPrefix(text1, text2);
}
var commonprefix = text1.substring(0, commonlength);
text1 = text1.substring(commonlength);
text2 = text2.substring(commonlength);

// Trim off common suffix (speedup).
commonlength = this.diff_commonSuffix(text1, text2);
if (checklines) {
commonlength = this.diff_commonSuffix_newLine(text1, text2);
} else {
commonlength = this.diff_commonSuffix(text1, text2);
}
var commonsuffix = text1.substring(text1.length - commonlength);
text1 = text1.substring(0, text1.length - commonlength);
text2 = text2.substring(0, text2.length - commonlength);
Expand Down Expand Up @@ -570,6 +578,32 @@ diff.prototype.diff_commonPrefix = function(text1, text2) {
return pointermid;
};

/**
* Determine the common prefix of two strings making delimitors only at new lines.
* @param {string} text1 First string.
* @param {string} text2 Second string.
* @return {number} The number of characters common to the start of each
* string.
*/
diff.prototype.diff_commonPrefix_newLine = function(text1, text2) {
var idx = this.diff_commonPrefix(text1, text2);
// special handling for the case when the whole string is matching
if (idx == text1.length && idx == text2.length) {
return idx;
}
if (idx == text1.length && text2[idx] == "\n") {
return idx
}
if (idx == text2.length && text1[idx] == "\n") {
return idx
}
var offset = text1.substring(0, idx).lastIndexOf("\n");
if (offset == -1) {
return 0;
}
return offset + 1;
};


/**
* Determine the common suffix of two strings.
Expand Down Expand Up @@ -602,6 +636,31 @@ diff.prototype.diff_commonSuffix = function(text1, text2) {
return pointermid;
};

/**
* Determine the common suffix of two strings making delimitors only at new lines.
* @param {string} text1 First string.
* @param {string} text2 Second string.
* @return {number} The number of characters common to the end of each string.
*/
diff.prototype.diff_commonSuffix_newLine = function(text1, text2) {
var idx = this.diff_commonSuffix(text1, text2);
// special handling for the case when the whole string is matching
if (idx == text1.length && idx == text2.length) {
return idx;
}
if (idx == text1.length && text2[text2.length - idx - 1] == "\n") {
return idx
}
if (idx == text2.length && text1[text1.length - idx - 1] == "\n") {
return idx
}
var offset = text1.substring(text1.length - idx).indexOf("\n");
if (offset == -1) {
return 0;
}
return idx - offset;
};


/**
* Determine if the suffix of one string is the prefix of another.
Expand Down
2 changes: 2 additions & 0 deletions tests/diff_test.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@

var tests = [
'testDiffCommonPrefix',
'testDiffCommonPrefixNewLine',
'testDiffCommonSuffix',
'testDiffCommonSuffixNewLine',
'testDiffCommonOverlap',
'testDiffHalfMatch',
'testDiffLinesToChars',
Expand Down
37 changes: 37 additions & 0 deletions tests/diff_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ function testDiffCommonPrefix() {
assertEquals(4, dmp.diff_commonPrefix('1234', '1234xyz'));
}

function testDiffCommonPrefixNewLine() {
// Detect any common prefix in repsect to new lines.
// Null case.
assertEquals(0, dmp.diff_commonPrefix_newLine('abc', 'abx'));

// Non-null case.
assertEquals(3, dmp.diff_commonPrefix_newLine('12\n34abcdef', '12\n34xyz'));

// Multiply \n case.
assertEquals(6, dmp.diff_commonPrefix_newLine('12\n34\n1abcdef', '12\n34\n1xyz'));

// Whole case.
assertEquals(4, dmp.diff_commonPrefix_newLine('1234', '1234\nxyz'));
assertEquals(0, dmp.diff_commonPrefix_newLine('1234', '12345\nxyz'));
}

function testDiffCommonSuffix() {
// Detect any common suffix.
// Null case.
Expand All @@ -103,6 +119,22 @@ function testDiffCommonSuffix() {
assertEquals(4, dmp.diff_commonSuffix('1234', 'xyz1234'));
}

function testDiffCommonSuffixNewLine() {
// Detect any common suffix in respect to new lines.
// Null case.
assertEquals(0, dmp.diff_commonSuffix_newLine('abc', 'xbc'));

// Non-null case.
assertEquals(3, dmp.diff_commonSuffix_newLine('abcdef12\n34', 'xyz12\n34'));

// Multiply \n case.
assertEquals(6, dmp.diff_commonSuffix_newLine('abcdef1\n12\n34', 'xyz1\n12\n34'));

// Whole case.
assertEquals(4, dmp.diff_commonSuffix_newLine('1234', 'xyz\n1234'));
assertEquals(0, dmp.diff_commonSuffix_newLine('1234', 'xyz\n01234'));
}

function testDiffCommonOverlap() {
// Detect any suffix/prefix overlap.
// Null case.
Expand Down Expand Up @@ -587,6 +619,11 @@ function testDiffMain() {
// Large equality.
assertEquivalent([[DIFF_INSERT, ' '], [DIFF_EQUAL, 'a'], [DIFF_INSERT, 'nd'], [DIFF_EQUAL, ' [[Pennsylvania]]'], [DIFF_DELETE, ' and [[New']], dmp.diff_main('a [[Pennsylvania]] and [[New', ' and [[Pennsylvania]]', false));

// Codifying a suboptimal but a technically correct diff
assertEquivalent([[DIFF_EQUAL, 'def x():\n pass\n\ndef '], [DIFF_DELETE, 'y():\n pass\n\ndef '], [DIFF_EQUAL, 'z():\n pass\n']], dmp.diff_main('def x():\n pass\n\ndef y():\n pass\n\ndef z():\n pass\n', 'def x():\n pass\n\ndef z():\n pass\n', false));
// Better diff when multiline heuristic is used
assertEquivalent([[DIFF_EQUAL, 'def x():\n pass\n\n'], [DIFF_DELETE, 'def y():\n pass\n\n'], [DIFF_EQUAL, 'def z():\n pass\n']], dmp.diff_main('def x():\n pass\n\ndef y():\n pass\n\ndef z():\n pass\n', 'def x():\n pass\n\ndef z():\n pass\n', true));

// Timeout.
dmp.Diff_Timeout = 0.1; // 100ms
var a = '`Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n';
Expand Down
2 changes: 1 addition & 1 deletion tests/speedtest.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <H1>Diff Speed Test</H1>
// No warmup loop since it risks triggering an 'unresponsive script' dialog
// in client-side JavaScript
var ms_start = (new Date()).getTime();
var d = dmp.diff_main(text1, text2, false);
var d = dmp.diff_main(text1, text2, true);
var ms_end = (new Date()).getTime();

var ds = dmp.diff_prettyHtml(d);
Expand Down