diff_match_patch.js 75 KB

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