imara_diff/
postprocess.rs1use crate::intern::{InternedInput, Token};
2use crate::slider_heuristic::SliderHeuristic;
3use crate::util::{find_hunk_end, find_hunk_start};
4use crate::{Diff, Hunk};
5
6impl Diff {
7 pub fn postprocess_with(
8 &mut self,
9 before: &[Token],
10 after: &[Token],
11 mut heuristic: impl SliderHeuristic,
12 ) {
13 Postprocessor {
14 added: &mut self.added,
15 removed: &mut self.removed,
16 tokens: after,
17 hunk: Hunk {
18 before: 0..0,
19 after: 0..0,
20 },
21 heuristic: &mut heuristic,
22 }
23 .run();
24 Postprocessor {
25 added: &mut self.removed,
26 removed: &mut self.added,
27 tokens: before,
28 hunk: Hunk {
29 before: 0..0,
30 after: 0..0,
31 },
32 heuristic: &mut heuristic,
33 }
34 .run()
35 }
36
37 pub fn postprocess_with_heuristic<T>(
38 &mut self,
39 input: &InternedInput<T>,
40 heuristic: impl SliderHeuristic,
41 ) {
42 self.postprocess_with(&input.before, &input.after, heuristic);
43 }
44}
45
46struct Postprocessor<'a, H> {
47 added: &'a mut [bool],
48 removed: &'a [bool],
49 tokens: &'a [Token],
50 hunk: Hunk,
52 heuristic: &'a mut H,
53}
54
55impl<H: SliderHeuristic> Postprocessor<'_, H> {
56 fn run(mut self) {
57 loop {
58 if !self.hunk.next_hunk(self.removed, self.added) {
60 break;
61 }
62
63 let mut earliest_end;
64 let mut is_modification;
65 loop {
66 while self.slide_up() {}
69 earliest_end = self.hunk.after.end;
70 is_modification = self.hunk.before.start != self.hunk.before.end;
71
72 let hunk_size_unexpanded = self.hunk.after.len();
73 while self.slide_down() {
76 is_modification |= self.hunk.before.start != self.hunk.before.end;
77 }
78 if hunk_size_unexpanded == self.hunk.after.len() {
81 break;
82 }
83 }
84
85 if self.hunk.after.end == earliest_end {
86 continue;
87 }
88 if is_modification {
89 while self.hunk.before.start == self.hunk.before.end {
93 let success = self.slide_up();
94 debug_assert!(success);
95 }
96 } else {
97 let slider_end = self.heuristic.best_slider_end(
98 self.tokens,
99 self.hunk.after.clone(),
100 earliest_end,
101 );
102 for _ in slider_end..self.hunk.after.end {
103 let success = self.slide_up();
104 debug_assert!(success);
105 }
106 }
107 }
108 }
109
110 fn slide_down(&mut self) -> bool {
112 let Some(&next_token) = self.tokens.get(self.hunk.after.end as usize) else {
113 return false;
114 };
115 if self.tokens[self.hunk.after.start as usize] != next_token {
116 return false;
117 }
118 self.added[self.hunk.after.start as usize] = false;
119 self.added[self.hunk.after.end as usize] = true;
120 self.hunk.after.start += 1;
121 self.hunk.after.end = find_hunk_end(self.added, self.hunk.after.end);
122 self.hunk.before.start = self.hunk.before.end + 1;
124 self.hunk.before.end = find_hunk_end(self.removed, self.hunk.before.start);
125 true
126 }
127
128 fn slide_up(&mut self) -> bool {
130 if self.hunk.after.start == 0 {
131 return false;
132 }
133 if self.tokens[self.hunk.after.start as usize - 1]
134 != self.tokens[self.hunk.after.end as usize - 1]
135 {
136 return false;
137 }
138 self.added[self.hunk.after.start as usize - 1] = true;
139 self.added[self.hunk.after.end as usize - 1] = false;
140 self.hunk.after.end -= 1;
141 self.hunk.after.start = find_hunk_start(self.added, self.hunk.after.start - 1);
142 self.hunk.before.end = self.hunk.before.start - 1;
144 self.hunk.before.start = find_hunk_start(self.removed, self.hunk.before.start - 1);
145 true
146 }
147}