3 * Copyright 2018 The diff-match-patch Authors.
4 * https://github.com/google/diff-match-patch
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * @fileoverview Computes the difference between two texts to create a patch.
21 * Applies the patch onto another text, allowing for errors.
22 * @author fraser@google.com (Neil Fraser)
26 * Class containing the diff, match and patch methods.
29 var diff_match_patch = function() {
32 // Redefine these in your program to override the defaults.
34 // Number of seconds to map a diff before giving up (0 for infinity).
35 this.Diff_Timeout
= 1.0;
36 // Cost of an empty edit operation in terms of edit characters.
37 this.Diff_EditCost
= 4;
38 // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
39 this.Match_Threshold
= 0.5;
40 // How far to search for a match (0 = exact location, 1000+ = broad match).
41 // A match this many characters away from the expected location will add
42 // 1.0 to the score (0.0 is a perfect match).
43 this.Match_Distance
= 1000;
44 // When deleting a large block of text (over ~64 characters), how close do
45 // the contents have to be to match the expected contents. (0.0 = perfection,
46 // 1.0 = very loose). Note that Match_Threshold controls how closely the
47 // end points of a delete need to match.
48 this.Patch_DeleteThreshold
= 0.5;
49 // Chunk size for context length.
50 this.Patch_Margin
= 4;
52 // The number of bits in an int.
53 this.Match_MaxBits
= 32;
61 * The data structure representing a diff is an array of tuples:
62 * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
63 * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
70 * Class representing one diff tuple.
71 * Attempts to look like a two-element array (which is what this used to be).
72 * @param {number} op Operation, one of: DIFF_DELETE, DIFF_INSERT, DIFF_EQUAL.
73 * @param {string} text Text to be deleted, inserted, or retained.
76 diff_match_patch
.Diff = function(op
, text
) {
81 diff_match_patch
.Diff
.prototype.length
= 2;
84 * Emulate the output of a two-element array.
85 * @return {string} Diff operation as a string.
87 diff_match_patch
.Diff
.prototype.toString = function() {
88 return this[0] + ',' + this[1];
93 * Find the differences between two texts. Simplifies the problem by stripping
94 * any common prefix or suffix off the texts before diffing.
95 * @param {string} text1 Old string to be diffed.
96 * @param {string} text2 New string to be diffed.
97 * @param {boolean=} opt_checklines Optional speedup flag. If present and false,
98 * then don't run a line-level diff first to identify the changed areas.
99 * Defaults to true, which does a faster, slightly less optimal diff.
100 * @param {number=} opt_deadline Optional time when the diff should be complete
101 * by. Used internally for recursive calls. Users should set DiffTimeout
103 * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
105 diff_match_patch
.prototype.diff_main = function(text1
, text2
, opt_checklines
,
107 // Set a deadline by which time the diff must be complete.
108 if (typeof opt_deadline
== 'undefined') {
109 if (this.Diff_Timeout
<= 0) {
110 opt_deadline
= Number
.MAX_VALUE
;
112 opt_deadline
= (new Date
).getTime() + this.Diff_Timeout
* 1000;
115 var deadline
= opt_deadline
;
117 // Check for null inputs.
118 if (text1
== null || text2
== null) {
119 throw new Error('Null input. (diff_main)');
122 // Check for equality (speedup).
123 if (text1
== text2
) {
125 return [new diff_match_patch
.Diff(DIFF_EQUAL
, text1
)];
130 if (typeof opt_checklines
== 'undefined') {
131 opt_checklines
= true;
133 var checklines
= opt_checklines
;
135 // Trim off common prefix (speedup).
136 var commonlength
= this.diff_commonPrefix(text1
, text2
);
137 var commonprefix
= text1
.substring(0, commonlength
);
138 text1
= text1
.substring(commonlength
);
139 text2
= text2
.substring(commonlength
);
141 // Trim off common suffix (speedup).
142 commonlength
= this.diff_commonSuffix(text1
, text2
);
143 var commonsuffix
= text1
.substring(text1
.length
- commonlength
);
144 text1
= text1
.substring(0, text1
.length
- commonlength
);
145 text2
= text2
.substring(0, text2
.length
- commonlength
);
147 // Compute the diff on the middle block.
148 var diffs
= this.diff_compute_(text1
, text2
, checklines
, deadline
);
150 // Restore the prefix and suffix.
152 diffs
.unshift(new diff_match_patch
.Diff(DIFF_EQUAL
, commonprefix
));
155 diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, commonsuffix
));
157 this.diff_cleanupMerge(diffs
);
163 * Find the differences between two texts. Assumes that the texts do not
164 * have any common prefix or suffix.
165 * @param {string} text1 Old string to be diffed.
166 * @param {string} text2 New string to be diffed.
167 * @param {boolean} checklines Speedup flag. If false, then don't run a
168 * line-level diff first to identify the changed areas.
169 * If true, then run a faster, slightly less optimal diff.
170 * @param {number} deadline Time when the diff should be complete by.
171 * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
174 diff_match_patch
.prototype.diff_compute_ = function(text1
, text2
, checklines
,
179 // Just add some text (speedup).
180 return [new diff_match_patch
.Diff(DIFF_INSERT
, text2
)];
184 // Just delete some text (speedup).
185 return [new diff_match_patch
.Diff(DIFF_DELETE
, text1
)];
188 var longtext
= text1
.length
> text2
.length
? text1
: text2
;
189 var shorttext
= text1
.length
> text2
.length
? text2
: text1
;
190 var i
= longtext
.indexOf(shorttext
);
192 // Shorter text is inside the longer text (speedup).
193 diffs
= [new diff_match_patch
.Diff(DIFF_INSERT
, longtext
.substring(0, i
)),
194 new diff_match_patch
.Diff(DIFF_EQUAL
, shorttext
),
195 new diff_match_patch
.Diff(DIFF_INSERT
,
196 longtext
.substring(i
+ shorttext
.length
))];
197 // Swap insertions for deletions if diff is reversed.
198 if (text1
.length
> text2
.length
) {
199 diffs
[0][0] = diffs
[2][0] = DIFF_DELETE
;
204 if (shorttext
.length
== 1) {
205 // Single character string.
206 // After the previous speedup, the character can't be an equality.
207 return [new diff_match_patch
.Diff(DIFF_DELETE
, text1
),
208 new diff_match_patch
.Diff(DIFF_INSERT
, text2
)];
211 // Check to see if the problem can be split in two.
212 var hm
= this.diff_halfMatch_(text1
, text2
);
214 // A half-match was found, sort out the return data.
219 var mid_common
= hm
[4];
220 // Send both pairs off for separate processing.
221 var diffs_a
= this.diff_main(text1_a
, text2_a
, checklines
, deadline
);
222 var diffs_b
= this.diff_main(text1_b
, text2_b
, checklines
, deadline
);
223 // Merge the results.
224 return diffs_a
.concat([new diff_match_patch
.Diff(DIFF_EQUAL
, mid_common
)],
228 if (checklines
&& text1
.length
> 100 && text2
.length
> 100) {
229 return this.diff_lineMode_(text1
, text2
, deadline
);
232 return this.diff_bisect_(text1
, text2
, deadline
);
237 * Do a quick line-level diff on both strings, then rediff the parts for
239 * This speedup can produce non-minimal diffs.
240 * @param {string} text1 Old string to be diffed.
241 * @param {string} text2 New string to be diffed.
242 * @param {number} deadline Time when the diff should be complete by.
243 * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
246 diff_match_patch
.prototype.diff_lineMode_ = function(text1
, text2
, deadline
) {
247 // Scan the text on a line-by-line basis first.
248 var a
= this.diff_linesToChars_(text1
, text2
);
251 var linearray
= a
.lineArray
;
253 var diffs
= this.diff_main(text1
, text2
, false, deadline
);
255 // Convert the diff back to original text.
256 this.diff_charsToLines_(diffs
, linearray
);
257 // Eliminate freak matches (e.g. blank lines)
258 this.diff_cleanupSemantic(diffs
);
260 // Rediff any replacement blocks, this time character-by-character.
261 // Add a dummy entry at the end.
262 diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, ''));
264 var count_delete
= 0;
265 var count_insert
= 0;
266 var text_delete
= '';
267 var text_insert
= '';
268 while (pointer
< diffs
.length
) {
269 switch (diffs
[pointer
][0]) {
272 text_insert
+= diffs
[pointer
][1];
276 text_delete
+= diffs
[pointer
][1];
279 // Upon reaching an equality, check for prior redundancies.
280 if (count_delete
>= 1 && count_insert
>= 1) {
281 // Delete the offending records and add the merged ones.
282 diffs
.splice(pointer
- count_delete
- count_insert
,
283 count_delete
+ count_insert
);
284 pointer
= pointer
- count_delete
- count_insert
;
286 this.diff_main(text_delete
, text_insert
, false, deadline
);
287 for (var j
= subDiff
.length
- 1; j
>= 0; j
--) {
288 diffs
.splice(pointer
, 0, subDiff
[j
]);
290 pointer
= pointer
+ subDiff
.length
;
300 diffs
.pop(); // Remove the dummy entry at the end.
307 * Find the 'middle snake' of a diff, split the problem in two
308 * and return the recursively constructed diff.
309 * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
310 * @param {string} text1 Old string to be diffed.
311 * @param {string} text2 New string to be diffed.
312 * @param {number} deadline Time at which to bail if not yet complete.
313 * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
316 diff_match_patch
.prototype.diff_bisect_ = function(text1
, text2
, deadline
) {
317 // Cache the text lengths to prevent multiple calls.
318 var text1_length
= text1
.length
;
319 var text2_length
= text2
.length
;
320 var max_d
= Math
.ceil((text1_length
+ text2_length
) / 2);
321 var v_offset
= max_d
;
322 var v_length
= 2 * max_d
;
323 var v1
= new Array(v_length
);
324 var v2
= new Array(v_length
);
325 // Setting all elements to -1 is faster in Chrome & Firefox than mixing
326 // integers and undefined.
327 for (var x
= 0; x
< v_length
; x
++) {
331 v1
[v_offset
+ 1] = 0;
332 v2
[v_offset
+ 1] = 0;
333 var delta
= text1_length
- text2_length
;
334 // If the total number of characters is odd, then the front path will collide
335 // with the reverse path.
336 var front
= (delta
% 2 != 0);
337 // Offsets for start and end of k loop.
338 // Prevents mapping of space beyond the grid.
343 for (var d
= 0; d
< max_d
; d
++) {
344 // Bail out if deadline is reached.
345 if ((new Date()).getTime() > deadline
) {
349 // Walk the front path one step.
350 for (var k1
= -d
+ k1start
; k1
<= d
- k1end
; k1
+= 2) {
351 var k1_offset
= v_offset
+ k1
;
353 if (k1
== -d
|| (k1
!= d
&& v1
[k1_offset
- 1] < v1
[k1_offset
+ 1])) {
354 x1
= v1
[k1_offset
+ 1];
356 x1
= v1
[k1_offset
- 1] + 1;
359 while (x1
< text1_length
&& y1
< text2_length
&&
360 text1
.charAt(x1
) == text2
.charAt(y1
)) {
365 if (x1
> text1_length
) {
366 // Ran off the right of the graph.
368 } else if (y1
> text2_length
) {
369 // Ran off the bottom of the graph.
372 var k2_offset
= v_offset
+ delta
- k1
;
373 if (k2_offset
>= 0 && k2_offset
< v_length
&& v2
[k2_offset
] != -1) {
374 // Mirror x2 onto top-left coordinate system.
375 var x2
= text1_length
- v2
[k2_offset
];
378 return this.diff_bisectSplit_(text1
, text2
, x1
, y1
, deadline
);
384 // Walk the reverse path one step.
385 for (var k2
= -d
+ k2start
; k2
<= d
- k2end
; k2
+= 2) {
386 var k2_offset
= v_offset
+ k2
;
388 if (k2
== -d
|| (k2
!= d
&& v2
[k2_offset
- 1] < v2
[k2_offset
+ 1])) {
389 x2
= v2
[k2_offset
+ 1];
391 x2
= v2
[k2_offset
- 1] + 1;
394 while (x2
< text1_length
&& y2
< text2_length
&&
395 text1
.charAt(text1_length
- x2
- 1) ==
396 text2
.charAt(text2_length
- y2
- 1)) {
401 if (x2
> text1_length
) {
402 // Ran off the left of the graph.
404 } else if (y2
> text2_length
) {
405 // Ran off the top of the graph.
408 var k1_offset
= v_offset
+ delta
- k2
;
409 if (k1_offset
>= 0 && k1_offset
< v_length
&& v1
[k1_offset
] != -1) {
410 var x1
= v1
[k1_offset
];
411 var y1
= v_offset
+ x1
- k1_offset
;
412 // Mirror x2 onto top-left coordinate system.
413 x2
= text1_length
- x2
;
416 return this.diff_bisectSplit_(text1
, text2
, x1
, y1
, deadline
);
422 // Diff took too long and hit the deadline or
423 // number of diffs equals number of characters, no commonality at all.
424 return [new diff_match_patch
.Diff(DIFF_DELETE
, text1
),
425 new diff_match_patch
.Diff(DIFF_INSERT
, text2
)];
430 * Given the location of the 'middle snake', split the diff in two parts
432 * @param {string} text1 Old string to be diffed.
433 * @param {string} text2 New string to be diffed.
434 * @param {number} x Index of split point in text1.
435 * @param {number} y Index of split point in text2.
436 * @param {number} deadline Time at which to bail if not yet complete.
437 * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
440 diff_match_patch
.prototype.diff_bisectSplit_ = function(text1
, text2
, x
, y
,
442 var text1a
= text1
.substring(0, x
);
443 var text2a
= text2
.substring(0, y
);
444 var text1b
= text1
.substring(x
);
445 var text2b
= text2
.substring(y
);
447 // Compute both diffs serially.
448 var diffs
= this.diff_main(text1a
, text2a
, false, deadline
);
449 var diffsb
= this.diff_main(text1b
, text2b
, false, deadline
);
451 return diffs
.concat(diffsb
);
456 * Split two texts into an array of strings. Reduce the texts to a string of
457 * hashes where each Unicode character represents one line.
458 * @param {string} text1 First string.
459 * @param {string} text2 Second string.
460 * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
461 * An object containing the encoded text1, the encoded text2 and
462 * the array of unique strings.
463 * The zeroth element of the array of unique strings is intentionally blank.
466 diff_match_patch
.prototype.diff_linesToChars_ = function(text1
, text2
) {
467 var lineArray
= []; // e.g. lineArray[4] == 'Hello\n'
468 var lineHash
= {}; // e.g. lineHash['Hello\n'] == 4
470 // '\x00' is a valid character, but various debuggers don't like it.
471 // So we'll insert a junk entry to avoid generating a null character.
475 * Split a text into an array of strings. Reduce the texts to a string of
476 * hashes where each Unicode character represents one line.
477 * Modifies linearray and linehash through being a closure.
478 * @param {string} text String to encode.
479 * @return {string} Encoded string.
482 function diff_linesToCharsMunge_(text
) {
484 // Walk the text, pulling out a substring for each line.
485 // text.split('\n') would would temporarily double our memory footprint.
486 // Modifying text would create many large strings to garbage collect.
489 // Keeping our own length variable is faster than looking it up.
490 var lineArrayLength
= lineArray
.length
;
491 while (lineEnd
< text
.length
- 1) {
492 lineEnd
= text
.indexOf('\n', lineStart
);
494 lineEnd
= text
.length
- 1;
496 var line
= text
.substring(lineStart
, lineEnd
+ 1);
498 if (lineHash
.hasOwnProperty
? lineHash
.hasOwnProperty(line
) :
499 (lineHash
[line
] !== undefined)) {
500 chars
+= String
.fromCharCode(lineHash
[line
]);
502 if (lineArrayLength
== maxLines
) {
503 // Bail out at 65535 because
504 // String.fromCharCode(65536) == String.fromCharCode(0)
505 line
= text
.substring(lineStart
);
506 lineEnd
= text
.length
;
508 chars
+= String
.fromCharCode(lineArrayLength
);
509 lineHash
[line
] = lineArrayLength
;
510 lineArray
[lineArrayLength
++] = line
;
512 lineStart
= lineEnd
+ 1;
516 // Allocate 2/3rds of the space for text1, the rest for text2.
517 var maxLines
= 40000;
518 var chars1
= diff_linesToCharsMunge_(text1
);
520 var chars2
= diff_linesToCharsMunge_(text2
);
521 return {chars1
: chars1
, chars2
: chars2
, lineArray
: lineArray
};
526 * Rehydrate the text in a diff from a string of line hashes to real lines of
528 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
529 * @param {!Array.<string>} lineArray Array of unique strings.
532 diff_match_patch
.prototype.diff_charsToLines_ = function(diffs
, lineArray
) {
533 for (var i
= 0; i
< diffs
.length
; i
++) {
534 var chars
= diffs
[i
][1];
536 for (var j
= 0; j
< chars
.length
; j
++) {
537 text
[j
] = lineArray
[chars
.charCodeAt(j
)];
539 diffs
[i
][1] = text
.join('');
545 * Determine the common prefix of two strings.
546 * @param {string} text1 First string.
547 * @param {string} text2 Second string.
548 * @return {number} The number of characters common to the start of each
551 diff_match_patch
.prototype.diff_commonPrefix = function(text1
, text2
) {
552 // Quick check for common null cases.
553 if (!text1
|| !text2
|| text1
.charAt(0) != text2
.charAt(0)) {
557 // Performance analysis: https://neil.fraser.name/news/2007/10/09/
559 var pointermax
= Math
.min(text1
.length
, text2
.length
);
560 var pointermid
= pointermax
;
561 var pointerstart
= 0;
562 while (pointermin
< pointermid
) {
563 if (text1
.substring(pointerstart
, pointermid
) ==
564 text2
.substring(pointerstart
, pointermid
)) {
565 pointermin
= pointermid
;
566 pointerstart
= pointermin
;
568 pointermax
= pointermid
;
570 pointermid
= Math
.floor((pointermax
- pointermin
) / 2 + pointermin
);
577 * Determine the common suffix of two strings.
578 * @param {string} text1 First string.
579 * @param {string} text2 Second string.
580 * @return {number} The number of characters common to the end of each string.
582 diff_match_patch
.prototype.diff_commonSuffix = function(text1
, text2
) {
583 // Quick check for common null cases.
584 if (!text1
|| !text2
||
585 text1
.charAt(text1
.length
- 1) != text2
.charAt(text2
.length
- 1)) {
589 // Performance analysis: https://neil.fraser.name/news/2007/10/09/
591 var pointermax
= Math
.min(text1
.length
, text2
.length
);
592 var pointermid
= pointermax
;
594 while (pointermin
< pointermid
) {
595 if (text1
.substring(text1
.length
- pointermid
, text1
.length
- pointerend
) ==
596 text2
.substring(text2
.length
- pointermid
, text2
.length
- pointerend
)) {
597 pointermin
= pointermid
;
598 pointerend
= pointermin
;
600 pointermax
= pointermid
;
602 pointermid
= Math
.floor((pointermax
- pointermin
) / 2 + pointermin
);
609 * Determine if the suffix of one string is the prefix of another.
610 * @param {string} text1 First string.
611 * @param {string} text2 Second string.
612 * @return {number} The number of characters common to the end of the first
613 * string and the start of the second string.
616 diff_match_patch
.prototype.diff_commonOverlap_ = function(text1
, text2
) {
617 // Cache the text lengths to prevent multiple calls.
618 var text1_length
= text1
.length
;
619 var text2_length
= text2
.length
;
620 // Eliminate the null case.
621 if (text1_length
== 0 || text2_length
== 0) {
624 // Truncate the longer string.
625 if (text1_length
> text2_length
) {
626 text1
= text1
.substring(text1_length
- text2_length
);
627 } else if (text1_length
< text2_length
) {
628 text2
= text2
.substring(0, text1_length
);
630 var text_length
= Math
.min(text1_length
, text2_length
);
631 // Quick check for the worst case.
632 if (text1
== text2
) {
636 // Start by looking for a single character match
637 // and increase length until no match is found.
638 // Performance analysis: https://neil.fraser.name/news/2010/11/04/
642 var pattern
= text1
.substring(text_length
- length
);
643 var found
= text2
.indexOf(pattern
);
648 if (found
== 0 || text1
.substring(text_length
- length
) ==
649 text2
.substring(0, length
)) {
658 * Do the two texts share a substring which is at least half the length of the
660 * This speedup can produce non-minimal diffs.
661 * @param {string} text1 First string.
662 * @param {string} text2 Second string.
663 * @return {Array.<string>} Five element Array, containing the prefix of
664 * text1, the suffix of text1, the prefix of text2, the suffix of
665 * text2 and the common middle. Or null if there was no match.
668 diff_match_patch
.prototype.diff_halfMatch_ = function(text1
, text2
) {
669 if (this.Diff_Timeout
<= 0) {
670 // Don't risk returning a non-optimal diff if we have unlimited time.
673 var longtext
= text1
.length
> text2
.length
? text1
: text2
;
674 var shorttext
= text1
.length
> text2
.length
? text2
: text1
;
675 if (longtext
.length
< 4 || shorttext
.length
* 2 < longtext
.length
) {
676 return null; // Pointless.
678 var dmp
= this; // 'this' becomes 'window' in a closure.
681 * Does a substring of shorttext exist within longtext such that the substring
682 * is at least half the length of longtext?
683 * Closure, but does not reference any external variables.
684 * @param {string} longtext Longer string.
685 * @param {string} shorttext Shorter string.
686 * @param {number} i Start index of quarter length substring within longtext.
687 * @return {Array.<string>} Five element Array, containing the prefix of
688 * longtext, the suffix of longtext, the prefix of shorttext, the suffix
689 * of shorttext and the common middle. Or null if there was no match.
692 function diff_halfMatchI_(longtext
, shorttext
, i
) {
693 // Start with a 1/4 length substring at position i as a seed.
694 var seed
= longtext
.substring(i
, i
+ Math
.floor(longtext
.length
/ 4));
696 var best_common
= '';
697 var best_longtext_a
, best_longtext_b
, best_shorttext_a
, best_shorttext_b
;
698 while ((j
= shorttext
.indexOf(seed
, j
+ 1)) != -1) {
699 var prefixLength
= dmp
.diff_commonPrefix(longtext
.substring(i
),
700 shorttext
.substring(j
));
701 var suffixLength
= dmp
.diff_commonSuffix(longtext
.substring(0, i
),
702 shorttext
.substring(0, j
));
703 if (best_common
.length
< suffixLength
+ prefixLength
) {
704 best_common
= shorttext
.substring(j
- suffixLength
, j
) +
705 shorttext
.substring(j
, j
+ prefixLength
);
706 best_longtext_a
= longtext
.substring(0, i
- suffixLength
);
707 best_longtext_b
= longtext
.substring(i
+ prefixLength
);
708 best_shorttext_a
= shorttext
.substring(0, j
- suffixLength
);
709 best_shorttext_b
= shorttext
.substring(j
+ prefixLength
);
712 if (best_common
.length
* 2 >= longtext
.length
) {
713 return [best_longtext_a
, best_longtext_b
,
714 best_shorttext_a
, best_shorttext_b
, best_common
];
720 // First check if the second quarter is the seed for a half-match.
721 var hm1
= diff_halfMatchI_(longtext
, shorttext
,
722 Math
.ceil(longtext
.length
/ 4));
723 // Check again based on the third quarter.
724 var hm2
= diff_halfMatchI_(longtext
, shorttext
,
725 Math
.ceil(longtext
.length
/ 2));
734 // Both matched. Select the longest.
735 hm
= hm1
[4].length
> hm2
[4].length
? hm1
: hm2
;
738 // A half-match was found, sort out the return data.
739 var text1_a
, text1_b
, text2_a
, text2_b
;
740 if (text1
.length
> text2
.length
) {
751 var mid_common
= hm
[4];
752 return [text1_a
, text1_b
, text2_a
, text2_b
, mid_common
];
757 * Reduce the number of edits by eliminating semantically trivial equalities.
758 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
760 diff_match_patch
.prototype.diff_cleanupSemantic = function(diffs
) {
762 var equalities
= []; // Stack of indices where equalities are found.
763 var equalitiesLength
= 0; // Keeping our own length var is faster in JS.
764 /** @type {?string} */
765 var lastEquality
= null;
766 // Always equal to diffs[equalities[equalitiesLength - 1]][1]
767 var pointer
= 0; // Index of current position.
768 // Number of characters that changed prior to the equality.
769 var length_insertions1
= 0;
770 var length_deletions1
= 0;
771 // Number of characters that changed after the equality.
772 var length_insertions2
= 0;
773 var length_deletions2
= 0;
774 while (pointer
< diffs
.length
) {
775 if (diffs
[pointer
][0] == DIFF_EQUAL
) { // Equality found.
776 equalities
[equalitiesLength
++] = pointer
;
777 length_insertions1
= length_insertions2
;
778 length_deletions1
= length_deletions2
;
779 length_insertions2
= 0;
780 length_deletions2
= 0;
781 lastEquality
= diffs
[pointer
][1];
782 } else { // An insertion or deletion.
783 if (diffs
[pointer
][0] == DIFF_INSERT
) {
784 length_insertions2
+= diffs
[pointer
][1].length
;
786 length_deletions2
+= diffs
[pointer
][1].length
;
788 // Eliminate an equality that is smaller or equal to the edits on both
790 if (lastEquality
&& (lastEquality
.length
<=
791 Math
.max(length_insertions1
, length_deletions1
)) &&
792 (lastEquality
.length
<= Math
.max(length_insertions2
,
793 length_deletions2
))) {
795 diffs
.splice(equalities
[equalitiesLength
- 1], 0,
796 new diff_match_patch
.Diff(DIFF_DELETE
, lastEquality
));
797 // Change second copy to insert.
798 diffs
[equalities
[equalitiesLength
- 1] + 1][0] = DIFF_INSERT
;
799 // Throw away the equality we just deleted.
801 // Throw away the previous equality (it needs to be reevaluated).
803 pointer
= equalitiesLength
> 0 ? equalities
[equalitiesLength
- 1] : -1;
804 length_insertions1
= 0; // Reset the counters.
805 length_deletions1
= 0;
806 length_insertions2
= 0;
807 length_deletions2
= 0;
815 // Normalize the diff.
817 this.diff_cleanupMerge(diffs
);
819 this.diff_cleanupSemanticLossless(diffs
);
821 // Find any overlaps between deletions and insertions.
822 // e.g: <del>abcxxx</del><ins>xxxdef</ins>
823 // -> <del>abc</del>xxx<ins>def</ins>
824 // e.g: <del>xxxabc</del><ins>defxxx</ins>
825 // -> <ins>def</ins>xxx<del>abc</del>
826 // Only extract an overlap if it is as big as the edit ahead or behind it.
828 while (pointer
< diffs
.length
) {
829 if (diffs
[pointer
- 1][0] == DIFF_DELETE
&&
830 diffs
[pointer
][0] == DIFF_INSERT
) {
831 var deletion
= diffs
[pointer
- 1][1];
832 var insertion
= diffs
[pointer
][1];
833 var overlap_length1
= this.diff_commonOverlap_(deletion
, insertion
);
834 var overlap_length2
= this.diff_commonOverlap_(insertion
, deletion
);
835 if (overlap_length1
>= overlap_length2
) {
836 if (overlap_length1
>= deletion
.length
/ 2 ||
837 overlap_length1
>= insertion
.length
/ 2) {
838 // Overlap found. Insert an equality and trim the surrounding edits.
839 diffs
.splice(pointer
, 0, new diff_match_patch
.Diff(DIFF_EQUAL
,
840 insertion
.substring(0, overlap_length1
)));
841 diffs
[pointer
- 1][1] =
842 deletion
.substring(0, deletion
.length
- overlap_length1
);
843 diffs
[pointer
+ 1][1] = insertion
.substring(overlap_length1
);
847 if (overlap_length2
>= deletion
.length
/ 2 ||
848 overlap_length2
>= insertion
.length
/ 2) {
849 // Reverse overlap found.
850 // Insert an equality and swap and trim the surrounding edits.
851 diffs
.splice(pointer
, 0, new diff_match_patch
.Diff(DIFF_EQUAL
,
852 deletion
.substring(0, overlap_length2
)));
853 diffs
[pointer
- 1][0] = DIFF_INSERT
;
854 diffs
[pointer
- 1][1] =
855 insertion
.substring(0, insertion
.length
- overlap_length2
);
856 diffs
[pointer
+ 1][0] = DIFF_DELETE
;
857 diffs
[pointer
+ 1][1] =
858 deletion
.substring(overlap_length2
);
870 * Look for single edits surrounded on both sides by equalities
871 * which can be shifted sideways to align the edit to a word boundary.
872 * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
873 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
875 diff_match_patch
.prototype.diff_cleanupSemanticLossless = function(diffs
) {
877 * Given two strings, compute a score representing whether the internal
878 * boundary falls on logical boundaries.
879 * Scores range from 6 (best) to 0 (worst).
880 * Closure, but does not reference any external variables.
881 * @param {string} one First string.
882 * @param {string} two Second string.
883 * @return {number} The score.
886 function diff_cleanupSemanticScore_(one
, two
) {
888 // Edges are the best.
892 // Each port of this function behaves slightly differently due to
893 // subtle differences in each language's definition of things like
894 // 'whitespace'. Since this function's purpose is largely cosmetic,
895 // the choice has been made to use each language's native features
896 // rather than force total conformity.
897 var char1
= one
.charAt(one
.length
- 1);
898 var char2
= two
.charAt(0);
899 var nonAlphaNumeric1
= char1
.match(diff_match_patch
.nonAlphaNumericRegex_
);
900 var nonAlphaNumeric2
= char2
.match(diff_match_patch
.nonAlphaNumericRegex_
);
901 var whitespace1
= nonAlphaNumeric1
&&
902 char1
.match(diff_match_patch
.whitespaceRegex_
);
903 var whitespace2
= nonAlphaNumeric2
&&
904 char2
.match(diff_match_patch
.whitespaceRegex_
);
905 var lineBreak1
= whitespace1
&&
906 char1
.match(diff_match_patch
.linebreakRegex_
);
907 var lineBreak2
= whitespace2
&&
908 char2
.match(diff_match_patch
.linebreakRegex_
);
909 var blankLine1
= lineBreak1
&&
910 one
.match(diff_match_patch
.blanklineEndRegex_
);
911 var blankLine2
= lineBreak2
&&
912 two
.match(diff_match_patch
.blanklineStartRegex_
);
914 if (blankLine1
|| blankLine2
) {
915 // Five points for blank lines.
917 } else if (lineBreak1
|| lineBreak2
) {
918 // Four points for line breaks.
920 } else if (nonAlphaNumeric1
&& !whitespace1
&& whitespace2
) {
921 // Three points for end of sentences.
923 } else if (whitespace1
|| whitespace2
) {
924 // Two points for whitespace.
926 } else if (nonAlphaNumeric1
|| nonAlphaNumeric2
) {
927 // One point for non-alphanumeric.
934 // Intentionally ignore the first and last element (don't need checking).
935 while (pointer
< diffs
.length
- 1) {
936 if (diffs
[pointer
- 1][0] == DIFF_EQUAL
&&
937 diffs
[pointer
+ 1][0] == DIFF_EQUAL
) {
938 // This is a single edit surrounded by equalities.
939 var equality1
= diffs
[pointer
- 1][1];
940 var edit
= diffs
[pointer
][1];
941 var equality2
= diffs
[pointer
+ 1][1];
943 // First, shift the edit as far left as possible.
944 var commonOffset
= this.diff_commonSuffix(equality1
, edit
);
946 var commonString
= edit
.substring(edit
.length
- commonOffset
);
947 equality1
= equality1
.substring(0, equality1
.length
- commonOffset
);
948 edit
= commonString
+ edit
.substring(0, edit
.length
- commonOffset
);
949 equality2
= commonString
+ equality2
;
952 // Second, step character by character right, looking for the best fit.
953 var bestEquality1
= equality1
;
955 var bestEquality2
= equality2
;
956 var bestScore
= diff_cleanupSemanticScore_(equality1
, edit
) +
957 diff_cleanupSemanticScore_(edit
, equality2
);
958 while (edit
.charAt(0) === equality2
.charAt(0)) {
959 equality1
+= edit
.charAt(0);
960 edit
= edit
.substring(1) + equality2
.charAt(0);
961 equality2
= equality2
.substring(1);
962 var score
= diff_cleanupSemanticScore_(equality1
, edit
) +
963 diff_cleanupSemanticScore_(edit
, equality2
);
964 // The >= encourages trailing rather than leading whitespace on edits.
965 if (score
>= bestScore
) {
967 bestEquality1
= equality1
;
969 bestEquality2
= equality2
;
973 if (diffs
[pointer
- 1][1] != bestEquality1
) {
974 // We have an improvement, save it back to the diff.
976 diffs
[pointer
- 1][1] = bestEquality1
;
978 diffs
.splice(pointer
- 1, 1);
981 diffs
[pointer
][1] = bestEdit
;
983 diffs
[pointer
+ 1][1] = bestEquality2
;
985 diffs
.splice(pointer
+ 1, 1);
994 // Define some regex patterns for matching boundaries.
995 diff_match_patch
.nonAlphaNumericRegex_
= /[^a-zA-Z0-9]/;
996 diff_match_patch
.whitespaceRegex_
= /\s/;
997 diff_match_patch
.linebreakRegex_
= /[\r\n]/;
998 diff_match_patch
.blanklineEndRegex_
= /\n\r?\n$/;
999 diff_match_patch
.blanklineStartRegex_
= /^\r?\n\r?\n/;
1002 * Reduce the number of edits by eliminating operationally trivial equalities.
1003 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1005 diff_match_patch
.prototype.diff_cleanupEfficiency = function(diffs
) {
1006 var changes
= false;
1007 var equalities
= []; // Stack of indices where equalities are found.
1008 var equalitiesLength
= 0; // Keeping our own length var is faster in JS.
1009 /** @type {?string} */
1010 var lastEquality
= null;
1011 // Always equal to diffs[equalities[equalitiesLength - 1]][1]
1012 var pointer
= 0; // Index of current position.
1013 // Is there an insertion operation before the last equality.
1014 var pre_ins
= false;
1015 // Is there a deletion operation before the last equality.
1016 var pre_del
= false;
1017 // Is there an insertion operation after the last equality.
1018 var post_ins
= false;
1019 // Is there a deletion operation after the last equality.
1020 var post_del
= false;
1021 while (pointer
< diffs
.length
) {
1022 if (diffs
[pointer
][0] == DIFF_EQUAL
) { // Equality found.
1023 if (diffs
[pointer
][1].length
< this.Diff_EditCost
&&
1024 (post_ins
|| post_del
)) {
1026 equalities
[equalitiesLength
++] = pointer
;
1029 lastEquality
= diffs
[pointer
][1];
1031 // Not a candidate, and can never become one.
1032 equalitiesLength
= 0;
1033 lastEquality
= null;
1035 post_ins
= post_del
= false;
1036 } else { // An insertion or deletion.
1037 if (diffs
[pointer
][0] == DIFF_DELETE
) {
1043 * Five types to be split:
1044 * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
1045 * <ins>A</ins>X<ins>C</ins><del>D</del>
1046 * <ins>A</ins><del>B</del>X<ins>C</ins>
1047 * <ins>A</del>X<ins>C</ins><del>D</del>
1048 * <ins>A</ins><del>B</del>X<del>C</del>
1050 if (lastEquality
&& ((pre_ins
&& pre_del
&& post_ins
&& post_del
) ||
1051 ((lastEquality
.length
< this.Diff_EditCost
/ 2) &&
1052 (pre_ins
+ pre_del
+ post_ins
+ post_del
) == 3))) {
1053 // Duplicate record.
1054 diffs
.splice(equalities
[equalitiesLength
- 1], 0,
1055 new diff_match_patch
.Diff(DIFF_DELETE
, lastEquality
));
1056 // Change second copy to insert.
1057 diffs
[equalities
[equalitiesLength
- 1] + 1][0] = DIFF_INSERT
;
1058 equalitiesLength
--; // Throw away the equality we just deleted;
1059 lastEquality
= null;
1060 if (pre_ins
&& pre_del
) {
1061 // No changes made which could affect previous entry, keep going.
1062 post_ins
= post_del
= true;
1063 equalitiesLength
= 0;
1065 equalitiesLength
--; // Throw away the previous equality.
1066 pointer
= equalitiesLength
> 0 ?
1067 equalities
[equalitiesLength
- 1] : -1;
1068 post_ins
= post_del
= false;
1077 this.diff_cleanupMerge(diffs
);
1083 * Reorder and merge like edit sections. Merge equalities.
1084 * Any edit section can move as long as it doesn't cross an equality.
1085 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1087 diff_match_patch
.prototype.diff_cleanupMerge = function(diffs
) {
1088 // Add a dummy entry at the end.
1089 diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, ''));
1091 var count_delete
= 0;
1092 var count_insert
= 0;
1093 var text_delete
= '';
1094 var text_insert
= '';
1096 while (pointer
< diffs
.length
) {
1097 switch (diffs
[pointer
][0]) {
1100 text_insert
+= diffs
[pointer
][1];
1105 text_delete
+= diffs
[pointer
][1];
1109 // Upon reaching an equality, check for prior redundancies.
1110 if (count_delete
+ count_insert
> 1) {
1111 if (count_delete
!== 0 && count_insert
!== 0) {
1112 // Factor out any common prefixies.
1113 commonlength
= this.diff_commonPrefix(text_insert
, text_delete
);
1114 if (commonlength
!== 0) {
1115 if ((pointer
- count_delete
- count_insert
) > 0 &&
1116 diffs
[pointer
- count_delete
- count_insert
- 1][0] ==
1118 diffs
[pointer
- count_delete
- count_insert
- 1][1] +=
1119 text_insert
.substring(0, commonlength
);
1121 diffs
.splice(0, 0, new diff_match_patch
.Diff(DIFF_EQUAL
,
1122 text_insert
.substring(0, commonlength
)));
1125 text_insert
= text_insert
.substring(commonlength
);
1126 text_delete
= text_delete
.substring(commonlength
);
1128 // Factor out any common suffixies.
1129 commonlength
= this.diff_commonSuffix(text_insert
, text_delete
);
1130 if (commonlength
!== 0) {
1131 diffs
[pointer
][1] = text_insert
.substring(text_insert
.length
-
1132 commonlength
) + diffs
[pointer
][1];
1133 text_insert
= text_insert
.substring(0, text_insert
.length
-
1135 text_delete
= text_delete
.substring(0, text_delete
.length
-
1139 // Delete the offending records and add the merged ones.
1140 pointer
-= count_delete
+ count_insert
;
1141 diffs
.splice(pointer
, count_delete
+ count_insert
);
1142 if (text_delete
.length
) {
1143 diffs
.splice(pointer
, 0,
1144 new diff_match_patch
.Diff(DIFF_DELETE
, text_delete
));
1147 if (text_insert
.length
) {
1148 diffs
.splice(pointer
, 0,
1149 new diff_match_patch
.Diff(DIFF_INSERT
, text_insert
));
1153 } else if (pointer
!== 0 && diffs
[pointer
- 1][0] == DIFF_EQUAL
) {
1154 // Merge this equality with the previous one.
1155 diffs
[pointer
- 1][1] += diffs
[pointer
][1];
1156 diffs
.splice(pointer
, 1);
1167 if (diffs
[diffs
.length
- 1][1] === '') {
1168 diffs
.pop(); // Remove the dummy entry at the end.
1171 // Second pass: look for single edits surrounded on both sides by equalities
1172 // which can be shifted sideways to eliminate an equality.
1173 // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
1174 var changes
= false;
1176 // Intentionally ignore the first and last element (don't need checking).
1177 while (pointer
< diffs
.length
- 1) {
1178 if (diffs
[pointer
- 1][0] == DIFF_EQUAL
&&
1179 diffs
[pointer
+ 1][0] == DIFF_EQUAL
) {
1180 // This is a single edit surrounded by equalities.
1181 if (diffs
[pointer
][1].substring(diffs
[pointer
][1].length
-
1182 diffs
[pointer
- 1][1].length
) == diffs
[pointer
- 1][1]) {
1183 // Shift the edit over the previous equality.
1184 diffs
[pointer
][1] = diffs
[pointer
- 1][1] +
1185 diffs
[pointer
][1].substring(0, diffs
[pointer
][1].length
-
1186 diffs
[pointer
- 1][1].length
);
1187 diffs
[pointer
+ 1][1] = diffs
[pointer
- 1][1] + diffs
[pointer
+ 1][1];
1188 diffs
.splice(pointer
- 1, 1);
1190 } else if (diffs
[pointer
][1].substring(0, diffs
[pointer
+ 1][1].length
) ==
1191 diffs
[pointer
+ 1][1]) {
1192 // Shift the edit over the next equality.
1193 diffs
[pointer
- 1][1] += diffs
[pointer
+ 1][1];
1195 diffs
[pointer
][1].substring(diffs
[pointer
+ 1][1].length
) +
1196 diffs
[pointer
+ 1][1];
1197 diffs
.splice(pointer
+ 1, 1);
1203 // If shifts were made, the diff needs reordering and another shift sweep.
1205 this.diff_cleanupMerge(diffs
);
1211 * loc is a location in text1, compute and return the equivalent location in
1213 * e.g. 'The cat' vs 'The big cat', 1->1, 5->8
1214 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1215 * @param {number} loc Location within text1.
1216 * @return {number} Location within text2.
1218 diff_match_patch
.prototype.diff_xIndex = function(diffs
, loc
) {
1221 var last_chars1
= 0;
1222 var last_chars2
= 0;
1224 for (x
= 0; x
< diffs
.length
; x
++) {
1225 if (diffs
[x
][0] !== DIFF_INSERT
) { // Equality or deletion.
1226 chars1
+= diffs
[x
][1].length
;
1228 if (diffs
[x
][0] !== DIFF_DELETE
) { // Equality or insertion.
1229 chars2
+= diffs
[x
][1].length
;
1231 if (chars1
> loc
) { // Overshot the location.
1234 last_chars1
= chars1
;
1235 last_chars2
= chars2
;
1237 // Was the location was deleted?
1238 if (diffs
.length
!= x
&& diffs
[x
][0] === DIFF_DELETE
) {
1241 // Add the remaining character length.
1242 return last_chars2
+ (loc
- last_chars1
);
1247 * Convert a diff array into a pretty HTML report.
1248 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1249 * @return {string} HTML representation.
1251 diff_match_patch
.prototype.diff_prettyHtml = function(diffs
) {
1253 var pattern_amp
= /&/g
;
1254 var pattern_lt
= /</g
;
1255 var pattern_gt
= />/g
;
1256 var pattern_para
= /\n/g;
1257 for (var x
= 0; x
< diffs
.length
; x
++) {
1258 var op
= diffs
[x
][0]; // Operation (insert, delete, equal)
1259 var data
= diffs
[x
][1]; // Text of change.
1260 var text
= data
.replace(pattern_amp
, '&').replace(pattern_lt
, '<')
1261 .replace(pattern_gt
, '>').replace(pattern_para
, '¶<br>');
1264 html
[x
] = '<ins style="background:#e6ffe6;">' + text
+ '</ins>';
1267 html
[x
] = '<del style="background:#ffe6e6;">' + text
+ '</del>';
1270 html
[x
] = '<span>' + text
+ '</span>';
1274 return html
.join('');
1279 * Compute and return the source text (all equalities and deletions).
1280 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1281 * @return {string} Source text.
1283 diff_match_patch
.prototype.diff_text1 = function(diffs
) {
1285 for (var x
= 0; x
< diffs
.length
; x
++) {
1286 if (diffs
[x
][0] !== DIFF_INSERT
) {
1287 text
[x
] = diffs
[x
][1];
1290 return text
.join('');
1295 * Compute and return the destination text (all equalities and insertions).
1296 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1297 * @return {string} Destination text.
1299 diff_match_patch
.prototype.diff_text2 = function(diffs
) {
1301 for (var x
= 0; x
< diffs
.length
; x
++) {
1302 if (diffs
[x
][0] !== DIFF_DELETE
) {
1303 text
[x
] = diffs
[x
][1];
1306 return text
.join('');
1311 * Compute the Levenshtein distance; the number of inserted, deleted or
1312 * substituted characters.
1313 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1314 * @return {number} Number of changes.
1316 diff_match_patch
.prototype.diff_levenshtein = function(diffs
) {
1317 var levenshtein
= 0;
1320 for (var x
= 0; x
< diffs
.length
; x
++) {
1321 var op
= diffs
[x
][0];
1322 var data
= diffs
[x
][1];
1325 insertions
+= data
.length
;
1328 deletions
+= data
.length
;
1331 // A deletion and an insertion is one substitution.
1332 levenshtein
+= Math
.max(insertions
, deletions
);
1338 levenshtein
+= Math
.max(insertions
, deletions
);
1344 * Crush the diff into an encoded string which describes the operations
1345 * required to transform text1 into text2.
1346 * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.
1347 * Operations are tab-separated. Inserted text is escaped using %xx notation.
1348 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1349 * @return {string} Delta text.
1351 diff_match_patch
.prototype.diff_toDelta = function(diffs
) {
1353 for (var x
= 0; x
< diffs
.length
; x
++) {
1354 switch (diffs
[x
][0]) {
1356 text
[x
] = '+' + encodeURI(diffs
[x
][1]);
1359 text
[x
] = '-' + diffs
[x
][1].length
;
1362 text
[x
] = '=' + diffs
[x
][1].length
;
1366 return text
.join('\t').replace(/%20/g, ' ');
1371 * Given the original text1, and an encoded string which describes the
1372 * operations required to transform text1 into text2, compute the full diff.
1373 * @param {string} text1 Source string for the diff.
1374 * @param {string} delta Delta text.
1375 * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
1376 * @throws {!Error} If invalid input.
1378 diff_match_patch
.prototype.diff_fromDelta = function(text1
, delta
) {
1380 var diffsLength
= 0; // Keeping our own length var is faster in JS.
1381 var pointer
= 0; // Cursor in text1
1382 var tokens
= delta
.split(/\t/g);
1383 for (var x
= 0; x
< tokens
.length
; x
++) {
1384 // Each token begins with a one character parameter which specifies the
1385 // operation of this token (delete, insert, equality).
1386 var param
= tokens
[x
].substring(1);
1387 switch (tokens
[x
].charAt(0)) {
1390 diffs
[diffsLength
++] =
1391 new diff_match_patch
.Diff(DIFF_INSERT
, decodeURI(param
));
1393 // Malformed URI sequence.
1394 throw new Error('Illegal escape in diff_fromDelta: ' + param
);
1400 var n
= parseInt(param
, 10);
1401 if (isNaN(n
) || n
< 0) {
1402 throw new Error('Invalid number in diff_fromDelta: ' + param
);
1404 var text
= text1
.substring(pointer
, pointer
+= n
);
1405 if (tokens
[x
].charAt(0) == '=') {
1406 diffs
[diffsLength
++] = new diff_match_patch
.Diff(DIFF_EQUAL
, text
);
1408 diffs
[diffsLength
++] = new diff_match_patch
.Diff(DIFF_DELETE
, text
);
1412 // Blank tokens are ok (from a trailing \t).
1413 // Anything else is an error.
1415 throw new Error('Invalid diff operation in diff_fromDelta: ' +
1420 if (pointer
!= text1
.length
) {
1421 throw new Error('Delta length (' + pointer
+
1422 ') does not equal source text length (' + text1
.length
+ ').');
1432 * Locate the best instance of 'pattern' in 'text' near 'loc'.
1433 * @param {string} text The text to search.
1434 * @param {string} pattern The pattern to search for.
1435 * @param {number} loc The location to search around.
1436 * @return {number} Best match index or -1.
1438 diff_match_patch
.prototype.match_main = function(text
, pattern
, loc
) {
1439 // Check for null inputs.
1440 if (text
== null || pattern
== null || loc
== null) {
1441 throw new Error('Null input. (match_main)');
1444 loc
= Math
.max(0, Math
.min(loc
, text
.length
));
1445 if (text
== pattern
) {
1446 // Shortcut (potentially not guaranteed by the algorithm)
1448 } else if (!text
.length
) {
1449 // Nothing to match.
1451 } else if (text
.substring(loc
, loc
+ pattern
.length
) == pattern
) {
1452 // Perfect match at the perfect spot! (Includes case of null pattern)
1455 // Do a fuzzy compare.
1456 return this.match_bitap_(text
, pattern
, loc
);
1462 * Locate the best instance of 'pattern' in 'text' near 'loc' using the
1464 * @param {string} text The text to search.
1465 * @param {string} pattern The pattern to search for.
1466 * @param {number} loc The location to search around.
1467 * @return {number} Best match index or -1.
1470 diff_match_patch
.prototype.match_bitap_ = function(text
, pattern
, loc
) {
1471 if (pattern
.length
> this.Match_MaxBits
) {
1472 throw new Error('Pattern too long for this browser.');
1475 // Initialise the alphabet.
1476 var s
= this.match_alphabet_(pattern
);
1478 var dmp
= this; // 'this' becomes 'window' in a closure.
1481 * Compute and return the score for a match with e errors and x location.
1482 * Accesses loc and pattern through being a closure.
1483 * @param {number} e Number of errors in match.
1484 * @param {number} x Location of match.
1485 * @return {number} Overall score for match (0.0 = good, 1.0 = bad).
1488 function match_bitapScore_(e
, x
) {
1489 var accuracy
= e
/ pattern
.length
;
1490 var proximity
= Math
.abs(loc
- x
);
1491 if (!dmp
.Match_Distance
) {
1492 // Dodge divide by zero error.
1493 return proximity
? 1.0 : accuracy
;
1495 return accuracy
+ (proximity
/ dmp
.Match_Distance
);
1498 // Highest score beyond which we give up.
1499 var score_threshold
= this.Match_Threshold
;
1500 // Is there a nearby exact match? (speedup)
1501 var best_loc
= text
.indexOf(pattern
, loc
);
1502 if (best_loc
!= -1) {
1503 score_threshold
= Math
.min(match_bitapScore_(0, best_loc
), score_threshold
);
1504 // What about in the other direction? (speedup)
1505 best_loc
= text
.lastIndexOf(pattern
, loc
+ pattern
.length
);
1506 if (best_loc
!= -1) {
1508 Math
.min(match_bitapScore_(0, best_loc
), score_threshold
);
1512 // Initialise the bit arrays.
1513 var matchmask
= 1 << (pattern
.length
- 1);
1516 var bin_min
, bin_mid
;
1517 var bin_max
= pattern
.length
+ text
.length
;
1519 for (var d
= 0; d
< pattern
.length
; d
++) {
1520 // Scan for the best match; each iteration allows for one more error.
1521 // Run a binary search to determine how far from 'loc' we can stray at this
1525 while (bin_min
< bin_mid
) {
1526 if (match_bitapScore_(d
, loc
+ bin_mid
) <= score_threshold
) {
1531 bin_mid
= Math
.floor((bin_max
- bin_min
) / 2 + bin_min
);
1533 // Use the result from this iteration as the maximum for the next.
1535 var start
= Math
.max(1, loc
- bin_mid
+ 1);
1536 var finish
= Math
.min(loc
+ bin_mid
, text
.length
) + pattern
.length
;
1538 var rd
= Array(finish
+ 2);
1539 rd
[finish
+ 1] = (1 << d
) - 1;
1540 for (var j
= finish
; j
>= start
; j
--) {
1541 // The alphabet (s) is a sparse hash, so the following line generates
1543 var charMatch
= s
[text
.charAt(j
- 1)];
1544 if (d
=== 0) { // First pass: exact match.
1545 rd
[j
] = ((rd
[j
+ 1] << 1) | 1) & charMatch
;
1546 } else { // Subsequent passes: fuzzy match.
1547 rd
[j
] = (((rd
[j
+ 1] << 1) | 1) & charMatch
) |
1548 (((last_rd
[j
+ 1] | last_rd
[j
]) << 1) | 1) |
1551 if (rd
[j
] & matchmask
) {
1552 var score
= match_bitapScore_(d
, j
- 1);
1553 // This match will almost certainly be better than any existing match.
1554 // But check anyway.
1555 if (score
<= score_threshold
) {
1557 score_threshold
= score
;
1559 if (best_loc
> loc
) {
1560 // When passing loc, don't exceed our current distance from loc.
1561 start
= Math
.max(1, 2 * loc
- best_loc
);
1563 // Already passed loc, downhill from here on in.
1569 // No hope for a (better) match at greater error levels.
1570 if (match_bitapScore_(d
+ 1, loc
) > score_threshold
) {
1580 * Initialise the alphabet for the Bitap algorithm.
1581 * @param {string} pattern The text to encode.
1582 * @return {!Object} Hash of character locations.
1585 diff_match_patch
.prototype.match_alphabet_ = function(pattern
) {
1587 for (var i
= 0; i
< pattern
.length
; i
++) {
1588 s
[pattern
.charAt(i
)] = 0;
1590 for (var i
= 0; i
< pattern
.length
; i
++) {
1591 s
[pattern
.charAt(i
)] |= 1 << (pattern
.length
- i
- 1);
1601 * Increase the context until it is unique,
1602 * but don't let the pattern expand beyond Match_MaxBits.
1603 * @param {!diff_match_patch.patch_obj} patch The patch to grow.
1604 * @param {string} text Source text.
1607 diff_match_patch
.prototype.patch_addContext_ = function(patch
, text
) {
1608 if (text
.length
== 0) {
1611 if (patch
.start2
=== null) {
1612 throw Error('patch not initialized');
1614 var pattern
= text
.substring(patch
.start2
, patch
.start2
+ patch
.length1
);
1617 // Look for the first and last matches of pattern in text. If two different
1618 // matches are found, increase the pattern length.
1619 while (text
.indexOf(pattern
) != text
.lastIndexOf(pattern
) &&
1620 pattern
.length
< this.Match_MaxBits
- this.Patch_Margin
-
1621 this.Patch_Margin
) {
1622 padding
+= this.Patch_Margin
;
1623 pattern
= text
.substring(patch
.start2
- padding
,
1624 patch
.start2
+ patch
.length1
+ padding
);
1626 // Add one chunk for good luck.
1627 padding
+= this.Patch_Margin
;
1630 var prefix
= text
.substring(patch
.start2
- padding
, patch
.start2
);
1632 patch
.diffs
.unshift(new diff_match_patch
.Diff(DIFF_EQUAL
, prefix
));
1635 var suffix
= text
.substring(patch
.start2
+ patch
.length1
,
1636 patch
.start2
+ patch
.length1
+ padding
);
1638 patch
.diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, suffix
));
1641 // Roll back the start points.
1642 patch
.start1
-= prefix
.length
;
1643 patch
.start2
-= prefix
.length
;
1644 // Extend the lengths.
1645 patch
.length1
+= prefix
.length
+ suffix
.length
;
1646 patch
.length2
+= prefix
.length
+ suffix
.length
;
1651 * Compute a list of patches to turn text1 into text2.
1652 * Use diffs if provided, otherwise compute it ourselves.
1653 * There are four ways to call this function, depending on what data is
1654 * available to the caller:
1656 * a = text1, b = text2
1659 * Method 3 (optimal):
1660 * a = text1, b = diffs
1661 * Method 4 (deprecated, use method 3):
1662 * a = text1, b = text2, c = diffs
1664 * @param {string|!Array.<!diff_match_patch.Diff>} a text1 (methods 1,3,4) or
1665 * Array of diff tuples for text1 to text2 (method 2).
1666 * @param {string|!Array.<!diff_match_patch.Diff>} opt_b text2 (methods 1,4) or
1667 * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2).
1668 * @param {string|!Array.<!diff_match_patch.Diff>} opt_c Array of diff tuples
1669 * for text1 to text2 (method 4) or undefined (methods 1,2,3).
1670 * @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.
1672 diff_match_patch
.prototype.patch_make = function(a
, opt_b
, opt_c
) {
1674 if (typeof a
== 'string' && typeof opt_b
== 'string' &&
1675 typeof opt_c
== 'undefined') {
1676 // Method 1: text1, text2
1677 // Compute diffs from text1 and text2.
1678 text1
= /** @type {string} */(a
);
1679 diffs
= this.diff_main(text1
, /** @type {string} */(opt_b
), true);
1680 if (diffs
.length
> 2) {
1681 this.diff_cleanupSemantic(diffs
);
1682 this.diff_cleanupEfficiency(diffs
);
1684 } else if (a
&& typeof a
== 'object' && typeof opt_b
== 'undefined' &&
1685 typeof opt_c
== 'undefined') {
1687 // Compute text1 from diffs.
1688 diffs
= /** @type {!Array.<!diff_match_patch.Diff>} */(a
);
1689 text1
= this.diff_text1(diffs
);
1690 } else if (typeof a
== 'string' && opt_b
&& typeof opt_b
== 'object' &&
1691 typeof opt_c
== 'undefined') {
1692 // Method 3: text1, diffs
1693 text1
= /** @type {string} */(a
);
1694 diffs
= /** @type {!Array.<!diff_match_patch.Diff>} */(opt_b
);
1695 } else if (typeof a
== 'string' && typeof opt_b
== 'string' &&
1696 opt_c
&& typeof opt_c
== 'object') {
1697 // Method 4: text1, text2, diffs
1698 // text2 is not used.
1699 text1
= /** @type {string} */(a
);
1700 diffs
= /** @type {!Array.<!diff_match_patch.Diff>} */(opt_c
);
1702 throw new Error('Unknown call format to patch_make.');
1705 if (diffs
.length
=== 0) {
1706 return []; // Get rid of the null case.
1709 var patch
= new diff_match_patch
.patch_obj();
1710 var patchDiffLength
= 0; // Keeping our own length var is faster in JS.
1711 var char_count1
= 0; // Number of characters into the text1 string.
1712 var char_count2
= 0; // Number of characters into the text2 string.
1713 // Start with text1 (prepatch_text) and apply the diffs until we arrive at
1714 // text2 (postpatch_text). We recreate the patches one by one to determine
1716 var prepatch_text
= text1
;
1717 var postpatch_text
= text1
;
1718 for (var x
= 0; x
< diffs
.length
; x
++) {
1719 var diff_type
= diffs
[x
][0];
1720 var diff_text
= diffs
[x
][1];
1722 if (!patchDiffLength
&& diff_type
!== DIFF_EQUAL
) {
1723 // A new patch starts here.
1724 patch
.start1
= char_count1
;
1725 patch
.start2
= char_count2
;
1728 switch (diff_type
) {
1730 patch
.diffs
[patchDiffLength
++] = diffs
[x
];
1731 patch
.length2
+= diff_text
.length
;
1732 postpatch_text
= postpatch_text
.substring(0, char_count2
) + diff_text
+
1733 postpatch_text
.substring(char_count2
);
1736 patch
.length1
+= diff_text
.length
;
1737 patch
.diffs
[patchDiffLength
++] = diffs
[x
];
1738 postpatch_text
= postpatch_text
.substring(0, char_count2
) +
1739 postpatch_text
.substring(char_count2
+
1743 if (diff_text
.length
<= 2 * this.Patch_Margin
&&
1744 patchDiffLength
&& diffs
.length
!= x
+ 1) {
1745 // Small equality inside a patch.
1746 patch
.diffs
[patchDiffLength
++] = diffs
[x
];
1747 patch
.length1
+= diff_text
.length
;
1748 patch
.length2
+= diff_text
.length
;
1749 } else if (diff_text
.length
>= 2 * this.Patch_Margin
) {
1750 // Time for a new patch.
1751 if (patchDiffLength
) {
1752 this.patch_addContext_(patch
, prepatch_text
);
1753 patches
.push(patch
);
1754 patch
= new diff_match_patch
.patch_obj();
1755 patchDiffLength
= 0;
1756 // Unlike Unidiff, our patch lists have a rolling context.
1757 // https://github.com/google/diff-match-patch/wiki/Unidiff
1758 // Update prepatch text & pos to reflect the application of the
1759 // just completed patch.
1760 prepatch_text
= postpatch_text
;
1761 char_count1
= char_count2
;
1767 // Update the current character count.
1768 if (diff_type
!== DIFF_INSERT
) {
1769 char_count1
+= diff_text
.length
;
1771 if (diff_type
!== DIFF_DELETE
) {
1772 char_count2
+= diff_text
.length
;
1775 // Pick up the leftover patch if not empty.
1776 if (patchDiffLength
) {
1777 this.patch_addContext_(patch
, prepatch_text
);
1778 patches
.push(patch
);
1786 * Given an array of patches, return another array that is identical.
1787 * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
1788 * @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.
1790 diff_match_patch
.prototype.patch_deepCopy = function(patches
) {
1791 // Making deep copies is hard in JavaScript.
1792 var patchesCopy
= [];
1793 for (var x
= 0; x
< patches
.length
; x
++) {
1794 var patch
= patches
[x
];
1795 var patchCopy
= new diff_match_patch
.patch_obj();
1796 patchCopy
.diffs
= [];
1797 for (var y
= 0; y
< patch
.diffs
.length
; y
++) {
1798 patchCopy
.diffs
[y
] =
1799 new diff_match_patch
.Diff(patch
.diffs
[y
][0], patch
.diffs
[y
][1]);
1801 patchCopy
.start1
= patch
.start1
;
1802 patchCopy
.start2
= patch
.start2
;
1803 patchCopy
.length1
= patch
.length1
;
1804 patchCopy
.length2
= patch
.length2
;
1805 patchesCopy
[x
] = patchCopy
;
1812 * Merge a set of patches onto the text. Return a patched text, as well
1813 * as a list of true/false values indicating which patches were applied.
1814 * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
1815 * @param {string} text Old text.
1816 * @return {!Array.<string|!Array.<boolean>>} Two element Array, containing the
1817 * new text and an array of boolean values.
1819 diff_match_patch
.prototype.patch_apply = function(patches
, text
) {
1820 if (patches
.length
== 0) {
1824 // Deep copy the patches so that no changes are made to originals.
1825 patches
= this.patch_deepCopy(patches
);
1827 var nullPadding
= this.patch_addPadding(patches
);
1828 text
= nullPadding
+ text
+ nullPadding
;
1830 this.patch_splitMax(patches
);
1831 // delta keeps track of the offset between the expected and actual location
1832 // of the previous patch. If there are patches expected at positions 10 and
1833 // 20, but the first patch was found at 12, delta is 2 and the second patch
1834 // has an effective expected position of 22.
1837 for (var x
= 0; x
< patches
.length
; x
++) {
1838 var expected_loc
= patches
[x
].start2
+ delta
;
1839 var text1
= this.diff_text1(patches
[x
].diffs
);
1842 if (text1
.length
> this.Match_MaxBits
) {
1843 // patch_splitMax will only provide an oversized pattern in the case of
1844 // a monster delete.
1845 start_loc
= this.match_main(text
, text1
.substring(0, this.Match_MaxBits
),
1847 if (start_loc
!= -1) {
1848 end_loc
= this.match_main(text
,
1849 text1
.substring(text1
.length
- this.Match_MaxBits
),
1850 expected_loc
+ text1
.length
- this.Match_MaxBits
);
1851 if (end_loc
== -1 || start_loc
>= end_loc
) {
1852 // Can't find valid trailing context. Drop this patch.
1857 start_loc
= this.match_main(text
, text1
, expected_loc
);
1859 if (start_loc
== -1) {
1860 // No match found. :(
1862 // Subtract the delta for this failed patch from subsequent patches.
1863 delta
-= patches
[x
].length2
- patches
[x
].length1
;
1865 // Found a match. :)
1867 delta
= start_loc
- expected_loc
;
1869 if (end_loc
== -1) {
1870 text2
= text
.substring(start_loc
, start_loc
+ text1
.length
);
1872 text2
= text
.substring(start_loc
, end_loc
+ this.Match_MaxBits
);
1874 if (text1
== text2
) {
1875 // Perfect match, just shove the replacement text in.
1876 text
= text
.substring(0, start_loc
) +
1877 this.diff_text2(patches
[x
].diffs
) +
1878 text
.substring(start_loc
+ text1
.length
);
1880 // Imperfect match. Run a diff to get a framework of equivalent
1882 var diffs
= this.diff_main(text1
, text2
, false);
1883 if (text1
.length
> this.Match_MaxBits
&&
1884 this.diff_levenshtein(diffs
) / text1
.length
>
1885 this.Patch_DeleteThreshold
) {
1886 // The end points match, but the content is unacceptably bad.
1889 this.diff_cleanupSemanticLossless(diffs
);
1892 for (var y
= 0; y
< patches
[x
].diffs
.length
; y
++) {
1893 var mod
= patches
[x
].diffs
[y
];
1894 if (mod
[0] !== DIFF_EQUAL
) {
1895 index2
= this.diff_xIndex(diffs
, index1
);
1897 if (mod
[0] === DIFF_INSERT
) { // Insertion
1898 text
= text
.substring(0, start_loc
+ index2
) + mod
[1] +
1899 text
.substring(start_loc
+ index2
);
1900 } else if (mod
[0] === DIFF_DELETE
) { // Deletion
1901 text
= text
.substring(0, start_loc
+ index2
) +
1902 text
.substring(start_loc
+ this.diff_xIndex(diffs
,
1903 index1
+ mod
[1].length
));
1905 if (mod
[0] !== DIFF_DELETE
) {
1906 index1
+= mod
[1].length
;
1913 // Strip the padding off.
1914 text
= text
.substring(nullPadding
.length
, text
.length
- nullPadding
.length
);
1915 return [text
, results
];
1920 * Add some padding on text start and end so that edges can match something.
1921 * Intended to be called only from within patch_apply.
1922 * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
1923 * @return {string} The padding string added to each side.
1925 diff_match_patch
.prototype.patch_addPadding = function(patches
) {
1926 var paddingLength
= this.Patch_Margin
;
1927 var nullPadding
= '';
1928 for (var x
= 1; x
<= paddingLength
; x
++) {
1929 nullPadding
+= String
.fromCharCode(x
);
1932 // Bump all the patches forward.
1933 for (var x
= 0; x
< patches
.length
; x
++) {
1934 patches
[x
].start1
+= paddingLength
;
1935 patches
[x
].start2
+= paddingLength
;
1938 // Add some padding on start of first diff.
1939 var patch
= patches
[0];
1940 var diffs
= patch
.diffs
;
1941 if (diffs
.length
== 0 || diffs
[0][0] != DIFF_EQUAL
) {
1942 // Add nullPadding equality.
1943 diffs
.unshift(new diff_match_patch
.Diff(DIFF_EQUAL
, nullPadding
));
1944 patch
.start1
-= paddingLength
; // Should be 0.
1945 patch
.start2
-= paddingLength
; // Should be 0.
1946 patch
.length1
+= paddingLength
;
1947 patch
.length2
+= paddingLength
;
1948 } else if (paddingLength
> diffs
[0][1].length
) {
1949 // Grow first equality.
1950 var extraLength
= paddingLength
- diffs
[0][1].length
;
1951 diffs
[0][1] = nullPadding
.substring(diffs
[0][1].length
) + diffs
[0][1];
1952 patch
.start1
-= extraLength
;
1953 patch
.start2
-= extraLength
;
1954 patch
.length1
+= extraLength
;
1955 patch
.length2
+= extraLength
;
1958 // Add some padding on end of last diff.
1959 patch
= patches
[patches
.length
- 1];
1960 diffs
= patch
.diffs
;
1961 if (diffs
.length
== 0 || diffs
[diffs
.length
- 1][0] != DIFF_EQUAL
) {
1962 // Add nullPadding equality.
1963 diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, nullPadding
));
1964 patch
.length1
+= paddingLength
;
1965 patch
.length2
+= paddingLength
;
1966 } else if (paddingLength
> diffs
[diffs
.length
- 1][1].length
) {
1967 // Grow last equality.
1968 var extraLength
= paddingLength
- diffs
[diffs
.length
- 1][1].length
;
1969 diffs
[diffs
.length
- 1][1] += nullPadding
.substring(0, extraLength
);
1970 patch
.length1
+= extraLength
;
1971 patch
.length2
+= extraLength
;
1979 * Look through the patches and break up any which are longer than the maximum
1980 * limit of the match algorithm.
1981 * Intended to be called only from within patch_apply.
1982 * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
1984 diff_match_patch
.prototype.patch_splitMax = function(patches
) {
1985 var patch_size
= this.Match_MaxBits
;
1986 for (var x
= 0; x
< patches
.length
; x
++) {
1987 if (patches
[x
].length1
<= patch_size
) {
1990 var bigpatch
= patches
[x
];
1991 // Remove the big old patch.
1992 patches
.splice(x
--, 1);
1993 var start1
= bigpatch
.start1
;
1994 var start2
= bigpatch
.start2
;
1995 var precontext
= '';
1996 while (bigpatch
.diffs
.length
!== 0) {
1997 // Create one of several smaller patches.
1998 var patch
= new diff_match_patch
.patch_obj();
2000 patch
.start1
= start1
- precontext
.length
;
2001 patch
.start2
= start2
- precontext
.length
;
2002 if (precontext
!== '') {
2003 patch
.length1
= patch
.length2
= precontext
.length
;
2004 patch
.diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, precontext
));
2006 while (bigpatch
.diffs
.length
!== 0 &&
2007 patch
.length1
< patch_size
- this.Patch_Margin
) {
2008 var diff_type
= bigpatch
.diffs
[0][0];
2009 var diff_text
= bigpatch
.diffs
[0][1];
2010 if (diff_type
=== DIFF_INSERT
) {
2011 // Insertions are harmless.
2012 patch
.length2
+= diff_text
.length
;
2013 start2
+= diff_text
.length
;
2014 patch
.diffs
.push(bigpatch
.diffs
.shift());
2016 } else if (diff_type
=== DIFF_DELETE
&& patch
.diffs
.length
== 1 &&
2017 patch
.diffs
[0][0] == DIFF_EQUAL
&&
2018 diff_text
.length
> 2 * patch_size
) {
2019 // This is a large deletion. Let it pass in one chunk.
2020 patch
.length1
+= diff_text
.length
;
2021 start1
+= diff_text
.length
;
2023 patch
.diffs
.push(new diff_match_patch
.Diff(diff_type
, diff_text
));
2024 bigpatch
.diffs
.shift();
2026 // Deletion or equality. Only take as much as we can stomach.
2027 diff_text
= diff_text
.substring(0,
2028 patch_size
- patch
.length1
- this.Patch_Margin
);
2029 patch
.length1
+= diff_text
.length
;
2030 start1
+= diff_text
.length
;
2031 if (diff_type
=== DIFF_EQUAL
) {
2032 patch
.length2
+= diff_text
.length
;
2033 start2
+= diff_text
.length
;
2037 patch
.diffs
.push(new diff_match_patch
.Diff(diff_type
, diff_text
));
2038 if (diff_text
== bigpatch
.diffs
[0][1]) {
2039 bigpatch
.diffs
.shift();
2041 bigpatch
.diffs
[0][1] =
2042 bigpatch
.diffs
[0][1].substring(diff_text
.length
);
2046 // Compute the head context for the next patch.
2047 precontext
= this.diff_text2(patch
.diffs
);
2049 precontext
.substring(precontext
.length
- this.Patch_Margin
);
2050 // Append the end context for this patch.
2051 var postcontext
= this.diff_text1(bigpatch
.diffs
)
2052 .substring(0, this.Patch_Margin
);
2053 if (postcontext
!== '') {
2054 patch
.length1
+= postcontext
.length
;
2055 patch
.length2
+= postcontext
.length
;
2056 if (patch
.diffs
.length
!== 0 &&
2057 patch
.diffs
[patch
.diffs
.length
- 1][0] === DIFF_EQUAL
) {
2058 patch
.diffs
[patch
.diffs
.length
- 1][1] += postcontext
;
2060 patch
.diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, postcontext
));
2064 patches
.splice(++x
, 0, patch
);
2072 * Take a list of patches and return a textual representation.
2073 * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
2074 * @return {string} Text representation of patches.
2076 diff_match_patch
.prototype.patch_toText = function(patches
) {
2078 for (var x
= 0; x
< patches
.length
; x
++) {
2079 text
[x
] = patches
[x
];
2081 return text
.join('');
2086 * Parse a textual representation of patches and return a list of Patch objects.
2087 * @param {string} textline Text representation of patches.
2088 * @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.
2089 * @throws {!Error} If invalid input.
2091 diff_match_patch
.prototype.patch_fromText = function(textline
) {
2096 var text
= textline
.split('\n');
2097 var textPointer
= 0;
2098 var patchHeader
= /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;
2099 while (textPointer
< text
.length
) {
2100 var m
= text
[textPointer
].match(patchHeader
);
2102 throw new Error('Invalid patch string: ' + text
[textPointer
]);
2104 var patch
= new diff_match_patch
.patch_obj();
2105 patches
.push(patch
);
2106 patch
.start1
= parseInt(m
[1], 10);
2110 } else if (m
[2] == '0') {
2114 patch
.length1
= parseInt(m
[2], 10);
2117 patch
.start2
= parseInt(m
[3], 10);
2121 } else if (m
[4] == '0') {
2125 patch
.length2
= parseInt(m
[4], 10);
2129 while (textPointer
< text
.length
) {
2130 var sign
= text
[textPointer
].charAt(0);
2132 var line
= decodeURI(text
[textPointer
].substring(1));
2134 // Malformed URI sequence.
2135 throw new Error('Illegal escape in patch_fromText: ' + line
);
2139 patch
.diffs
.push(new diff_match_patch
.Diff(DIFF_DELETE
, line
));
2140 } else if (sign
== '+') {
2142 patch
.diffs
.push(new diff_match_patch
.Diff(DIFF_INSERT
, line
));
2143 } else if (sign
== ' ') {
2145 patch
.diffs
.push(new diff_match_patch
.Diff(DIFF_EQUAL
, line
));
2146 } else if (sign
== '@') {
2147 // Start of next patch.
2149 } else if (sign
=== '') {
2150 // Blank line? Whatever.
2153 throw new Error('Invalid patch mode "' + sign
+ '" in: ' + line
);
2163 * Class representing one patch operation.
2166 diff_match_patch
.patch_obj = function() {
2167 /** @type {!Array.<!diff_match_patch.Diff>} */
2169 /** @type {?number} */
2171 /** @type {?number} */
2173 /** @type {number} */
2175 /** @type {number} */
2181 * Emulate GNU diff's format.
2182 * Header: @@ -382,8 +481,9 @@
2183 * Indices are printed as 1-based, not 0-based.
2184 * @return {string} The GNU diff string.
2186 diff_match_patch
.patch_obj
.prototype.toString = function() {
2187 var coords1
, coords2
;
2188 if (this.length1
=== 0) {
2189 coords1
= this.start1
+ ',0';
2190 } else if (this.length1
== 1) {
2191 coords1
= this.start1
+ 1;
2193 coords1
= (this.start1
+ 1) + ',' + this.length1
;
2195 if (this.length2
=== 0) {
2196 coords2
= this.start2
+ ',0';
2197 } else if (this.length2
== 1) {
2198 coords2
= this.start2
+ 1;
2200 coords2
= (this.start2
+ 1) + ',' + this.length2
;
2202 var text
= ['@@ -' + coords1
+ ' +' + coords2
+ ' @@\n'];
2204 // Escape the body of the patch with %xx notation.
2205 for (var x
= 0; x
< this.diffs
.length
; x
++) {
2206 switch (this.diffs
[x
][0]) {
2217 text
[x
+ 1] = op
+ encodeURI(this.diffs
[x
][1]) + '\n';
2219 return text
.join('').replace(/%20/g, ' ');
2222 // CLOSURE:begin_strip
2223 // Lines below here will not be included in the Closure-compatible library.
2225 // Export these global variables so that they survive Google's JS compiler.
2226 // In a browser, 'this' will be 'window'.
2227 // Users of node.js should 'require' the uncompressed version since Google's
2228 // JS compiler may break the following exports for non-browser environments.
2229 /** @suppress {globalThis} */
2230 this['diff_match_patch'] = diff_match_patch
;
2231 /** @suppress {globalThis} */
2232 this['DIFF_DELETE'] = DIFF_DELETE
;
2233 /** @suppress {globalThis} */
2234 this['DIFF_INSERT'] = DIFF_INSERT
;
2235 /** @suppress {globalThis} */
2236 this['DIFF_EQUAL'] = DIFF_EQUAL
;