Skip to main content

java_diff_utils_rs/text/delta_merge/
delta_merge_utils.rs

1//! Utility functions for merging inline deltas.
2
3use crate::patch::chunk::Chunk;
4use crate::patch::delta::Delta;
5use crate::patch::delta_type::DeltaType;
6use crate::text::delta_merge::inline_delta_merge_info::InlineDeltaMergeInfo;
7
8/// Utility features for merging inline deltas.
9pub struct DeltaMergeUtils;
10
11impl DeltaMergeUtils {
12    /// Merges adjacent or close inline deltas if the intervening unchanged lines
13    /// satisfy the provided `replace_equality` predicate.
14    pub fn merge_inline_deltas<F>(
15        delta_merge_info: &InlineDeltaMergeInfo<String>,
16        replace_equality: F,
17    ) -> Vec<Delta<String>>
18    where
19        F: Fn(&[String]) -> bool,
20    {
21        let original_deltas = delta_merge_info.deltas();
22        if original_deltas.len() < 2 {
23            return original_deltas.to_vec();
24        }
25
26        let mut new_deltas: Vec<Delta<String>> = Vec::new();
27        new_deltas.push(original_deltas[0].clone());
28
29        for current_delta in original_deltas.iter().skip(1) {
30            let previous_delta = new_deltas.last().unwrap();
31
32            let prev_source_pos = previous_delta.source().position();
33            let prev_source_len = previous_delta.source().len();
34            let start_idx = prev_source_pos + prev_source_len;
35            let end_idx = current_delta.source().position();
36
37            let equalities =
38                if start_idx <= end_idx && end_idx <= delta_merge_info.orig_list().len() {
39                    &delta_merge_info.orig_list()[start_idx..end_idx]
40                } else {
41                    &[]
42                };
43
44            if replace_equality(equalities) {
45                // Merge previous delta, equalities, and current delta into a single Change delta
46                let mut all_source_lines = Vec::new();
47                all_source_lines.extend(previous_delta.source().lines().iter().cloned());
48                all_source_lines.extend(equalities.iter().cloned());
49                all_source_lines.extend(current_delta.source().lines().iter().cloned());
50
51                let mut all_target_lines = Vec::new();
52                all_target_lines.extend(previous_delta.target().lines().iter().cloned());
53                all_target_lines.extend(equalities.iter().cloned());
54                all_target_lines.extend(current_delta.target().lines().iter().cloned());
55
56                let replacement_source =
57                    Chunk::new(previous_delta.source().position(), all_source_lines, None);
58                let replacement_target =
59                    Chunk::new(previous_delta.target().position(), all_target_lines, None);
60
61                let replacement =
62                    Delta::new(DeltaType::Change, replacement_source, replacement_target);
63
64                new_deltas.pop();
65                new_deltas.push(replacement);
66            } else {
67                new_deltas.push(current_delta.clone());
68            }
69        }
70
71        new_deltas
72    }
73}