diff_match_patch_uncompressed.js 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239
  1. /**
  2. * Diff Match and Patch
  3. * Copyright 2018 The diff-match-patch Authors.
  4. * https://github.com/google/diff-match-patch
  5. *
  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
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  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.
  17. */
  18. /**
  19. * @fileoverview Computes the difference between two texts to create a patch.
  20. * Applies the patch onto another text, allowing for errors.
  21. * @author fraser@google.com (Neil Fraser)
  22. */
  23. /**
  24. * Class containing the diff, match and patch methods.
  25. * @constructor
  26. */
  27. var diff_match_patch = function() {
  28. // Defaults.
  29. // Redefine these in your program to override the defaults.
  30. // Number of seconds to map a diff before giving up (0 for infinity).
  31. this.Diff_Timeout = 1.0;
  32. // Cost of an empty edit operation in terms of edit characters.
  33. this.Diff_EditCost = 4;
  34. // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
  35. this.Match_Threshold = 0.5;
  36. // How far to search for a match (0 = exact location, 1000+ = broad match).
  37. // A match this many characters away from the expected location will add
  38. // 1.0 to the score (0.0 is a perfect match).
  39. this.Match_Distance = 1000;
  40. // When deleting a large block of text (over ~64 characters), how close do
  41. // the contents have to be to match the expected contents. (0.0 = perfection,
  42. // 1.0 = very loose). Note that Match_Threshold controls how closely the
  43. // end points of a delete need to match.
  44. this.Patch_DeleteThreshold = 0.5;
  45. // Chunk size for context length.
  46. this.Patch_Margin = 4;
  47. // The number of bits in an int.
  48. this.Match_MaxBits = 32;
  49. };
  50. // DIFF FUNCTIONS
  51. /**
  52. * The data structure representing a diff is an array of tuples:
  53. * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
  54. * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
  55. */
  56. var DIFF_DELETE = -1;
  57. var DIFF_INSERT = 1;
  58. var DIFF_EQUAL = 0;
  59. /**
  60. * Class representing one diff tuple.
  61. * Attempts to look like a two-element array (which is what this used to be).
  62. * @param {number} op Operation, one of: DIFF_DELETE, DIFF_INSERT, DIFF_EQUAL.
  63. * @param {string} text Text to be deleted, inserted, or retained.
  64. * @constructor
  65. */
  66. diff_match_patch.Diff = function(op, text) {
  67. this[0] = op;
  68. this[1] = text;
  69. };
  70. diff_match_patch.Diff.prototype.length = 2;
  71. /**
  72. * Emulate the output of a two-element array.
  73. * @return {string} Diff operation as a string.
  74. */
  75. diff_match_patch.Diff.prototype.toString = function() {
  76. return this[0] + ',' + this[1];
  77. };
  78. /**
  79. * Find the differences between two texts. Simplifies the problem by stripping
  80. * any common prefix or suffix off the texts before diffing.
  81. * @param {string} text1 Old string to be diffed.
  82. * @param {string} text2 New string to be diffed.
  83. * @param {boolean=} opt_checklines Optional speedup flag. If present and false,
  84. * then don't run a line-level diff first to identify the changed areas.
  85. * Defaults to true, which does a faster, slightly less optimal diff.
  86. * @param {number=} opt_deadline Optional time when the diff should be complete
  87. * by. Used internally for recursive calls. Users should set DiffTimeout
  88. * instead.
  89. * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  90. */
  91. diff_match_patch.prototype.diff_main = function(text1, text2, opt_checklines,
  92. opt_deadline) {
  93. // Set a deadline by which time the diff must be complete.
  94. if (typeof opt_deadline == 'undefined') {
  95. if (this.Diff_Timeout <= 0) {
  96. opt_deadline = Number.MAX_VALUE;
  97. } else {
  98. opt_deadline = (new Date).getTime() + this.Diff_Timeout * 1000;
  99. }
  100. }
  101. var deadline = opt_deadline;
  102. // Check for null inputs.
  103. if (text1 == null || text2 == null) {
  104. throw new Error('Null input. (diff_main)');
  105. }
  106. // Check for equality (speedup).
  107. if (text1 == text2) {
  108. if (text1) {
  109. return [new diff_match_patch.Diff(DIFF_EQUAL, text1)];
  110. }
  111. return [];
  112. }
  113. if (typeof opt_checklines == 'undefined') {
  114. opt_checklines = true;
  115. }
  116. var checklines = opt_checklines;
  117. // Trim off common prefix (speedup).
  118. var commonlength = this.diff_commonPrefix(text1, text2);
  119. var commonprefix = text1.substring(0, commonlength);
  120. text1 = text1.substring(commonlength);
  121. text2 = text2.substring(commonlength);
  122. // Trim off common suffix (speedup).
  123. commonlength = this.diff_commonSuffix(text1, text2);
  124. var commonsuffix = text1.substring(text1.length - commonlength);
  125. text1 = text1.substring(0, text1.length - commonlength);
  126. text2 = text2.substring(0, text2.length - commonlength);
  127. // Compute the diff on the middle block.
  128. var diffs = this.diff_compute_(text1, text2, checklines, deadline);
  129. // Restore the prefix and suffix.
  130. if (commonprefix) {
  131. diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL, commonprefix));
  132. }
  133. if (commonsuffix) {
  134. diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, commonsuffix));
  135. }
  136. this.diff_cleanupMerge(diffs);
  137. return diffs;
  138. };
  139. /**
  140. * Find the differences between two texts. Assumes that the texts do not
  141. * have any common prefix or suffix.
  142. * @param {string} text1 Old string to be diffed.
  143. * @param {string} text2 New string to be diffed.
  144. * @param {boolean} checklines Speedup flag. If false, then don't run a
  145. * line-level diff first to identify the changed areas.
  146. * If true, then run a faster, slightly less optimal diff.
  147. * @param {number} deadline Time when the diff should be complete by.
  148. * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  149. * @private
  150. */
  151. diff_match_patch.prototype.diff_compute_ = function(text1, text2, checklines,
  152. deadline) {
  153. var diffs;
  154. if (!text1) {
  155. // Just add some text (speedup).
  156. return [new diff_match_patch.Diff(DIFF_INSERT, text2)];
  157. }
  158. if (!text2) {
  159. // Just delete some text (speedup).
  160. return [new diff_match_patch.Diff(DIFF_DELETE, text1)];
  161. }
  162. var longtext = text1.length > text2.length ? text1 : text2;
  163. var shorttext = text1.length > text2.length ? text2 : text1;
  164. var i = longtext.indexOf(shorttext);
  165. if (i != -1) {
  166. // Shorter text is inside the longer text (speedup).
  167. diffs = [new diff_match_patch.Diff(DIFF_INSERT, longtext.substring(0, i)),
  168. new diff_match_patch.Diff(DIFF_EQUAL, shorttext),
  169. new diff_match_patch.Diff(DIFF_INSERT,
  170. longtext.substring(i + shorttext.length))];
  171. // Swap insertions for deletions if diff is reversed.
  172. if (text1.length > text2.length) {
  173. diffs[0][0] = diffs[2][0] = DIFF_DELETE;
  174. }
  175. return diffs;
  176. }
  177. if (shorttext.length == 1) {
  178. // Single character string.
  179. // After the previous speedup, the character can't be an equality.
  180. return [new diff_match_patch.Diff(DIFF_DELETE, text1),
  181. new diff_match_patch.Diff(DIFF_INSERT, text2)];
  182. }
  183. // Check to see if the problem can be split in two.
  184. var hm = this.diff_halfMatch_(text1, text2);
  185. if (hm) {
  186. // A half-match was found, sort out the return data.
  187. var text1_a = hm[0];
  188. var text1_b = hm[1];
  189. var text2_a = hm[2];
  190. var text2_b = hm[3];
  191. var mid_common = hm[4];
  192. // Send both pairs off for separate processing.
  193. var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline);
  194. var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline);
  195. // Merge the results.
  196. return diffs_a.concat([new diff_match_patch.Diff(DIFF_EQUAL, mid_common)],
  197. diffs_b);
  198. }
  199. if (checklines && text1.length > 100 && text2.length > 100) {
  200. return this.diff_lineMode_(text1, text2, deadline);
  201. }
  202. return this.diff_bisect_(text1, text2, deadline);
  203. };
  204. /**
  205. * Do a quick line-level diff on both strings, then rediff the parts for
  206. * greater accuracy.
  207. * This speedup can produce non-minimal diffs.
  208. * @param {string} text1 Old string to be diffed.
  209. * @param {string} text2 New string to be diffed.
  210. * @param {number} deadline Time when the diff should be complete by.
  211. * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  212. * @private
  213. */
  214. diff_match_patch.prototype.diff_lineMode_ = function(text1, text2, deadline) {
  215. // Scan the text on a line-by-line basis first.
  216. var a = this.diff_linesToChars_(text1, text2);
  217. text1 = a.chars1;
  218. text2 = a.chars2;
  219. var linearray = a.lineArray;
  220. var diffs = this.diff_main(text1, text2, false, deadline);
  221. // Convert the diff back to original text.
  222. this.diff_charsToLines_(diffs, linearray);
  223. // Eliminate freak matches (e.g. blank lines)
  224. this.diff_cleanupSemantic(diffs);
  225. // Rediff any replacement blocks, this time character-by-character.
  226. // Add a dummy entry at the end.
  227. diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, ''));
  228. var pointer = 0;
  229. var count_delete = 0;
  230. var count_insert = 0;
  231. var text_delete = '';
  232. var text_insert = '';
  233. while (pointer < diffs.length) {
  234. switch (diffs[pointer][0]) {
  235. case DIFF_INSERT:
  236. count_insert++;
  237. text_insert += diffs[pointer][1];
  238. break;
  239. case DIFF_DELETE:
  240. count_delete++;
  241. text_delete += diffs[pointer][1];
  242. break;
  243. case DIFF_EQUAL:
  244. // Upon reaching an equality, check for prior redundancies.
  245. if (count_delete >= 1 && count_insert >= 1) {
  246. // Delete the offending records and add the merged ones.
  247. diffs.splice(pointer - count_delete - count_insert,
  248. count_delete + count_insert);
  249. pointer = pointer - count_delete - count_insert;
  250. var subDiff =
  251. this.diff_main(text_delete, text_insert, false, deadline);
  252. for (var j = subDiff.length - 1; j >= 0; j--) {
  253. diffs.splice(pointer, 0, subDiff[j]);
  254. }
  255. pointer = pointer + subDiff.length;
  256. }
  257. count_insert = 0;
  258. count_delete = 0;
  259. text_delete = '';
  260. text_insert = '';
  261. break;
  262. }
  263. pointer++;
  264. }
  265. diffs.pop(); // Remove the dummy entry at the end.
  266. return diffs;
  267. };
  268. /**
  269. * Find the 'middle snake' of a diff, split the problem in two
  270. * and return the recursively constructed diff.
  271. * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
  272. * @param {string} text1 Old string to be diffed.
  273. * @param {string} text2 New string to be diffed.
  274. * @param {number} deadline Time at which to bail if not yet complete.
  275. * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  276. * @private
  277. */
  278. diff_match_patch.prototype.diff_bisect_ = function(text1, text2, deadline) {
  279. // Cache the text lengths to prevent multiple calls.
  280. var text1_length = text1.length;
  281. var text2_length = text2.length;
  282. var max_d = Math.ceil((text1_length + text2_length) / 2);
  283. var v_offset = max_d;
  284. var v_length = 2 * max_d;
  285. var v1 = new Array(v_length);
  286. var v2 = new Array(v_length);
  287. // Setting all elements to -1 is faster in Chrome & Firefox than mixing
  288. // integers and undefined.
  289. for (var x = 0; x < v_length; x++) {
  290. v1[x] = -1;
  291. v2[x] = -1;
  292. }
  293. v1[v_offset + 1] = 0;
  294. v2[v_offset + 1] = 0;
  295. var delta = text1_length - text2_length;
  296. // If the total number of characters is odd, then the front path will collide
  297. // with the reverse path.
  298. var front = (delta % 2 != 0);
  299. // Offsets for start and end of k loop.
  300. // Prevents mapping of space beyond the grid.
  301. var k1start = 0;
  302. var k1end = 0;
  303. var k2start = 0;
  304. var k2end = 0;
  305. for (var d = 0; d < max_d; d++) {
  306. // Bail out if deadline is reached.
  307. if ((new Date()).getTime() > deadline) {
  308. break;
  309. }
  310. // Walk the front path one step.
  311. for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
  312. var k1_offset = v_offset + k1;
  313. var x1;
  314. if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) {
  315. x1 = v1[k1_offset + 1];
  316. } else {
  317. x1 = v1[k1_offset - 1] + 1;
  318. }
  319. var y1 = x1 - k1;
  320. while (x1 < text1_length && y1 < text2_length &&
  321. text1.charAt(x1) == text2.charAt(y1)) {
  322. x1++;
  323. y1++;
  324. }
  325. v1[k1_offset] = x1;
  326. if (x1 > text1_length) {
  327. // Ran off the right of the graph.
  328. k1end += 2;
  329. } else if (y1 > text2_length) {
  330. // Ran off the bottom of the graph.
  331. k1start += 2;
  332. } else if (front) {
  333. var k2_offset = v_offset + delta - k1;
  334. if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
  335. // Mirror x2 onto top-left coordinate system.
  336. var x2 = text1_length - v2[k2_offset];
  337. if (x1 >= x2) {
  338. // Overlap detected.
  339. return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
  340. }
  341. }
  342. }
  343. }
  344. // Walk the reverse path one step.
  345. for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
  346. var k2_offset = v_offset + k2;
  347. var x2;
  348. if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) {
  349. x2 = v2[k2_offset + 1];
  350. } else {
  351. x2 = v2[k2_offset - 1] + 1;
  352. }
  353. var y2 = x2 - k2;
  354. while (x2 < text1_length && y2 < text2_length &&
  355. text1.charAt(text1_length - x2 - 1) ==
  356. text2.charAt(text2_length - y2 - 1)) {
  357. x2++;
  358. y2++;
  359. }
  360. v2[k2_offset] = x2;
  361. if (x2 > text1_length) {
  362. // Ran off the left of the graph.
  363. k2end += 2;
  364. } else if (y2 > text2_length) {
  365. // Ran off the top of the graph.
  366. k2start += 2;
  367. } else if (!front) {
  368. var k1_offset = v_offset + delta - k2;
  369. if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
  370. var x1 = v1[k1_offset];
  371. var y1 = v_offset + x1 - k1_offset;
  372. // Mirror x2 onto top-left coordinate system.
  373. x2 = text1_length - x2;
  374. if (x1 >= x2) {
  375. // Overlap detected.
  376. return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
  377. }
  378. }
  379. }
  380. }
  381. }
  382. // Diff took too long and hit the deadline or
  383. // number of diffs equals number of characters, no commonality at all.
  384. return [new diff_match_patch.Diff(DIFF_DELETE, text1),
  385. new diff_match_patch.Diff(DIFF_INSERT, text2)];
  386. };
  387. /**
  388. * Given the location of the 'middle snake', split the diff in two parts
  389. * and recurse.
  390. * @param {string} text1 Old string to be diffed.
  391. * @param {string} text2 New string to be diffed.
  392. * @param {number} x Index of split point in text1.
  393. * @param {number} y Index of split point in text2.
  394. * @param {number} deadline Time at which to bail if not yet complete.
  395. * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  396. * @private
  397. */
  398. diff_match_patch.prototype.diff_bisectSplit_ = function(text1, text2, x, y,
  399. deadline) {
  400. var text1a = text1.substring(0, x);
  401. var text2a = text2.substring(0, y);
  402. var text1b = text1.substring(x);
  403. var text2b = text2.substring(y);
  404. // Compute both diffs serially.
  405. var diffs = this.diff_main(text1a, text2a, false, deadline);
  406. var diffsb = this.diff_main(text1b, text2b, false, deadline);
  407. return diffs.concat(diffsb);
  408. };
  409. /**
  410. * Split two texts into an array of strings. Reduce the texts to a string of
  411. * hashes where each Unicode character represents one line.
  412. * @param {string} text1 First string.
  413. * @param {string} text2 Second string.
  414. * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
  415. * An object containing the encoded text1, the encoded text2 and
  416. * the array of unique strings.
  417. * The zeroth element of the array of unique strings is intentionally blank.
  418. * @private
  419. */
  420. diff_match_patch.prototype.diff_linesToChars_ = function(text1, text2) {
  421. var lineArray = []; // e.g. lineArray[4] == 'Hello\n'
  422. var lineHash = {}; // e.g. lineHash['Hello\n'] == 4
  423. // '\x00' is a valid character, but various debuggers don't like it.
  424. // So we'll insert a junk entry to avoid generating a null character.
  425. lineArray[0] = '';
  426. /**
  427. * Split a text into an array of strings. Reduce the texts to a string of
  428. * hashes where each Unicode character represents one line.
  429. * Modifies linearray and linehash through being a closure.
  430. * @param {string} text String to encode.
  431. * @return {string} Encoded string.
  432. * @private
  433. */
  434. function diff_linesToCharsMunge_(text) {
  435. var chars = '';
  436. // Walk the text, pulling out a substring for each line.
  437. // text.split('\n') would would temporarily double our memory footprint.
  438. // Modifying text would create many large strings to garbage collect.
  439. var lineStart = 0;
  440. var lineEnd = -1;
  441. // Keeping our own length variable is faster than looking it up.
  442. var lineArrayLength = lineArray.length;
  443. while (lineEnd < text.length - 1) {
  444. lineEnd = text.indexOf('\n', lineStart);
  445. if (lineEnd == -1) {
  446. lineEnd = text.length - 1;
  447. }
  448. var line = text.substring(lineStart, lineEnd + 1);
  449. if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) :
  450. (lineHash[line] !== undefined)) {
  451. chars += String.fromCharCode(lineHash[line]);
  452. } else {
  453. if (lineArrayLength == maxLines) {
  454. // Bail out at 65535 because
  455. // String.fromCharCode(65536) == String.fromCharCode(0)
  456. line = text.substring(lineStart);
  457. lineEnd = text.length;
  458. }
  459. chars += String.fromCharCode(lineArrayLength);
  460. lineHash[line] = lineArrayLength;
  461. lineArray[lineArrayLength++] = line;
  462. }
  463. lineStart = lineEnd + 1;
  464. }
  465. return chars;
  466. }
  467. // Allocate 2/3rds of the space for text1, the rest for text2.
  468. var maxLines = 40000;
  469. var chars1 = diff_linesToCharsMunge_(text1);
  470. maxLines = 65535;
  471. var chars2 = diff_linesToCharsMunge_(text2);
  472. return {chars1: chars1, chars2: chars2, lineArray: lineArray};
  473. };
  474. /**
  475. * Rehydrate the text in a diff from a string of line hashes to real lines of
  476. * text.
  477. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  478. * @param {!Array.<string>} lineArray Array of unique strings.
  479. * @private
  480. */
  481. diff_match_patch.prototype.diff_charsToLines_ = function(diffs, lineArray) {
  482. for (var i = 0; i < diffs.length; i++) {
  483. var chars = diffs[i][1];
  484. var text = [];
  485. for (var j = 0; j < chars.length; j++) {
  486. text[j] = lineArray[chars.charCodeAt(j)];
  487. }
  488. diffs[i][1] = text.join('');
  489. }
  490. };
  491. /**
  492. * Determine the common prefix of two strings.
  493. * @param {string} text1 First string.
  494. * @param {string} text2 Second string.
  495. * @return {number} The number of characters common to the start of each
  496. * string.
  497. */
  498. diff_match_patch.prototype.diff_commonPrefix = function(text1, text2) {
  499. // Quick check for common null cases.
  500. if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) {
  501. return 0;
  502. }
  503. // Binary search.
  504. // Performance analysis: https://neil.fraser.name/news/2007/10/09/
  505. var pointermin = 0;
  506. var pointermax = Math.min(text1.length, text2.length);
  507. var pointermid = pointermax;
  508. var pointerstart = 0;
  509. while (pointermin < pointermid) {
  510. if (text1.substring(pointerstart, pointermid) ==
  511. text2.substring(pointerstart, pointermid)) {
  512. pointermin = pointermid;
  513. pointerstart = pointermin;
  514. } else {
  515. pointermax = pointermid;
  516. }
  517. pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  518. }
  519. return pointermid;
  520. };
  521. /**
  522. * Determine the common suffix of two strings.
  523. * @param {string} text1 First string.
  524. * @param {string} text2 Second string.
  525. * @return {number} The number of characters common to the end of each string.
  526. */
  527. diff_match_patch.prototype.diff_commonSuffix = function(text1, text2) {
  528. // Quick check for common null cases.
  529. if (!text1 || !text2 ||
  530. text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) {
  531. return 0;
  532. }
  533. // Binary search.
  534. // Performance analysis: https://neil.fraser.name/news/2007/10/09/
  535. var pointermin = 0;
  536. var pointermax = Math.min(text1.length, text2.length);
  537. var pointermid = pointermax;
  538. var pointerend = 0;
  539. while (pointermin < pointermid) {
  540. if (text1.substring(text1.length - pointermid, text1.length - pointerend) ==
  541. text2.substring(text2.length - pointermid, text2.length - pointerend)) {
  542. pointermin = pointermid;
  543. pointerend = pointermin;
  544. } else {
  545. pointermax = pointermid;
  546. }
  547. pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  548. }
  549. return pointermid;
  550. };
  551. /**
  552. * Determine if the suffix of one string is the prefix of another.
  553. * @param {string} text1 First string.
  554. * @param {string} text2 Second string.
  555. * @return {number} The number of characters common to the end of the first
  556. * string and the start of the second string.
  557. * @private
  558. */
  559. diff_match_patch.prototype.diff_commonOverlap_ = function(text1, text2) {
  560. // Cache the text lengths to prevent multiple calls.
  561. var text1_length = text1.length;
  562. var text2_length = text2.length;
  563. // Eliminate the null case.
  564. if (text1_length == 0 || text2_length == 0) {
  565. return 0;
  566. }
  567. // Truncate the longer string.
  568. if (text1_length > text2_length) {
  569. text1 = text1.substring(text1_length - text2_length);
  570. } else if (text1_length < text2_length) {
  571. text2 = text2.substring(0, text1_length);
  572. }
  573. var text_length = Math.min(text1_length, text2_length);
  574. // Quick check for the worst case.
  575. if (text1 == text2) {
  576. return text_length;
  577. }
  578. // Start by looking for a single character match
  579. // and increase length until no match is found.
  580. // Performance analysis: https://neil.fraser.name/news/2010/11/04/
  581. var best = 0;
  582. var length = 1;
  583. while (true) {
  584. var pattern = text1.substring(text_length - length);
  585. var found = text2.indexOf(pattern);
  586. if (found == -1) {
  587. return best;
  588. }
  589. length += found;
  590. if (found == 0 || text1.substring(text_length - length) ==
  591. text2.substring(0, length)) {
  592. best = length;
  593. length++;
  594. }
  595. }
  596. };
  597. /**
  598. * Do the two texts share a substring which is at least half the length of the
  599. * longer text?
  600. * This speedup can produce non-minimal diffs.
  601. * @param {string} text1 First string.
  602. * @param {string} text2 Second string.
  603. * @return {Array.<string>} Five element Array, containing the prefix of
  604. * text1, the suffix of text1, the prefix of text2, the suffix of
  605. * text2 and the common middle. Or null if there was no match.
  606. * @private
  607. */
  608. diff_match_patch.prototype.diff_halfMatch_ = function(text1, text2) {
  609. if (this.Diff_Timeout <= 0) {
  610. // Don't risk returning a non-optimal diff if we have unlimited time.
  611. return null;
  612. }
  613. var longtext = text1.length > text2.length ? text1 : text2;
  614. var shorttext = text1.length > text2.length ? text2 : text1;
  615. if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
  616. return null; // Pointless.
  617. }
  618. var dmp = this; // 'this' becomes 'window' in a closure.
  619. /**
  620. * Does a substring of shorttext exist within longtext such that the substring
  621. * is at least half the length of longtext?
  622. * Closure, but does not reference any external variables.
  623. * @param {string} longtext Longer string.
  624. * @param {string} shorttext Shorter string.
  625. * @param {number} i Start index of quarter length substring within longtext.
  626. * @return {Array.<string>} Five element Array, containing the prefix of
  627. * longtext, the suffix of longtext, the prefix of shorttext, the suffix
  628. * of shorttext and the common middle. Or null if there was no match.
  629. * @private
  630. */
  631. function diff_halfMatchI_(longtext, shorttext, i) {
  632. // Start with a 1/4 length substring at position i as a seed.
  633. var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
  634. var j = -1;
  635. var best_common = '';
  636. var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
  637. while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
  638. var prefixLength = dmp.diff_commonPrefix(longtext.substring(i),
  639. shorttext.substring(j));
  640. var suffixLength = dmp.diff_commonSuffix(longtext.substring(0, i),
  641. shorttext.substring(0, j));
  642. if (best_common.length < suffixLength + prefixLength) {
  643. best_common = shorttext.substring(j - suffixLength, j) +
  644. shorttext.substring(j, j + prefixLength);
  645. best_longtext_a = longtext.substring(0, i - suffixLength);
  646. best_longtext_b = longtext.substring(i + prefixLength);
  647. best_shorttext_a = shorttext.substring(0, j - suffixLength);
  648. best_shorttext_b = shorttext.substring(j + prefixLength);
  649. }
  650. }
  651. if (best_common.length * 2 >= longtext.length) {
  652. return [best_longtext_a, best_longtext_b,
  653. best_shorttext_a, best_shorttext_b, best_common];
  654. } else {
  655. return null;
  656. }
  657. }
  658. // First check if the second quarter is the seed for a half-match.
  659. var hm1 = diff_halfMatchI_(longtext, shorttext,
  660. Math.ceil(longtext.length / 4));
  661. // Check again based on the third quarter.
  662. var hm2 = diff_halfMatchI_(longtext, shorttext,
  663. Math.ceil(longtext.length / 2));
  664. var hm;
  665. if (!hm1 && !hm2) {
  666. return null;
  667. } else if (!hm2) {
  668. hm = hm1;
  669. } else if (!hm1) {
  670. hm = hm2;
  671. } else {
  672. // Both matched. Select the longest.
  673. hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
  674. }
  675. // A half-match was found, sort out the return data.
  676. var text1_a, text1_b, text2_a, text2_b;
  677. if (text1.length > text2.length) {
  678. text1_a = hm[0];
  679. text1_b = hm[1];
  680. text2_a = hm[2];
  681. text2_b = hm[3];
  682. } else {
  683. text2_a = hm[0];
  684. text2_b = hm[1];
  685. text1_a = hm[2];
  686. text1_b = hm[3];
  687. }
  688. var mid_common = hm[4];
  689. return [text1_a, text1_b, text2_a, text2_b, mid_common];
  690. };
  691. /**
  692. * Reduce the number of edits by eliminating semantically trivial equalities.
  693. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  694. */
  695. diff_match_patch.prototype.diff_cleanupSemantic = function(diffs) {
  696. var changes = false;
  697. var equalities = []; // Stack of indices where equalities are found.
  698. var equalitiesLength = 0; // Keeping our own length var is faster in JS.
  699. /** @type {?string} */
  700. var lastEquality = null;
  701. // Always equal to diffs[equalities[equalitiesLength - 1]][1]
  702. var pointer = 0; // Index of current position.
  703. // Number of characters that changed prior to the equality.
  704. var length_insertions1 = 0;
  705. var length_deletions1 = 0;
  706. // Number of characters that changed after the equality.
  707. var length_insertions2 = 0;
  708. var length_deletions2 = 0;
  709. while (pointer < diffs.length) {
  710. if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found.
  711. equalities[equalitiesLength++] = pointer;
  712. length_insertions1 = length_insertions2;
  713. length_deletions1 = length_deletions2;
  714. length_insertions2 = 0;
  715. length_deletions2 = 0;
  716. lastEquality = diffs[pointer][1];
  717. } else { // An insertion or deletion.
  718. if (diffs[pointer][0] == DIFF_INSERT) {
  719. length_insertions2 += diffs[pointer][1].length;
  720. } else {
  721. length_deletions2 += diffs[pointer][1].length;
  722. }
  723. // Eliminate an equality that is smaller or equal to the edits on both
  724. // sides of it.
  725. if (lastEquality && (lastEquality.length <=
  726. Math.max(length_insertions1, length_deletions1)) &&
  727. (lastEquality.length <= Math.max(length_insertions2,
  728. length_deletions2))) {
  729. // Duplicate record.
  730. diffs.splice(equalities[equalitiesLength - 1], 0,
  731. new diff_match_patch.Diff(DIFF_DELETE, lastEquality));
  732. // Change second copy to insert.
  733. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  734. // Throw away the equality we just deleted.
  735. equalitiesLength--;
  736. // Throw away the previous equality (it needs to be reevaluated).
  737. equalitiesLength--;
  738. pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
  739. length_insertions1 = 0; // Reset the counters.
  740. length_deletions1 = 0;
  741. length_insertions2 = 0;
  742. length_deletions2 = 0;
  743. lastEquality = null;
  744. changes = true;
  745. }
  746. }
  747. pointer++;
  748. }
  749. // Normalize the diff.
  750. if (changes) {
  751. this.diff_cleanupMerge(diffs);
  752. }
  753. this.diff_cleanupSemanticLossless(diffs);
  754. // Find any overlaps between deletions and insertions.
  755. // e.g: <del>abcxxx</del><ins>xxxdef</ins>
  756. // -> <del>abc</del>xxx<ins>def</ins>
  757. // e.g: <del>xxxabc</del><ins>defxxx</ins>
  758. // -> <ins>def</ins>xxx<del>abc</del>
  759. // Only extract an overlap if it is as big as the edit ahead or behind it.
  760. pointer = 1;
  761. while (pointer < diffs.length) {
  762. if (diffs[pointer - 1][0] == DIFF_DELETE &&
  763. diffs[pointer][0] == DIFF_INSERT) {
  764. var deletion = diffs[pointer - 1][1];
  765. var insertion = diffs[pointer][1];
  766. var overlap_length1 = this.diff_commonOverlap_(deletion, insertion);
  767. var overlap_length2 = this.diff_commonOverlap_(insertion, deletion);
  768. if (overlap_length1 >= overlap_length2) {
  769. if (overlap_length1 >= deletion.length / 2 ||
  770. overlap_length1 >= insertion.length / 2) {
  771. // Overlap found. Insert an equality and trim the surrounding edits.
  772. diffs.splice(pointer, 0, new diff_match_patch.Diff(DIFF_EQUAL,
  773. insertion.substring(0, overlap_length1)));
  774. diffs[pointer - 1][1] =
  775. deletion.substring(0, deletion.length - overlap_length1);
  776. diffs[pointer + 1][1] = insertion.substring(overlap_length1);
  777. pointer++;
  778. }
  779. } else {
  780. if (overlap_length2 >= deletion.length / 2 ||
  781. overlap_length2 >= insertion.length / 2) {
  782. // Reverse overlap found.
  783. // Insert an equality and swap and trim the surrounding edits.
  784. diffs.splice(pointer, 0, new diff_match_patch.Diff(DIFF_EQUAL,
  785. deletion.substring(0, overlap_length2)));
  786. diffs[pointer - 1][0] = DIFF_INSERT;
  787. diffs[pointer - 1][1] =
  788. insertion.substring(0, insertion.length - overlap_length2);
  789. diffs[pointer + 1][0] = DIFF_DELETE;
  790. diffs[pointer + 1][1] =
  791. deletion.substring(overlap_length2);
  792. pointer++;
  793. }
  794. }
  795. pointer++;
  796. }
  797. pointer++;
  798. }
  799. };
  800. /**
  801. * Look for single edits surrounded on both sides by equalities
  802. * which can be shifted sideways to align the edit to a word boundary.
  803. * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
  804. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  805. */
  806. diff_match_patch.prototype.diff_cleanupSemanticLossless = function(diffs) {
  807. /**
  808. * Given two strings, compute a score representing whether the internal
  809. * boundary falls on logical boundaries.
  810. * Scores range from 6 (best) to 0 (worst).
  811. * Closure, but does not reference any external variables.
  812. * @param {string} one First string.
  813. * @param {string} two Second string.
  814. * @return {number} The score.
  815. * @private
  816. */
  817. function diff_cleanupSemanticScore_(one, two) {
  818. if (!one || !two) {
  819. // Edges are the best.
  820. return 6;
  821. }
  822. // Each port of this function behaves slightly differently due to
  823. // subtle differences in each language's definition of things like
  824. // 'whitespace'. Since this function's purpose is largely cosmetic,
  825. // the choice has been made to use each language's native features
  826. // rather than force total conformity.
  827. var char1 = one.charAt(one.length - 1);
  828. var char2 = two.charAt(0);
  829. var nonAlphaNumeric1 = char1.match(diff_match_patch.nonAlphaNumericRegex_);
  830. var nonAlphaNumeric2 = char2.match(diff_match_patch.nonAlphaNumericRegex_);
  831. var whitespace1 = nonAlphaNumeric1 &&
  832. char1.match(diff_match_patch.whitespaceRegex_);
  833. var whitespace2 = nonAlphaNumeric2 &&
  834. char2.match(diff_match_patch.whitespaceRegex_);
  835. var lineBreak1 = whitespace1 &&
  836. char1.match(diff_match_patch.linebreakRegex_);
  837. var lineBreak2 = whitespace2 &&
  838. char2.match(diff_match_patch.linebreakRegex_);
  839. var blankLine1 = lineBreak1 &&
  840. one.match(diff_match_patch.blanklineEndRegex_);
  841. var blankLine2 = lineBreak2 &&
  842. two.match(diff_match_patch.blanklineStartRegex_);
  843. if (blankLine1 || blankLine2) {
  844. // Five points for blank lines.
  845. return 5;
  846. } else if (lineBreak1 || lineBreak2) {
  847. // Four points for line breaks.
  848. return 4;
  849. } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) {
  850. // Three points for end of sentences.
  851. return 3;
  852. } else if (whitespace1 || whitespace2) {
  853. // Two points for whitespace.
  854. return 2;
  855. } else if (nonAlphaNumeric1 || nonAlphaNumeric2) {
  856. // One point for non-alphanumeric.
  857. return 1;
  858. }
  859. return 0;
  860. }
  861. var pointer = 1;
  862. // Intentionally ignore the first and last element (don't need checking).
  863. while (pointer < diffs.length - 1) {
  864. if (diffs[pointer - 1][0] == DIFF_EQUAL &&
  865. diffs[pointer + 1][0] == DIFF_EQUAL) {
  866. // This is a single edit surrounded by equalities.
  867. var equality1 = diffs[pointer - 1][1];
  868. var edit = diffs[pointer][1];
  869. var equality2 = diffs[pointer + 1][1];
  870. // First, shift the edit as far left as possible.
  871. var commonOffset = this.diff_commonSuffix(equality1, edit);
  872. if (commonOffset) {
  873. var commonString = edit.substring(edit.length - commonOffset);
  874. equality1 = equality1.substring(0, equality1.length - commonOffset);
  875. edit = commonString + edit.substring(0, edit.length - commonOffset);
  876. equality2 = commonString + equality2;
  877. }
  878. // Second, step character by character right, looking for the best fit.
  879. var bestEquality1 = equality1;
  880. var bestEdit = edit;
  881. var bestEquality2 = equality2;
  882. var bestScore = diff_cleanupSemanticScore_(equality1, edit) +
  883. diff_cleanupSemanticScore_(edit, equality2);
  884. while (edit.charAt(0) === equality2.charAt(0)) {
  885. equality1 += edit.charAt(0);
  886. edit = edit.substring(1) + equality2.charAt(0);
  887. equality2 = equality2.substring(1);
  888. var score = diff_cleanupSemanticScore_(equality1, edit) +
  889. diff_cleanupSemanticScore_(edit, equality2);
  890. // The >= encourages trailing rather than leading whitespace on edits.
  891. if (score >= bestScore) {
  892. bestScore = score;
  893. bestEquality1 = equality1;
  894. bestEdit = edit;
  895. bestEquality2 = equality2;
  896. }
  897. }
  898. if (diffs[pointer - 1][1] != bestEquality1) {
  899. // We have an improvement, save it back to the diff.
  900. if (bestEquality1) {
  901. diffs[pointer - 1][1] = bestEquality1;
  902. } else {
  903. diffs.splice(pointer - 1, 1);
  904. pointer--;
  905. }
  906. diffs[pointer][1] = bestEdit;
  907. if (bestEquality2) {
  908. diffs[pointer + 1][1] = bestEquality2;
  909. } else {
  910. diffs.splice(pointer + 1, 1);
  911. pointer--;
  912. }
  913. }
  914. }
  915. pointer++;
  916. }
  917. };
  918. // Define some regex patterns for matching boundaries.
  919. diff_match_patch.nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/;
  920. diff_match_patch.whitespaceRegex_ = /\s/;
  921. diff_match_patch.linebreakRegex_ = /[\r\n]/;
  922. diff_match_patch.blanklineEndRegex_ = /\n\r?\n$/;
  923. diff_match_patch.blanklineStartRegex_ = /^\r?\n\r?\n/;
  924. /**
  925. * Reduce the number of edits by eliminating operationally trivial equalities.
  926. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  927. */
  928. diff_match_patch.prototype.diff_cleanupEfficiency = function(diffs) {
  929. var changes = false;
  930. var equalities = []; // Stack of indices where equalities are found.
  931. var equalitiesLength = 0; // Keeping our own length var is faster in JS.
  932. /** @type {?string} */
  933. var lastEquality = null;
  934. // Always equal to diffs[equalities[equalitiesLength - 1]][1]
  935. var pointer = 0; // Index of current position.
  936. // Is there an insertion operation before the last equality.
  937. var pre_ins = false;
  938. // Is there a deletion operation before the last equality.
  939. var pre_del = false;
  940. // Is there an insertion operation after the last equality.
  941. var post_ins = false;
  942. // Is there a deletion operation after the last equality.
  943. var post_del = false;
  944. while (pointer < diffs.length) {
  945. if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found.
  946. if (diffs[pointer][1].length < this.Diff_EditCost &&
  947. (post_ins || post_del)) {
  948. // Candidate found.
  949. equalities[equalitiesLength++] = pointer;
  950. pre_ins = post_ins;
  951. pre_del = post_del;
  952. lastEquality = diffs[pointer][1];
  953. } else {
  954. // Not a candidate, and can never become one.
  955. equalitiesLength = 0;
  956. lastEquality = null;
  957. }
  958. post_ins = post_del = false;
  959. } else { // An insertion or deletion.
  960. if (diffs[pointer][0] == DIFF_DELETE) {
  961. post_del = true;
  962. } else {
  963. post_ins = true;
  964. }
  965. /*
  966. * Five types to be split:
  967. * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
  968. * <ins>A</ins>X<ins>C</ins><del>D</del>
  969. * <ins>A</ins><del>B</del>X<ins>C</ins>
  970. * <ins>A</del>X<ins>C</ins><del>D</del>
  971. * <ins>A</ins><del>B</del>X<del>C</del>
  972. */
  973. if (lastEquality && ((pre_ins && pre_del && post_ins && post_del) ||
  974. ((lastEquality.length < this.Diff_EditCost / 2) &&
  975. (pre_ins + pre_del + post_ins + post_del) == 3))) {
  976. // Duplicate record.
  977. diffs.splice(equalities[equalitiesLength - 1], 0,
  978. new diff_match_patch.Diff(DIFF_DELETE, lastEquality));
  979. // Change second copy to insert.
  980. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  981. equalitiesLength--; // Throw away the equality we just deleted;
  982. lastEquality = null;
  983. if (pre_ins && pre_del) {
  984. // No changes made which could affect previous entry, keep going.
  985. post_ins = post_del = true;
  986. equalitiesLength = 0;
  987. } else {
  988. equalitiesLength--; // Throw away the previous equality.
  989. pointer = equalitiesLength > 0 ?
  990. equalities[equalitiesLength - 1] : -1;
  991. post_ins = post_del = false;
  992. }
  993. changes = true;
  994. }
  995. }
  996. pointer++;
  997. }
  998. if (changes) {
  999. this.diff_cleanupMerge(diffs);
  1000. }
  1001. };
  1002. /**
  1003. * Reorder and merge like edit sections. Merge equalities.
  1004. * Any edit section can move as long as it doesn't cross an equality.
  1005. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1006. */
  1007. diff_match_patch.prototype.diff_cleanupMerge = function(diffs) {
  1008. // Add a dummy entry at the end.
  1009. diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, ''));
  1010. var pointer = 0;
  1011. var count_delete = 0;
  1012. var count_insert = 0;
  1013. var text_delete = '';
  1014. var text_insert = '';
  1015. var commonlength;
  1016. while (pointer < diffs.length) {
  1017. switch (diffs[pointer][0]) {
  1018. case DIFF_INSERT:
  1019. count_insert++;
  1020. text_insert += diffs[pointer][1];
  1021. pointer++;
  1022. break;
  1023. case DIFF_DELETE:
  1024. count_delete++;
  1025. text_delete += diffs[pointer][1];
  1026. pointer++;
  1027. break;
  1028. case DIFF_EQUAL:
  1029. // Upon reaching an equality, check for prior redundancies.
  1030. if (count_delete + count_insert > 1) {
  1031. if (count_delete !== 0 && count_insert !== 0) {
  1032. // Factor out any common prefixies.
  1033. commonlength = this.diff_commonPrefix(text_insert, text_delete);
  1034. if (commonlength !== 0) {
  1035. if ((pointer - count_delete - count_insert) > 0 &&
  1036. diffs[pointer - count_delete - count_insert - 1][0] ==
  1037. DIFF_EQUAL) {
  1038. diffs[pointer - count_delete - count_insert - 1][1] +=
  1039. text_insert.substring(0, commonlength);
  1040. } else {
  1041. diffs.splice(0, 0, new diff_match_patch.Diff(DIFF_EQUAL,
  1042. text_insert.substring(0, commonlength)));
  1043. pointer++;
  1044. }
  1045. text_insert = text_insert.substring(commonlength);
  1046. text_delete = text_delete.substring(commonlength);
  1047. }
  1048. // Factor out any common suffixies.
  1049. commonlength = this.diff_commonSuffix(text_insert, text_delete);
  1050. if (commonlength !== 0) {
  1051. diffs[pointer][1] = text_insert.substring(text_insert.length -
  1052. commonlength) + diffs[pointer][1];
  1053. text_insert = text_insert.substring(0, text_insert.length -
  1054. commonlength);
  1055. text_delete = text_delete.substring(0, text_delete.length -
  1056. commonlength);
  1057. }
  1058. }
  1059. // Delete the offending records and add the merged ones.
  1060. pointer -= count_delete + count_insert;
  1061. diffs.splice(pointer, count_delete + count_insert);
  1062. if (text_delete.length) {
  1063. diffs.splice(pointer, 0,
  1064. new diff_match_patch.Diff(DIFF_DELETE, text_delete));
  1065. pointer++;
  1066. }
  1067. if (text_insert.length) {
  1068. diffs.splice(pointer, 0,
  1069. new diff_match_patch.Diff(DIFF_INSERT, text_insert));
  1070. pointer++;
  1071. }
  1072. pointer++;
  1073. } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) {
  1074. // Merge this equality with the previous one.
  1075. diffs[pointer - 1][1] += diffs[pointer][1];
  1076. diffs.splice(pointer, 1);
  1077. } else {
  1078. pointer++;
  1079. }
  1080. count_insert = 0;
  1081. count_delete = 0;
  1082. text_delete = '';
  1083. text_insert = '';
  1084. break;
  1085. }
  1086. }
  1087. if (diffs[diffs.length - 1][1] === '') {
  1088. diffs.pop(); // Remove the dummy entry at the end.
  1089. }
  1090. // Second pass: look for single edits surrounded on both sides by equalities
  1091. // which can be shifted sideways to eliminate an equality.
  1092. // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
  1093. var changes = false;
  1094. pointer = 1;
  1095. // Intentionally ignore the first and last element (don't need checking).
  1096. while (pointer < diffs.length - 1) {
  1097. if (diffs[pointer - 1][0] == DIFF_EQUAL &&
  1098. diffs[pointer + 1][0] == DIFF_EQUAL) {
  1099. // This is a single edit surrounded by equalities.
  1100. if (diffs[pointer][1].substring(diffs[pointer][1].length -
  1101. diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) {
  1102. // Shift the edit over the previous equality.
  1103. diffs[pointer][1] = diffs[pointer - 1][1] +
  1104. diffs[pointer][1].substring(0, diffs[pointer][1].length -
  1105. diffs[pointer - 1][1].length);
  1106. diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
  1107. diffs.splice(pointer - 1, 1);
  1108. changes = true;
  1109. } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==
  1110. diffs[pointer + 1][1]) {
  1111. // Shift the edit over the next equality.
  1112. diffs[pointer - 1][1] += diffs[pointer + 1][1];
  1113. diffs[pointer][1] =
  1114. diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
  1115. diffs[pointer + 1][1];
  1116. diffs.splice(pointer + 1, 1);
  1117. changes = true;
  1118. }
  1119. }
  1120. pointer++;
  1121. }
  1122. // If shifts were made, the diff needs reordering and another shift sweep.
  1123. if (changes) {
  1124. this.diff_cleanupMerge(diffs);
  1125. }
  1126. };
  1127. /**
  1128. * loc is a location in text1, compute and return the equivalent location in
  1129. * text2.
  1130. * e.g. 'The cat' vs 'The big cat', 1->1, 5->8
  1131. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1132. * @param {number} loc Location within text1.
  1133. * @return {number} Location within text2.
  1134. */
  1135. diff_match_patch.prototype.diff_xIndex = function(diffs, loc) {
  1136. var chars1 = 0;
  1137. var chars2 = 0;
  1138. var last_chars1 = 0;
  1139. var last_chars2 = 0;
  1140. var x;
  1141. for (x = 0; x < diffs.length; x++) {
  1142. if (diffs[x][0] !== DIFF_INSERT) { // Equality or deletion.
  1143. chars1 += diffs[x][1].length;
  1144. }
  1145. if (diffs[x][0] !== DIFF_DELETE) { // Equality or insertion.
  1146. chars2 += diffs[x][1].length;
  1147. }
  1148. if (chars1 > loc) { // Overshot the location.
  1149. break;
  1150. }
  1151. last_chars1 = chars1;
  1152. last_chars2 = chars2;
  1153. }
  1154. // Was the location was deleted?
  1155. if (diffs.length != x && diffs[x][0] === DIFF_DELETE) {
  1156. return last_chars2;
  1157. }
  1158. // Add the remaining character length.
  1159. return last_chars2 + (loc - last_chars1);
  1160. };
  1161. /**
  1162. * Convert a diff array into a pretty HTML report.
  1163. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1164. * @return {string} HTML representation.
  1165. */
  1166. diff_match_patch.prototype.diff_prettyHtml = function(diffs) {
  1167. var html = [];
  1168. var pattern_amp = /&/g;
  1169. var pattern_lt = /</g;
  1170. var pattern_gt = />/g;
  1171. var pattern_para = /\n/g;
  1172. for (var x = 0; x < diffs.length; x++) {
  1173. var op = diffs[x][0]; // Operation (insert, delete, equal)
  1174. var data = diffs[x][1]; // Text of change.
  1175. // var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
  1176. // .replace(pattern_gt, '&gt;').replace(pattern_para, '&para;<br>');
  1177. var text = data;
  1178. switch (op) {
  1179. case DIFF_INSERT:
  1180. //text = data.replace(pattern_para, '&para;<br>');
  1181. html[x] = '<ins style="background:#e6ffe6;">' + text + '</ins>';
  1182. break;
  1183. case DIFF_DELETE:
  1184. //text = data.replace(pattern_para, '&para;<br>');
  1185. html[x] = '<del style="background:#ffe6e6;">' + text + '</del>';
  1186. break;
  1187. case DIFF_EQUAL:
  1188. html[x] = '<span>' + text + '</span>';
  1189. break;
  1190. }
  1191. }
  1192. return html.join('');
  1193. };
  1194. /**
  1195. * Compute and return the source text (all equalities and deletions).
  1196. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1197. * @return {string} Source text.
  1198. */
  1199. diff_match_patch.prototype.diff_text1 = function(diffs) {
  1200. var text = [];
  1201. for (var x = 0; x < diffs.length; x++) {
  1202. if (diffs[x][0] !== DIFF_INSERT) {
  1203. text[x] = diffs[x][1];
  1204. }
  1205. }
  1206. return text.join('');
  1207. };
  1208. /**
  1209. * Compute and return the destination text (all equalities and insertions).
  1210. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1211. * @return {string} Destination text.
  1212. */
  1213. diff_match_patch.prototype.diff_text2 = function(diffs) {
  1214. var text = [];
  1215. for (var x = 0; x < diffs.length; x++) {
  1216. if (diffs[x][0] !== DIFF_DELETE) {
  1217. text[x] = diffs[x][1];
  1218. }
  1219. }
  1220. return text.join('');
  1221. };
  1222. /**
  1223. * Compute the Levenshtein distance; the number of inserted, deleted or
  1224. * substituted characters.
  1225. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1226. * @return {number} Number of changes.
  1227. */
  1228. diff_match_patch.prototype.diff_levenshtein = function(diffs) {
  1229. var levenshtein = 0;
  1230. var insertions = 0;
  1231. var deletions = 0;
  1232. for (var x = 0; x < diffs.length; x++) {
  1233. var op = diffs[x][0];
  1234. var data = diffs[x][1];
  1235. switch (op) {
  1236. case DIFF_INSERT:
  1237. insertions += data.length;
  1238. break;
  1239. case DIFF_DELETE:
  1240. deletions += data.length;
  1241. break;
  1242. case DIFF_EQUAL:
  1243. // A deletion and an insertion is one substitution.
  1244. levenshtein += Math.max(insertions, deletions);
  1245. insertions = 0;
  1246. deletions = 0;
  1247. break;
  1248. }
  1249. }
  1250. levenshtein += Math.max(insertions, deletions);
  1251. return levenshtein;
  1252. };
  1253. /**
  1254. * Crush the diff into an encoded string which describes the operations
  1255. * required to transform text1 into text2.
  1256. * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.
  1257. * Operations are tab-separated. Inserted text is escaped using %xx notation.
  1258. * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
  1259. * @return {string} Delta text.
  1260. */
  1261. diff_match_patch.prototype.diff_toDelta = function(diffs) {
  1262. var text = [];
  1263. for (var x = 0; x < diffs.length; x++) {
  1264. switch (diffs[x][0]) {
  1265. case DIFF_INSERT:
  1266. text[x] = '+' + encodeURI(diffs[x][1]);
  1267. break;
  1268. case DIFF_DELETE:
  1269. text[x] = '-' + diffs[x][1].length;
  1270. break;
  1271. case DIFF_EQUAL:
  1272. text[x] = '=' + diffs[x][1].length;
  1273. break;
  1274. }
  1275. }
  1276. return text.join('\t').replace(/%20/g, ' ');
  1277. };
  1278. /**
  1279. * Given the original text1, and an encoded string which describes the
  1280. * operations required to transform text1 into text2, compute the full diff.
  1281. * @param {string} text1 Source string for the diff.
  1282. * @param {string} delta Delta text.
  1283. * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
  1284. * @throws {!Error} If invalid input.
  1285. */
  1286. diff_match_patch.prototype.diff_fromDelta = function(text1, delta) {
  1287. var diffs = [];
  1288. var diffsLength = 0; // Keeping our own length var is faster in JS.
  1289. var pointer = 0; // Cursor in text1
  1290. var tokens = delta.split(/\t/g);
  1291. for (var x = 0; x < tokens.length; x++) {
  1292. // Each token begins with a one character parameter which specifies the
  1293. // operation of this token (delete, insert, equality).
  1294. var param = tokens[x].substring(1);
  1295. switch (tokens[x].charAt(0)) {
  1296. case '+':
  1297. try {
  1298. diffs[diffsLength++] =
  1299. new diff_match_patch.Diff(DIFF_INSERT, decodeURI(param));
  1300. } catch (ex) {
  1301. // Malformed URI sequence.
  1302. throw new Error('Illegal escape in diff_fromDelta: ' + param);
  1303. }
  1304. break;
  1305. case '-':
  1306. // Fall through.
  1307. case '=':
  1308. var n = parseInt(param, 10);
  1309. if (isNaN(n) || n < 0) {
  1310. throw new Error('Invalid number in diff_fromDelta: ' + param);
  1311. }
  1312. var text = text1.substring(pointer, pointer += n);
  1313. if (tokens[x].charAt(0) == '=') {
  1314. diffs[diffsLength++] = new diff_match_patch.Diff(DIFF_EQUAL, text);
  1315. } else {
  1316. diffs[diffsLength++] = new diff_match_patch.Diff(DIFF_DELETE, text);
  1317. }
  1318. break;
  1319. default:
  1320. // Blank tokens are ok (from a trailing \t).
  1321. // Anything else is an error.
  1322. if (tokens[x]) {
  1323. throw new Error('Invalid diff operation in diff_fromDelta: ' +
  1324. tokens[x]);
  1325. }
  1326. }
  1327. }
  1328. if (pointer != text1.length) {
  1329. throw new Error('Delta length (' + pointer +
  1330. ') does not equal source text length (' + text1.length + ').');
  1331. }
  1332. return diffs;
  1333. };
  1334. // MATCH FUNCTIONS
  1335. /**
  1336. * Locate the best instance of 'pattern' in 'text' near 'loc'.
  1337. * @param {string} text The text to search.
  1338. * @param {string} pattern The pattern to search for.
  1339. * @param {number} loc The location to search around.
  1340. * @return {number} Best match index or -1.
  1341. */
  1342. diff_match_patch.prototype.match_main = function(text, pattern, loc) {
  1343. // Check for null inputs.
  1344. if (text == null || pattern == null || loc == null) {
  1345. throw new Error('Null input. (match_main)');
  1346. }
  1347. loc = Math.max(0, Math.min(loc, text.length));
  1348. if (text == pattern) {
  1349. // Shortcut (potentially not guaranteed by the algorithm)
  1350. return 0;
  1351. } else if (!text.length) {
  1352. // Nothing to match.
  1353. return -1;
  1354. } else if (text.substring(loc, loc + pattern.length) == pattern) {
  1355. // Perfect match at the perfect spot! (Includes case of null pattern)
  1356. return loc;
  1357. } else {
  1358. // Do a fuzzy compare.
  1359. return this.match_bitap_(text, pattern, loc);
  1360. }
  1361. };
  1362. /**
  1363. * Locate the best instance of 'pattern' in 'text' near 'loc' using the
  1364. * Bitap algorithm.
  1365. * @param {string} text The text to search.
  1366. * @param {string} pattern The pattern to search for.
  1367. * @param {number} loc The location to search around.
  1368. * @return {number} Best match index or -1.
  1369. * @private
  1370. */
  1371. diff_match_patch.prototype.match_bitap_ = function(text, pattern, loc) {
  1372. if (pattern.length > this.Match_MaxBits) {
  1373. throw new Error('Pattern too long for this browser.');
  1374. }
  1375. // Initialise the alphabet.
  1376. var s = this.match_alphabet_(pattern);
  1377. var dmp = this; // 'this' becomes 'window' in a closure.
  1378. /**
  1379. * Compute and return the score for a match with e errors and x location.
  1380. * Accesses loc and pattern through being a closure.
  1381. * @param {number} e Number of errors in match.
  1382. * @param {number} x Location of match.
  1383. * @return {number} Overall score for match (0.0 = good, 1.0 = bad).
  1384. * @private
  1385. */
  1386. function match_bitapScore_(e, x) {
  1387. var accuracy = e / pattern.length;
  1388. var proximity = Math.abs(loc - x);
  1389. if (!dmp.Match_Distance) {
  1390. // Dodge divide by zero error.
  1391. return proximity ? 1.0 : accuracy;
  1392. }
  1393. return accuracy + (proximity / dmp.Match_Distance);
  1394. }
  1395. // Highest score beyond which we give up.
  1396. var score_threshold = this.Match_Threshold;
  1397. // Is there a nearby exact match? (speedup)
  1398. var best_loc = text.indexOf(pattern, loc);
  1399. if (best_loc != -1) {
  1400. score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold);
  1401. // What about in the other direction? (speedup)
  1402. best_loc = text.lastIndexOf(pattern, loc + pattern.length);
  1403. if (best_loc != -1) {
  1404. score_threshold =
  1405. Math.min(match_bitapScore_(0, best_loc), score_threshold);
  1406. }
  1407. }
  1408. // Initialise the bit arrays.
  1409. var matchmask = 1 << (pattern.length - 1);
  1410. best_loc = -1;
  1411. var bin_min, bin_mid;
  1412. var bin_max = pattern.length + text.length;
  1413. var last_rd;
  1414. for (var d = 0; d < pattern.length; d++) {
  1415. // Scan for the best match; each iteration allows for one more error.
  1416. // Run a binary search to determine how far from 'loc' we can stray at this
  1417. // error level.
  1418. bin_min = 0;
  1419. bin_mid = bin_max;
  1420. while (bin_min < bin_mid) {
  1421. if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) {
  1422. bin_min = bin_mid;
  1423. } else {
  1424. bin_max = bin_mid;
  1425. }
  1426. bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min);
  1427. }
  1428. // Use the result from this iteration as the maximum for the next.
  1429. bin_max = bin_mid;
  1430. var start = Math.max(1, loc - bin_mid + 1);
  1431. var finish = Math.min(loc + bin_mid, text.length) + pattern.length;
  1432. var rd = Array(finish + 2);
  1433. rd[finish + 1] = (1 << d) - 1;
  1434. for (var j = finish; j >= start; j--) {
  1435. // The alphabet (s) is a sparse hash, so the following line generates
  1436. // warnings.
  1437. var charMatch = s[text.charAt(j - 1)];
  1438. if (d === 0) { // First pass: exact match.
  1439. rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
  1440. } else { // Subsequent passes: fuzzy match.
  1441. rd[j] = (((rd[j + 1] << 1) | 1) & charMatch) |
  1442. (((last_rd[j + 1] | last_rd[j]) << 1) | 1) |
  1443. last_rd[j + 1];
  1444. }
  1445. if (rd[j] & matchmask) {
  1446. var score = match_bitapScore_(d, j - 1);
  1447. // This match will almost certainly be better than any existing match.
  1448. // But check anyway.
  1449. if (score <= score_threshold) {
  1450. // Told you so.
  1451. score_threshold = score;
  1452. best_loc = j - 1;
  1453. if (best_loc > loc) {
  1454. // When passing loc, don't exceed our current distance from loc.
  1455. start = Math.max(1, 2 * loc - best_loc);
  1456. } else {
  1457. // Already passed loc, downhill from here on in.
  1458. break;
  1459. }
  1460. }
  1461. }
  1462. }
  1463. // No hope for a (better) match at greater error levels.
  1464. if (match_bitapScore_(d + 1, loc) > score_threshold) {
  1465. break;
  1466. }
  1467. last_rd = rd;
  1468. }
  1469. return best_loc;
  1470. };
  1471. /**
  1472. * Initialise the alphabet for the Bitap algorithm.
  1473. * @param {string} pattern The text to encode.
  1474. * @return {!Object} Hash of character locations.
  1475. * @private
  1476. */
  1477. diff_match_patch.prototype.match_alphabet_ = function(pattern) {
  1478. var s = {};
  1479. for (var i = 0; i < pattern.length; i++) {
  1480. s[pattern.charAt(i)] = 0;
  1481. }
  1482. for (var i = 0; i < pattern.length; i++) {
  1483. s[pattern.charAt(i)] |= 1 << (pattern.length - i - 1);
  1484. }
  1485. return s;
  1486. };
  1487. // PATCH FUNCTIONS
  1488. /**
  1489. * Increase the context until it is unique,
  1490. * but don't let the pattern expand beyond Match_MaxBits.
  1491. * @param {!diff_match_patch.patch_obj} patch The patch to grow.
  1492. * @param {string} text Source text.
  1493. * @private
  1494. */
  1495. diff_match_patch.prototype.patch_addContext_ = function(patch, text) {
  1496. if (text.length == 0) {
  1497. return;
  1498. }
  1499. if (patch.start2 === null) {
  1500. throw Error('patch not initialized');
  1501. }
  1502. var pattern = text.substring(patch.start2, patch.start2 + patch.length1);
  1503. var padding = 0;
  1504. // Look for the first and last matches of pattern in text. If two different
  1505. // matches are found, increase the pattern length.
  1506. while (text.indexOf(pattern) != text.lastIndexOf(pattern) &&
  1507. pattern.length < this.Match_MaxBits - this.Patch_Margin -
  1508. this.Patch_Margin) {
  1509. padding += this.Patch_Margin;
  1510. pattern = text.substring(patch.start2 - padding,
  1511. patch.start2 + patch.length1 + padding);
  1512. }
  1513. // Add one chunk for good luck.
  1514. padding += this.Patch_Margin;
  1515. // Add the prefix.
  1516. var prefix = text.substring(patch.start2 - padding, patch.start2);
  1517. if (prefix) {
  1518. patch.diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL, prefix));
  1519. }
  1520. // Add the suffix.
  1521. var suffix = text.substring(patch.start2 + patch.length1,
  1522. patch.start2 + patch.length1 + padding);
  1523. if (suffix) {
  1524. patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, suffix));
  1525. }
  1526. // Roll back the start points.
  1527. patch.start1 -= prefix.length;
  1528. patch.start2 -= prefix.length;
  1529. // Extend the lengths.
  1530. patch.length1 += prefix.length + suffix.length;
  1531. patch.length2 += prefix.length + suffix.length;
  1532. };
  1533. /**
  1534. * Compute a list of patches to turn text1 into text2.
  1535. * Use diffs if provided, otherwise compute it ourselves.
  1536. * There are four ways to call this function, depending on what data is
  1537. * available to the caller:
  1538. * Method 1:
  1539. * a = text1, b = text2
  1540. * Method 2:
  1541. * a = diffs
  1542. * Method 3 (optimal):
  1543. * a = text1, b = diffs
  1544. * Method 4 (deprecated, use method 3):
  1545. * a = text1, b = text2, c = diffs
  1546. *
  1547. * @param {string|!Array.<!diff_match_patch.Diff>} a text1 (methods 1,3,4) or
  1548. * Array of diff tuples for text1 to text2 (method 2).
  1549. * @param {string|!Array.<!diff_match_patch.Diff>=} opt_b text2 (methods 1,4) or
  1550. * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2).
  1551. * @param {string|!Array.<!diff_match_patch.Diff>=} opt_c Array of diff tuples
  1552. * for text1 to text2 (method 4) or undefined (methods 1,2,3).
  1553. * @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.
  1554. */
  1555. diff_match_patch.prototype.patch_make = function(a, opt_b, opt_c) {
  1556. var text1, diffs;
  1557. if (typeof a == 'string' && typeof opt_b == 'string' &&
  1558. typeof opt_c == 'undefined') {
  1559. // Method 1: text1, text2
  1560. // Compute diffs from text1 and text2.
  1561. text1 = /** @type {string} */(a);
  1562. diffs = this.diff_main(text1, /** @type {string} */(opt_b), true);
  1563. if (diffs.length > 2) {
  1564. this.diff_cleanupSemantic(diffs);
  1565. this.diff_cleanupEfficiency(diffs);
  1566. }
  1567. } else if (a && typeof a == 'object' && typeof opt_b == 'undefined' &&
  1568. typeof opt_c == 'undefined') {
  1569. // Method 2: diffs
  1570. // Compute text1 from diffs.
  1571. diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(a);
  1572. text1 = this.diff_text1(diffs);
  1573. } else if (typeof a == 'string' && opt_b && typeof opt_b == 'object' &&
  1574. typeof opt_c == 'undefined') {
  1575. // Method 3: text1, diffs
  1576. text1 = /** @type {string} */(a);
  1577. diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(opt_b);
  1578. } else if (typeof a == 'string' && typeof opt_b == 'string' &&
  1579. opt_c && typeof opt_c == 'object') {
  1580. // Method 4: text1, text2, diffs
  1581. // text2 is not used.
  1582. text1 = /** @type {string} */(a);
  1583. diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(opt_c);
  1584. } else {
  1585. throw new Error('Unknown call format to patch_make.');
  1586. }
  1587. if (diffs.length === 0) {
  1588. return []; // Get rid of the null case.
  1589. }
  1590. var patches = [];
  1591. var patch = new diff_match_patch.patch_obj();
  1592. var patchDiffLength = 0; // Keeping our own length var is faster in JS.
  1593. var char_count1 = 0; // Number of characters into the text1 string.
  1594. var char_count2 = 0; // Number of characters into the text2 string.
  1595. // Start with text1 (prepatch_text) and apply the diffs until we arrive at
  1596. // text2 (postpatch_text). We recreate the patches one by one to determine
  1597. // context info.
  1598. var prepatch_text = text1;
  1599. var postpatch_text = text1;
  1600. for (var x = 0; x < diffs.length; x++) {
  1601. var diff_type = diffs[x][0];
  1602. var diff_text = diffs[x][1];
  1603. if (!patchDiffLength && diff_type !== DIFF_EQUAL) {
  1604. // A new patch starts here.
  1605. patch.start1 = char_count1;
  1606. patch.start2 = char_count2;
  1607. }
  1608. switch (diff_type) {
  1609. case DIFF_INSERT:
  1610. patch.diffs[patchDiffLength++] = diffs[x];
  1611. patch.length2 += diff_text.length;
  1612. postpatch_text = postpatch_text.substring(0, char_count2) + diff_text +
  1613. postpatch_text.substring(char_count2);
  1614. break;
  1615. case DIFF_DELETE:
  1616. patch.length1 += diff_text.length;
  1617. patch.diffs[patchDiffLength++] = diffs[x];
  1618. postpatch_text = postpatch_text.substring(0, char_count2) +
  1619. postpatch_text.substring(char_count2 +
  1620. diff_text.length);
  1621. break;
  1622. case DIFF_EQUAL:
  1623. if (diff_text.length <= 2 * this.Patch_Margin &&
  1624. patchDiffLength && diffs.length != x + 1) {
  1625. // Small equality inside a patch.
  1626. patch.diffs[patchDiffLength++] = diffs[x];
  1627. patch.length1 += diff_text.length;
  1628. patch.length2 += diff_text.length;
  1629. } else if (diff_text.length >= 2 * this.Patch_Margin) {
  1630. // Time for a new patch.
  1631. if (patchDiffLength) {
  1632. this.patch_addContext_(patch, prepatch_text);
  1633. patches.push(patch);
  1634. patch = new diff_match_patch.patch_obj();
  1635. patchDiffLength = 0;
  1636. // Unlike Unidiff, our patch lists have a rolling context.
  1637. // https://github.com/google/diff-match-patch/wiki/Unidiff
  1638. // Update prepatch text & pos to reflect the application of the
  1639. // just completed patch.
  1640. prepatch_text = postpatch_text;
  1641. char_count1 = char_count2;
  1642. }
  1643. }
  1644. break;
  1645. }
  1646. // Update the current character count.
  1647. if (diff_type !== DIFF_INSERT) {
  1648. char_count1 += diff_text.length;
  1649. }
  1650. if (diff_type !== DIFF_DELETE) {
  1651. char_count2 += diff_text.length;
  1652. }
  1653. }
  1654. // Pick up the leftover patch if not empty.
  1655. if (patchDiffLength) {
  1656. this.patch_addContext_(patch, prepatch_text);
  1657. patches.push(patch);
  1658. }
  1659. return patches;
  1660. };
  1661. /**
  1662. * Given an array of patches, return another array that is identical.
  1663. * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
  1664. * @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.
  1665. */
  1666. diff_match_patch.prototype.patch_deepCopy = function(patches) {
  1667. // Making deep copies is hard in JavaScript.
  1668. var patchesCopy = [];
  1669. for (var x = 0; x < patches.length; x++) {
  1670. var patch = patches[x];
  1671. var patchCopy = new diff_match_patch.patch_obj();
  1672. patchCopy.diffs = [];
  1673. for (var y = 0; y < patch.diffs.length; y++) {
  1674. patchCopy.diffs[y] =
  1675. new diff_match_patch.Diff(patch.diffs[y][0], patch.diffs[y][1]);
  1676. }
  1677. patchCopy.start1 = patch.start1;
  1678. patchCopy.start2 = patch.start2;
  1679. patchCopy.length1 = patch.length1;
  1680. patchCopy.length2 = patch.length2;
  1681. patchesCopy[x] = patchCopy;
  1682. }
  1683. return patchesCopy;
  1684. };
  1685. /**
  1686. * Merge a set of patches onto the text. Return a patched text, as well
  1687. * as a list of true/false values indicating which patches were applied.
  1688. * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
  1689. * @param {string} text Old text.
  1690. * @return {!Array.<string|!Array.<boolean>>} Two element Array, containing the
  1691. * new text and an array of boolean values.
  1692. */
  1693. diff_match_patch.prototype.patch_apply = function(patches, text) {
  1694. if (patches.length == 0) {
  1695. return [text, []];
  1696. }
  1697. // Deep copy the patches so that no changes are made to originals.
  1698. patches = this.patch_deepCopy(patches);
  1699. var nullPadding = this.patch_addPadding(patches);
  1700. text = nullPadding + text + nullPadding;
  1701. this.patch_splitMax(patches);
  1702. // delta keeps track of the offset between the expected and actual location
  1703. // of the previous patch. If there are patches expected at positions 10 and
  1704. // 20, but the first patch was found at 12, delta is 2 and the second patch
  1705. // has an effective expected position of 22.
  1706. var delta = 0;
  1707. var results = [];
  1708. for (var x = 0; x < patches.length; x++) {
  1709. var expected_loc = patches[x].start2 + delta;
  1710. var text1 = this.diff_text1(patches[x].diffs);
  1711. var start_loc;
  1712. var end_loc = -1;
  1713. if (text1.length > this.Match_MaxBits) {
  1714. // patch_splitMax will only provide an oversized pattern in the case of
  1715. // a monster delete.
  1716. start_loc = this.match_main(text, text1.substring(0, this.Match_MaxBits),
  1717. expected_loc);
  1718. if (start_loc != -1) {
  1719. end_loc = this.match_main(text,
  1720. text1.substring(text1.length - this.Match_MaxBits),
  1721. expected_loc + text1.length - this.Match_MaxBits);
  1722. if (end_loc == -1 || start_loc >= end_loc) {
  1723. // Can't find valid trailing context. Drop this patch.
  1724. start_loc = -1;
  1725. }
  1726. }
  1727. } else {
  1728. start_loc = this.match_main(text, text1, expected_loc);
  1729. }
  1730. if (start_loc == -1) {
  1731. // No match found. :(
  1732. results[x] = false;
  1733. // Subtract the delta for this failed patch from subsequent patches.
  1734. delta -= patches[x].length2 - patches[x].length1;
  1735. } else {
  1736. // Found a match. :)
  1737. results[x] = true;
  1738. delta = start_loc - expected_loc;
  1739. var text2;
  1740. if (end_loc == -1) {
  1741. text2 = text.substring(start_loc, start_loc + text1.length);
  1742. } else {
  1743. text2 = text.substring(start_loc, end_loc + this.Match_MaxBits);
  1744. }
  1745. if (text1 == text2) {
  1746. // Perfect match, just shove the replacement text in.
  1747. text = text.substring(0, start_loc) +
  1748. this.diff_text2(patches[x].diffs) +
  1749. text.substring(start_loc + text1.length);
  1750. } else {
  1751. // Imperfect match. Run a diff to get a framework of equivalent
  1752. // indices.
  1753. var diffs = this.diff_main(text1, text2, false);
  1754. if (text1.length > this.Match_MaxBits &&
  1755. this.diff_levenshtein(diffs) / text1.length >
  1756. this.Patch_DeleteThreshold) {
  1757. // The end points match, but the content is unacceptably bad.
  1758. results[x] = false;
  1759. } else {
  1760. this.diff_cleanupSemanticLossless(diffs);
  1761. var index1 = 0;
  1762. var index2;
  1763. for (var y = 0; y < patches[x].diffs.length; y++) {
  1764. var mod = patches[x].diffs[y];
  1765. if (mod[0] !== DIFF_EQUAL) {
  1766. index2 = this.diff_xIndex(diffs, index1);
  1767. }
  1768. if (mod[0] === DIFF_INSERT) { // Insertion
  1769. text = text.substring(0, start_loc + index2) + mod[1] +
  1770. text.substring(start_loc + index2);
  1771. } else if (mod[0] === DIFF_DELETE) { // Deletion
  1772. text = text.substring(0, start_loc + index2) + mod[1] +
  1773. text.substring(start_loc + this.diff_xIndex(diffs,
  1774. index1 + mod[1].length));
  1775. }
  1776. if (mod[0] !== DIFF_DELETE) {
  1777. index1 += mod[1].length;
  1778. }
  1779. }
  1780. }
  1781. }
  1782. }
  1783. }
  1784. // Strip the padding off.
  1785. text = text.substring(nullPadding.length, text.length - nullPadding.length);
  1786. return [text, results];
  1787. };
  1788. /**
  1789. * Add some padding on text start and end so that edges can match something.
  1790. * Intended to be called only from within patch_apply.
  1791. * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
  1792. * @return {string} The padding string added to each side.
  1793. */
  1794. diff_match_patch.prototype.patch_addPadding = function(patches) {
  1795. var paddingLength = this.Patch_Margin;
  1796. var nullPadding = '';
  1797. for (var x = 1; x <= paddingLength; x++) {
  1798. nullPadding += String.fromCharCode(x);
  1799. }
  1800. // Bump all the patches forward.
  1801. for (var x = 0; x < patches.length; x++) {
  1802. patches[x].start1 += paddingLength;
  1803. patches[x].start2 += paddingLength;
  1804. }
  1805. // Add some padding on start of first diff.
  1806. var patch = patches[0];
  1807. var diffs = patch.diffs;
  1808. if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL) {
  1809. // Add nullPadding equality.
  1810. diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL, nullPadding));
  1811. patch.start1 -= paddingLength; // Should be 0.
  1812. patch.start2 -= paddingLength; // Should be 0.
  1813. patch.length1 += paddingLength;
  1814. patch.length2 += paddingLength;
  1815. } else if (paddingLength > diffs[0][1].length) {
  1816. // Grow first equality.
  1817. var extraLength = paddingLength - diffs[0][1].length;
  1818. diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1];
  1819. patch.start1 -= extraLength;
  1820. patch.start2 -= extraLength;
  1821. patch.length1 += extraLength;
  1822. patch.length2 += extraLength;
  1823. }
  1824. // Add some padding on end of last diff.
  1825. patch = patches[patches.length - 1];
  1826. diffs = patch.diffs;
  1827. if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL) {
  1828. // Add nullPadding equality.
  1829. diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, nullPadding));
  1830. patch.length1 += paddingLength;
  1831. patch.length2 += paddingLength;
  1832. } else if (paddingLength > diffs[diffs.length - 1][1].length) {
  1833. // Grow last equality.
  1834. var extraLength = paddingLength - diffs[diffs.length - 1][1].length;
  1835. diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength);
  1836. patch.length1 += extraLength;
  1837. patch.length2 += extraLength;
  1838. }
  1839. return nullPadding;
  1840. };
  1841. /**
  1842. * Look through the patches and break up any which are longer than the maximum
  1843. * limit of the match algorithm.
  1844. * Intended to be called only from within patch_apply.
  1845. * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
  1846. */
  1847. diff_match_patch.prototype.patch_splitMax = function(patches) {
  1848. var patch_size = this.Match_MaxBits;
  1849. for (var x = 0; x < patches.length; x++) {
  1850. if (patches[x].length1 <= patch_size) {
  1851. continue;
  1852. }
  1853. var bigpatch = patches[x];
  1854. // Remove the big old patch.
  1855. patches.splice(x--, 1);
  1856. var start1 = bigpatch.start1;
  1857. var start2 = bigpatch.start2;
  1858. var precontext = '';
  1859. while (bigpatch.diffs.length !== 0) {
  1860. // Create one of several smaller patches.
  1861. var patch = new diff_match_patch.patch_obj();
  1862. var empty = true;
  1863. patch.start1 = start1 - precontext.length;
  1864. patch.start2 = start2 - precontext.length;
  1865. if (precontext !== '') {
  1866. patch.length1 = patch.length2 = precontext.length;
  1867. patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, precontext));
  1868. }
  1869. while (bigpatch.diffs.length !== 0 &&
  1870. patch.length1 < patch_size - this.Patch_Margin) {
  1871. var diff_type = bigpatch.diffs[0][0];
  1872. var diff_text = bigpatch.diffs[0][1];
  1873. if (diff_type === DIFF_INSERT) {
  1874. // Insertions are harmless.
  1875. patch.length2 += diff_text.length;
  1876. start2 += diff_text.length;
  1877. patch.diffs.push(bigpatch.diffs.shift());
  1878. empty = false;
  1879. } else if (diff_type === DIFF_DELETE && patch.diffs.length == 1 &&
  1880. patch.diffs[0][0] == DIFF_EQUAL &&
  1881. diff_text.length > 2 * patch_size) {
  1882. // This is a large deletion. Let it pass in one chunk.
  1883. patch.length1 += diff_text.length;
  1884. start1 += diff_text.length;
  1885. empty = false;
  1886. patch.diffs.push(new diff_match_patch.Diff(diff_type, diff_text));
  1887. bigpatch.diffs.shift();
  1888. } else {
  1889. // Deletion or equality. Only take as much as we can stomach.
  1890. diff_text = diff_text.substring(0,
  1891. patch_size - patch.length1 - this.Patch_Margin);
  1892. patch.length1 += diff_text.length;
  1893. start1 += diff_text.length;
  1894. if (diff_type === DIFF_EQUAL) {
  1895. patch.length2 += diff_text.length;
  1896. start2 += diff_text.length;
  1897. } else {
  1898. empty = false;
  1899. }
  1900. patch.diffs.push(new diff_match_patch.Diff(diff_type, diff_text));
  1901. if (diff_text == bigpatch.diffs[0][1]) {
  1902. bigpatch.diffs.shift();
  1903. } else {
  1904. bigpatch.diffs[0][1] =
  1905. bigpatch.diffs[0][1].substring(diff_text.length);
  1906. }
  1907. }
  1908. }
  1909. // Compute the head context for the next patch.
  1910. precontext = this.diff_text2(patch.diffs);
  1911. precontext =
  1912. precontext.substring(precontext.length - this.Patch_Margin);
  1913. // Append the end context for this patch.
  1914. var postcontext = this.diff_text1(bigpatch.diffs)
  1915. .substring(0, this.Patch_Margin);
  1916. if (postcontext !== '') {
  1917. patch.length1 += postcontext.length;
  1918. patch.length2 += postcontext.length;
  1919. if (patch.diffs.length !== 0 &&
  1920. patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL) {
  1921. patch.diffs[patch.diffs.length - 1][1] += postcontext;
  1922. } else {
  1923. patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, postcontext));
  1924. }
  1925. }
  1926. if (!empty) {
  1927. patches.splice(++x, 0, patch);
  1928. }
  1929. }
  1930. }
  1931. };
  1932. /**
  1933. * Take a list of patches and return a textual representation.
  1934. * @param {!Array.<!diff_match_patch.patch_obj>} patches Array of Patch objects.
  1935. * @return {string} Text representation of patches.
  1936. */
  1937. diff_match_patch.prototype.patch_toText = function(patches) {
  1938. var text = [];
  1939. for (var x = 0; x < patches.length; x++) {
  1940. text[x] = patches[x];
  1941. }
  1942. return text.join('');
  1943. };
  1944. /**
  1945. * Parse a textual representation of patches and return a list of Patch objects.
  1946. * @param {string} textline Text representation of patches.
  1947. * @return {!Array.<!diff_match_patch.patch_obj>} Array of Patch objects.
  1948. * @throws {!Error} If invalid input.
  1949. */
  1950. diff_match_patch.prototype.patch_fromText = function(textline) {
  1951. var patches = [];
  1952. if (!textline) {
  1953. return patches;
  1954. }
  1955. var text = textline.split('\n');
  1956. var textPointer = 0;
  1957. var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;
  1958. while (textPointer < text.length) {
  1959. var m = text[textPointer].match(patchHeader);
  1960. if (!m) {
  1961. throw new Error('Invalid patch string: ' + text[textPointer]);
  1962. }
  1963. var patch = new diff_match_patch.patch_obj();
  1964. patches.push(patch);
  1965. patch.start1 = parseInt(m[1], 10);
  1966. if (m[2] === '') {
  1967. patch.start1--;
  1968. patch.length1 = 1;
  1969. } else if (m[2] == '0') {
  1970. patch.length1 = 0;
  1971. } else {
  1972. patch.start1--;
  1973. patch.length1 = parseInt(m[2], 10);
  1974. }
  1975. patch.start2 = parseInt(m[3], 10);
  1976. if (m[4] === '') {
  1977. patch.start2--;
  1978. patch.length2 = 1;
  1979. } else if (m[4] == '0') {
  1980. patch.length2 = 0;
  1981. } else {
  1982. patch.start2--;
  1983. patch.length2 = parseInt(m[4], 10);
  1984. }
  1985. textPointer++;
  1986. while (textPointer < text.length) {
  1987. var sign = text[textPointer].charAt(0);
  1988. try {
  1989. var line = decodeURI(text[textPointer].substring(1));
  1990. } catch (ex) {
  1991. // Malformed URI sequence.
  1992. throw new Error('Illegal escape in patch_fromText: ' + line);
  1993. }
  1994. if (sign == '-') {
  1995. // Deletion.
  1996. patch.diffs.push(new diff_match_patch.Diff(DIFF_DELETE, line));
  1997. } else if (sign == '+') {
  1998. // Insertion.
  1999. patch.diffs.push(new diff_match_patch.Diff(DIFF_INSERT, line));
  2000. } else if (sign == ' ') {
  2001. // Minor equality.
  2002. patch.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL, line));
  2003. } else if (sign == '@') {
  2004. // Start of next patch.
  2005. break;
  2006. } else if (sign === '') {
  2007. // Blank line? Whatever.
  2008. } else {
  2009. // WTF?
  2010. throw new Error('Invalid patch mode "' + sign + '" in: ' + line);
  2011. }
  2012. textPointer++;
  2013. }
  2014. }
  2015. return patches;
  2016. };
  2017. /**
  2018. * Class representing one patch operation.
  2019. * @constructor
  2020. */
  2021. diff_match_patch.patch_obj = function() {
  2022. /** @type {!Array.<!diff_match_patch.Diff>} */
  2023. this.diffs = [];
  2024. /** @type {?number} */
  2025. this.start1 = null;
  2026. /** @type {?number} */
  2027. this.start2 = null;
  2028. /** @type {number} */
  2029. this.length1 = 0;
  2030. /** @type {number} */
  2031. this.length2 = 0;
  2032. };
  2033. /**
  2034. * Emulate GNU diff's format.
  2035. * Header: @@ -382,8 +481,9 @@
  2036. * Indices are printed as 1-based, not 0-based.
  2037. * @return {string} The GNU diff string.
  2038. */
  2039. diff_match_patch.patch_obj.prototype.toString = function() {
  2040. var coords1, coords2;
  2041. if (this.length1 === 0) {
  2042. coords1 = this.start1 + ',0';
  2043. } else if (this.length1 == 1) {
  2044. coords1 = this.start1 + 1;
  2045. } else {
  2046. coords1 = (this.start1 + 1) + ',' + this.length1;
  2047. }
  2048. if (this.length2 === 0) {
  2049. coords2 = this.start2 + ',0';
  2050. } else if (this.length2 == 1) {
  2051. coords2 = this.start2 + 1;
  2052. } else {
  2053. coords2 = (this.start2 + 1) + ',' + this.length2;
  2054. }
  2055. var text = ['@@ -' + coords1 + ' +' + coords2 + ' @@\n'];
  2056. var op;
  2057. // Escape the body of the patch with %xx notation.
  2058. for (var x = 0; x < this.diffs.length; x++) {
  2059. switch (this.diffs[x][0]) {
  2060. case DIFF_INSERT:
  2061. op = '+';
  2062. break;
  2063. case DIFF_DELETE:
  2064. op = '-';
  2065. break;
  2066. case DIFF_EQUAL:
  2067. op = ' ';
  2068. break;
  2069. }
  2070. text[x + 1] = op + encodeURI(this.diffs[x][1]) + '\n';
  2071. }
  2072. return text.join('').replace(/%20/g, ' ');
  2073. };
  2074. // CLOSURE:begin_strip
  2075. // Lines below here will not be included in the Closure-compatible library.
  2076. // Export these global variables so that they survive Google's JS compiler.
  2077. // In a browser, 'this' will be 'window'.
  2078. // Users of node.js should 'require' the uncompressed version since Google's
  2079. // JS compiler may break the following exports for non-browser environments.
  2080. /** @suppress {globalThis} */
  2081. this['diff_match_patch'] = diff_match_patch;
  2082. /** @suppress {globalThis} */
  2083. this['DIFF_DELETE'] = DIFF_DELETE;
  2084. /** @suppress {globalThis} */
  2085. this['DIFF_INSERT'] = DIFF_INSERT;
  2086. /** @suppress {globalThis} */
  2087. this['DIFF_EQUAL'] = DIFF_EQUAL;