index.js 76 KB

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