1use crate::delta::encode_uri;
5use crate::engine;
6use crate::types::{max, min, Diff, Dmp, Patch};
7use core::char;
8use percent_encoding::percent_decode;
9use std::fmt;
10
11#[allow(clippy::ptr_arg)]
14impl Dmp {
15 pub fn patch_add_context(&mut self, patch: &mut Patch, text: &mut Vec<char>) {
22 if text.is_empty() {
23 return;
24 }
25 let mut pattern: Vec<char> =
26 text[patch.start2 as usize..(patch.length1 as usize + patch.start2 as usize)].to_vec();
27 let mut padding: i32 = 0;
28
29 let ambiguous = |text: &[char], pattern: &[char]| {
34 if pattern.is_empty() {
35 text.len() != 1
36 } else {
37 engine::occurs_twice(text, pattern)
38 }
39 };
40 let mut rst = 0;
41 while ambiguous(text, &pattern)
42 && (pattern.len() as i32) < (self.match_maxbits - self.patch_margin * 2)
43 {
44 padding += self.patch_margin;
45 pattern = text[max(0, patch.start2 - padding) as usize
46 ..min(text.len() as i32, patch.start2 + patch.length1 + padding) as usize]
47 .to_vec();
48 rst += 1;
49 if rst > 5 {
50 break;
51 }
52 }
53 padding += self.patch_margin;
55
56 let prefix: String = text[max(0, patch.start2 - padding) as usize..patch.start2 as usize]
58 .iter()
59 .collect();
60 let prefix_length = prefix.chars().count() as i32;
61 if !prefix.is_empty() {
62 patch.diffs.insert(0, Diff::new(0, prefix.clone()));
63 }
64
65 let suffix: String = text[(patch.start2 + patch.length1) as usize
67 ..min(text.len() as i32, patch.start2 + patch.length1 + padding) as usize]
68 .iter()
69 .collect();
70 let suffix_length = suffix.chars().count() as i32;
71 if !suffix.is_empty() {
72 patch.diffs.push(Diff::new(0, suffix));
73 }
74 patch.start1 -= prefix_length;
76 patch.start2 -= prefix_length;
77 patch.length1 += prefix_length + suffix_length;
79 patch.length2 += prefix_length + suffix_length;
80 }
81
82 pub fn patch_make1(&mut self, text1: &str, text2: &str) -> Vec<Patch> {
90 let mut diffs: Vec<Diff> = self.diff_main(text1, text2, true);
91 if diffs.len() > 2 {
92 self.diff_cleanup_semantic(&mut diffs);
93 self.diff_cleanup_efficiency(&mut diffs);
94 }
95 self.patch_make4(text1, &mut diffs)
96 }
97
98 pub fn patch_make2(&mut self, diffs: &mut Vec<Diff>) -> Vec<Patch> {
106 let text1 = self.diff_text1(diffs);
107 self.patch_make4(text1.as_str(), diffs)
108 }
109
110 pub fn patch_make3(&mut self, text1: &str, _text2: &str, diffs: &mut Vec<Diff>) -> Vec<Patch> {
120 self.patch_make4(text1, diffs)
121 }
122 pub fn patch_make4(&mut self, text1: &str, diffs: &mut Vec<Diff>) -> Vec<Patch> {
130 let mut patches: Vec<Patch> = vec![];
131 if diffs.is_empty() {
132 return patches; }
134 let mut patch: Patch = Patch::new(vec![], 0, 0, 0, 0);
135 let mut char_count1 = 0; let mut char_count2 = 0; let mut prepatch: Vec<char> = text1.chars().collect(); let mut postpatch: Vec<char> = prepatch.clone();
139 for i in 0..diffs.len() {
140 let temp1: &Vec<char> = &(diffs[i].text.chars().collect());
141 if patch.diffs.is_empty() && diffs[i].operation != 0 {
142 patch.start1 = char_count1;
144 patch.start2 = char_count2;
145 }
146 if diffs[i].operation == 1 {
147 patch
149 .diffs
150 .push(Diff::new(diffs[i].operation, diffs[i].text.clone()));
151 patch.length2 += temp1.len() as i32;
152 postpatch.splice(
153 char_count2 as usize..char_count2 as usize,
154 temp1.iter().copied(),
155 );
156 } else if diffs[i].operation == -1 {
157 patch
159 .diffs
160 .push(Diff::new(diffs[i].operation, diffs[i].text.clone()));
161 patch.length1 += temp1.len() as i32;
162 postpatch.splice(
163 char_count2 as usize..char_count2 as usize + temp1.len(),
164 std::iter::empty(),
165 );
166 } else if temp1.len() as i32 <= self.patch_margin * 2
167 && !patch.diffs.is_empty()
168 && i != diffs.len() - 1
169 {
170 patch
172 .diffs
173 .push(Diff::new(diffs[i].operation, diffs[i].text.clone()));
174 patch.length1 += temp1.len() as i32;
175 patch.length2 += temp1.len() as i32;
176 } else if temp1.len() as i32 >= 2 * self.patch_margin {
177 if !patch.diffs.is_empty() {
179 self.patch_add_context(&mut patch, &mut prepatch);
180 patches.push(patch);
181 patch = Patch::new(vec![], 0, 0, 0, 0);
182 prepatch = postpatch.clone();
183 char_count1 = char_count2;
184 }
185 }
186
187 if diffs[i].operation != 1 {
189 char_count1 += temp1.len() as i32;
190 }
191 if diffs[i].operation != -1 {
192 char_count2 += temp1.len() as i32;
193 }
194 }
195
196 if !patch.diffs.is_empty() {
198 self.patch_add_context(&mut patch, &mut prepatch);
199 patches.push(patch);
201 }
202 patches
203 }
204
205 pub fn patch_deep_copy(&mut self, patches: &mut Vec<Patch>) -> Vec<Patch> {
213 let mut patches_copy: Vec<Patch> = vec![];
214 for patches_item in patches {
215 let mut patch_copy = Patch::new(vec![], 0, 0, 0, 0);
216 for j in 0..patches_item.diffs.len() {
217 let diff_copy = Diff::new(
218 patches_item.diffs[j].operation,
219 patches_item.diffs[j].text.clone(),
220 );
221 patch_copy.diffs.push(diff_copy);
222 }
223 patch_copy.start1 = patches_item.start1;
224 patch_copy.start2 = patches_item.start2;
225 patch_copy.length1 = patches_item.length1;
226 patch_copy.length2 = patches_item.length2;
227 patches_copy.push(patch_copy);
228 }
229 patches_copy
230 }
231
232 pub fn patch_apply(
233 &mut self,
234 patches: &mut Vec<Patch>,
235 source_text: &str,
236 ) -> (Vec<char>, Vec<bool>) {
237 if patches.is_empty() {
250 return (source_text.chars().collect(), vec![]);
251 }
252
253 let mut patches_copy: Vec<Patch> = self.patch_deep_copy(patches);
255
256 let null_padding: Vec<char> = self.patch_add_padding(&mut patches_copy);
257
258 let mut text = null_padding.clone();
259 text.extend(source_text.chars());
260 text.extend(&null_padding);
261
262 self.patch_splitmax(&mut patches_copy);
263
264 let mut delta: i32 = 0;
269 let mut results: Vec<bool> = vec![false; patches_copy.len()];
270 for x in 0..patches_copy.len() {
271 let expected_loc: i32 = patches_copy[x].start2 + delta;
272 let text1: Vec<char> = diff_text1_chars(&patches_copy[x].diffs);
273 let mut start_loc: i32;
274 let mut end_loc = -1;
275 if text1.len() as i32 > self.match_maxbits {
276 start_loc = crate::match_::match_chars(
279 self,
280 &text,
281 &text1[..self.match_maxbits as usize],
282 expected_loc,
283 );
284 if start_loc != -1 {
285 end_loc = crate::match_::match_chars(
286 self,
287 &text,
288 &text1[text1.len() - self.match_maxbits as usize..],
289 expected_loc + text1.len() as i32 - self.match_maxbits,
290 );
291 if end_loc == -1 || start_loc >= end_loc {
292 start_loc = -1;
294 }
295 }
296 } else {
297 start_loc = crate::match_::match_chars(self, &text, &text1, expected_loc);
298 }
299 if start_loc == -1 {
300 results[x] = false;
302 delta -= patches_copy[x].length2 - patches_copy[x].length1;
304 } else {
305 results[x] = true;
307 delta = start_loc - expected_loc;
308
309 let mut end_index: usize;
310 if end_loc == -1 {
311 end_index = start_loc as usize + text1.len();
312 } else {
313 end_index = (end_loc + self.match_maxbits) as usize;
314 }
315 end_index = std::cmp::min(text.len(), end_index);
316
317 if text1[..] == text[start_loc as usize..end_index] {
318 let replacement = diff_text2_chars(&patches_copy[x].diffs);
320 text.splice(
321 start_loc as usize..start_loc as usize + text1.len(),
322 replacement,
323 );
324 } else {
325 let mut diffs: Vec<Diff> = crate::diff::diff_main_chars(
328 self,
329 &text1,
330 &text[start_loc as usize..end_index],
331 false,
332 );
333 if text1.len() as i32 > self.match_maxbits
334 && (self.diff_levenshtein(&diffs) as f32 / (text1.len() as f32)
335 > self.patch_delete_threshold)
336 {
337 results[x] = false;
339 } else {
340 self.diff_cleanup_semantic_lossless(&mut diffs);
341 let mut index1: i32 = 0;
342 for y in 0..patches_copy[x].diffs.len() {
343 let op = patches_copy[x].diffs[y].operation;
344 let mod_len = patches_copy[x].diffs[y].text.chars().count() as i32;
345 if op != 0 {
346 let index2: i32 = self.diff_xindex(&diffs, index1);
347 if op == 1 {
348 let at = (start_loc + index2) as usize;
350 text.splice(at..at, patches_copy[x].diffs[y].text.chars());
351 } else if op == -1 {
352 let from = (start_loc + index2) as usize;
355 let until = (start_loc
356 + self.diff_xindex(&diffs, index1 + mod_len))
357 as usize;
358 text.splice(from..until, std::iter::empty());
359 }
360 }
361 if op != -1 {
362 index1 += mod_len;
363 }
364 }
365 }
366 }
367 }
368 }
369 text.drain(..null_padding.len());
371 text.truncate(text.len() - null_padding.len());
372 (text, results)
373 }
374
375 pub fn patch_add_padding(&mut self, patches: &mut Vec<Patch>) -> Vec<char> {
384 let padding_length = self.patch_margin;
385 let mut nullpadding: Vec<char> = vec![];
386 for i in 0..padding_length {
387 if let Some(ch) = char::from_u32(1 + i as u32) {
388 nullpadding.push(ch);
389 }
390 }
391
392 for patch in patches.iter_mut() {
394 patch.start1 += padding_length;
395 patch.start2 += padding_length;
396 }
397 let mut patch = patches[0].clone();
398 let mut diffs = patch.diffs;
399 if diffs.is_empty() || diffs[0].operation != 0 {
400 diffs.insert(0, Diff::new(0, nullpadding.clone().iter().collect()));
402 patch.start1 -= padding_length; patch.start2 -= padding_length; patch.length1 += padding_length;
405 patch.length2 += padding_length;
406 } else {
407 let text_len = diffs[0].text.chars().count() as i32;
408 if padding_length > text_len {
409 let extra_length = padding_length - text_len;
411 let mut new_text: String = nullpadding[text_len as usize..].iter().collect();
412 new_text += diffs[0].text.as_str();
413 diffs[0] = Diff::new(diffs[0].operation, new_text);
414 patch.start1 -= extra_length;
415 patch.start2 -= extra_length;
416 patch.length1 += extra_length;
417 patch.length2 += extra_length;
418 }
419 }
420
421 patch.diffs = diffs;
423 patches[0] = patch;
424 patch = patches[patches.len() - 1].clone();
425 diffs = patch.diffs;
426 if diffs.is_empty() || diffs[diffs.len() - 1].operation != 0 {
427 diffs.push(Diff::new(0, nullpadding.clone().iter().collect()));
429 patch.length1 += padding_length;
430 patch.length2 += padding_length;
431 } else {
432 let text_len = diffs[diffs.len() - 1].text.chars().count() as i32;
433 if padding_length > text_len {
434 let extra_length = padding_length - text_len;
436 let mut new_text: String = nullpadding[..extra_length as usize].iter().collect();
437 let diffs_len = diffs.len();
438 new_text = diffs[diffs_len - 1].text.clone() + new_text.as_str();
439 diffs[diffs_len - 1] = Diff::new(diffs[diffs_len - 1].operation, new_text);
440 patch.length1 += extra_length;
441 patch.length2 += extra_length;
442 }
443 }
444 patch.diffs = diffs;
445 let patches_len = patches.len();
446 patches[patches_len - 1] = patch;
447 nullpadding
448 }
449
450 pub fn patch_splitmax(&mut self, patches: &mut Vec<Patch>) {
457 let patch_size = self.match_maxbits;
458 if patch_size == 0 {
459 return;
460 }
461 let mut x: i32 = 0;
462 while (x as usize) < patches.len() {
463 if patches[x as usize].length1 <= patch_size {
464 x += 1;
465 continue;
466 }
467 let mut bigpatch = patches.remove(x as usize);
469 x -= 1;
470 let mut start1 = bigpatch.start1;
471 let mut start2 = bigpatch.start2;
472 let mut precontext: Vec<char> = vec![];
473 while !bigpatch.diffs.is_empty() {
474 let mut patch = Patch::new(vec![], 0, 0, 0, 0);
476 let mut empty = true;
477 patch.start1 = start1 - precontext.len() as i32;
478 patch.start2 = start2 - precontext.len() as i32;
479 if !precontext.is_empty() {
480 patch.length1 = precontext.len() as i32;
481 patch.length2 = precontext.len() as i32;
482 patch
483 .diffs
484 .push(Diff::new(0, precontext.clone().iter().collect()));
485 }
486 while !bigpatch.diffs.is_empty() && patch.length1 < patch_size - self.patch_margin {
487 let diff_type = bigpatch.diffs[0].operation;
488 let mut diff_text: Vec<char> = bigpatch.diffs[0].text.chars().collect();
489 if diff_type == 1 {
490 patch.length2 += diff_text.len() as i32;
492 start2 += diff_text.len() as i32;
493 patch.diffs.push(bigpatch.diffs[0].clone());
494 bigpatch.diffs.remove(0);
495 empty = false;
496 } else if diff_type == -1
497 && patch.diffs.len() == 1
498 && patch.diffs[0].operation == 0
499 && (diff_text.len() as i32) > 2 * patch_size
500 {
501 patch.length1 += diff_text.len() as i32;
503 start1 += diff_text.len() as i32;
504 empty = false;
505 patch
506 .diffs
507 .push(Diff::new(diff_type, diff_text.iter().collect()));
508 bigpatch.diffs.remove(0);
509 } else {
510 let diff_text_len: i32 = diff_text.len() as i32;
512 diff_text = diff_text[..min(
513 diff_text_len,
514 patch_size - patch.length1 - self.patch_margin,
515 ) as usize]
516 .to_vec();
517 patch.length1 += diff_text.len() as i32;
518 start1 += diff_text.len() as i32;
519 if diff_type == 0 {
520 patch.length2 += diff_text.len() as i32;
521 start2 += diff_text.len() as i32;
522 } else {
523 empty = false;
524 }
525 patch
526 .diffs
527 .push(Diff::new(diff_type, diff_text.clone().iter().collect()));
528 let temp: String = diff_text[..].iter().collect();
529 if temp == bigpatch.diffs[0].text.clone() {
530 bigpatch.diffs.remove(0);
531 } else {
532 let temp1: Vec<char> = bigpatch.diffs[0].text.chars().collect();
533 bigpatch.diffs[0].text = temp1[diff_text.len()..].iter().collect();
534 }
535 }
536 }
537 precontext = self.diff_text2(&mut patch.diffs).chars().collect();
539 precontext = precontext[(precontext.len()
540 - min(self.patch_margin, precontext.len() as i32) as usize)..]
541 .to_vec();
542 let postcontext = if self.diff_text1(&mut bigpatch.diffs).chars().count() as i32
544 > self.patch_margin
545 {
546 let temp: Vec<char> = self.diff_text1(&mut bigpatch.diffs).chars().collect();
547 temp[..self.patch_margin as usize].iter().collect()
548 } else {
549 self.diff_text1(&mut bigpatch.diffs)
550 };
551 let postcontext_len = postcontext.chars().count() as i32;
552 if !postcontext.is_empty() {
553 patch.length1 += postcontext_len;
554 patch.length2 += postcontext_len;
555 if !patch.diffs.is_empty() && patch.diffs[patch.diffs.len() - 1].operation == 0
556 {
557 let len = patch.diffs.len();
558 patch.diffs[len - 1].text += postcontext.as_str();
559 } else {
560 patch.diffs.push(Diff::new(0, postcontext));
561 }
562 }
563 if !empty {
564 x += 1;
565 patches.insert(x as usize, patch);
566 }
567 }
568 x += 1;
569 }
570 }
571
572 pub fn patch_to_text(&mut self, patches: &mut Vec<Patch>) -> String {
580 let mut text: String = "".to_string();
581 for patches_item in patches {
582 text += (patches_item.to_string()).as_str();
583 }
584 text
585 }
586
587 pub fn patch_from_text(&mut self, textline: String) -> Vec<Patch> {
598 try_patch_from_text(&textline).unwrap_or_else(|e| panic!("{}", e))
599 }
600
601 pub fn patch1_from_text(&mut self, textline: String) -> Patch {
602 try_patch_from_text(&textline)
605 .unwrap_or_else(|e| panic!("{}", e))
606 .into_iter()
607 .next()
608 .unwrap_or_else(|| panic!("Invalid patch string: {}", textline))
609 }
610}
611
612fn diff_text1_chars(diffs: &[Diff]) -> Vec<char> {
615 let mut text = Vec::new();
616 for diff in diffs {
617 if diff.operation != 1 {
618 text.extend(diff.text.chars());
619 }
620 }
621 text
622}
623
624fn diff_text2_chars(diffs: &[Diff]) -> Vec<char> {
626 let mut text = Vec::new();
627 for diff in diffs {
628 if diff.operation != -1 {
629 text.extend(diff.text.chars());
630 }
631 }
632 text
633}
634
635#[derive(Debug)]
636pub(crate) struct PatchError(String);
637
638impl fmt::Display for PatchError {
639 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
640 write!(f, "{}", self.0)
641 }
642}
643
644fn parse_coords(part: &str) -> Result<(i32, i32), PatchError> {
649 let err = || PatchError(format!("Invalid patch coordinates: {}", part));
650 let num = |s: &str| {
651 if s.is_empty() || !s.bytes().all(|b| b.is_ascii_digit()) {
652 return Err(err());
653 }
654 s.parse::<i32>().map_err(|_| err())
655 };
656 let (start, length) = part.split_once(',').unwrap_or((part, ""));
657 match length {
658 "" => Ok((num(start)? - 1, 1)),
659 "0" => Ok((num(start)?, 0)),
660 _ => Ok((num(start)? - 1, num(length)?)),
661 }
662}
663
664fn parse_header(line: &str) -> Result<(i32, i32, i32, i32), PatchError> {
665 let err = || PatchError(format!("Invalid patch string: {}", line));
666 let coords = line
667 .strip_prefix("@@ -")
668 .and_then(|r| r.strip_suffix(" @@"))
669 .ok_or_else(err)?;
670 let (c1, c2) = coords.split_once(" +").ok_or_else(err)?;
671 let (start1, length1) = parse_coords(c1)?;
672 let (start2, length2) = parse_coords(c2)?;
673 Ok((start1, length1, start2, length2))
674}
675
676pub(crate) fn try_patch_from_text(text: &str) -> Result<Vec<Patch>, PatchError> {
677 let mut patches: Vec<Patch> = vec![];
678 let lines: Vec<&str> = text.split('\n').collect();
679 let mut i = 0;
680 while i < lines.len() {
681 if lines[i].is_empty() {
682 i += 1;
683 continue;
684 }
685 let (start1, length1, start2, length2) = parse_header(lines[i])?;
686 let mut patch = Patch::new(vec![], start1, start2, length1, length2);
687 i += 1;
688 while i < lines.len() {
689 let line = lines[i];
690 if line.starts_with('@') {
691 break;
693 }
694 if line.is_empty() {
695 i += 1;
697 continue;
698 }
699 let mut line_chars = line.chars();
700 let sign = line_chars.next().unwrap();
701 let body = line_chars.as_str();
702 let decoded = percent_decode(body.as_bytes())
703 .decode_utf8()
704 .map_err(|_| PatchError(format!("Illegal escape in patch_from_text: {}", body)))?
705 .to_string();
706 match sign {
707 '+' => patch.diffs.push(Diff::new(1, decoded)),
708 '-' => patch.diffs.push(Diff::new(-1, decoded)),
709 ' ' => patch.diffs.push(Diff::new(0, decoded)),
710 _ => return Err(PatchError(format!("Invalid patch mode: {}", line))),
711 }
712 i += 1;
713 }
714 patches.push(patch);
715 }
716 Ok(patches)
717}
718
719impl fmt::Display for Patch {
723 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
724 let coords = |start: i32, length: i32| match length {
725 0 => format!("{},0", start),
726 1 => format!("{}", start + 1),
727 _ => format!("{},{}", start + 1, length),
728 };
729 writeln!(
730 f,
731 "@@ -{} +{} @@",
732 coords(self.start1, self.length1),
733 coords(self.start2, self.length2)
734 )?;
735 for diff in &self.diffs {
736 let sign = match diff.operation {
737 0 => ' ',
738 -1 => '-',
739 _ => '+',
740 };
741 writeln!(f, "{}{}", sign, encode_uri(&diff.text))?;
742 }
743 Ok(())
744 }
745}
746
747#[allow(clippy::ptr_arg)]
750impl Dmp {
751 pub fn split_by_char(&mut self, text: &str, ch: char) -> Vec<String> {
760 let temp: Vec<&str> = text.split(ch).collect();
761 let mut temp1: Vec<String> = vec![];
762 for temp_item in &temp {
763 temp1.push(temp_item.to_string());
764 }
765 temp1
766 }
767
768 pub fn split_by_chars(&mut self, text: &str) -> Vec<String> {
776 let temp: Vec<&str> = text.split("@@ ").collect();
777 let mut temp1: Vec<String> = vec![];
778 for temp_item in &temp {
779 temp1.push(temp_item.to_string());
780 }
781 temp1
782 }
783}