1 use super::diff::*;
2 use super::vertex_buffer::{ConflictMarker, Diff};
3 use super::{bytes_len, bytes_pos, Line};
4 use crate::change::{Atom, Hunk, LocalByte, NewVertex};
5 use crate::pristine::{ChangeId, ChangePosition, EdgeFlags, Inode, Position};
6 use crate::record::Recorded;
7 use crate::text_encoding::Encoding;
8 use crate::{HashMap, HashSet};
9
10 pub struct ConflictContexts {
11 pub up: HashMap<usize, ChangePosition>,
12 pub side_ends: HashMap<usize, Vec<ChangePosition>>,
13 pub active: HashSet<usize>,
14 pub reorderings: HashMap<usize, ChangePosition>,
15 }
16
17 impl ConflictContexts {
new() -> Self18 pub fn new() -> Self {
19 ConflictContexts {
20 side_ends: HashMap::default(),
21 up: HashMap::default(),
22 active: HashSet::default(),
23 reorderings: HashMap::default(),
24 }
25 }
26 }
27
28 impl Recorded {
replace( &mut self, diff: &Diff, conflict_contexts: &mut ConflictContexts, lines_a: &[Line], lines_b: &[Line], inode: Inode, dd: &D, r: usize, encoding: &Option<Encoding>, )29 pub(super) fn replace(
30 &mut self,
31 diff: &Diff,
32 conflict_contexts: &mut ConflictContexts,
33 lines_a: &[Line],
34 lines_b: &[Line],
35 inode: Inode,
36 dd: &D,
37 r: usize,
38 encoding: &Option<Encoding>,
39 ) {
40 let old = dd[r].old;
41 let old_len = dd[r].old_len;
42 let from_new = dd[r].new;
43 let len = dd[r].new_len;
44 let up_context = get_up_context(diff, conflict_contexts, lines_a, old);
45
46 let start = self.contents.lock().len();
47
48 let down_context = get_down_context(
49 diff,
50 conflict_contexts,
51 dd,
52 lines_a,
53 lines_b,
54 old,
55 old_len,
56 from_new,
57 len,
58 start,
59 );
60
61 debug!("old {:?}..{:?}", old, old + old_len);
62 trace!("old {:?}", &lines_a[old..(old + old_len)]);
63 debug!("new {:?}..{:?}", from_new, from_new + len);
64 trace!("new {:?}", &lines_b[from_new..(from_new + len)]);
65
66 let mut contents = self.contents.lock();
67 for &line in &lines_b[from_new..(from_new + len)] {
68 contents.extend(line.l);
69 }
70 let end = contents.len();
71 if start >= end {
72 return;
73 }
74 contents.push(0);
75 std::mem::drop(contents);
76
77 let change = NewVertex {
78 up_context,
79 down_context,
80 flag: EdgeFlags::BLOCK,
81 start: ChangePosition(start.into()),
82 end: ChangePosition(end.into()),
83 inode: diff.inode,
84 };
85 if old_len > 0 {
86 match self.actions.pop() {
87 Some(Hunk::Edit {
88 change: c, local, ..
89 }) => {
90 if local.line == from_new + 1 {
91 self.actions.push(Hunk::Replacement {
92 change: c,
93 local,
94 replacement: Atom::NewVertex(change),
95 encoding: encoding.clone(),
96 });
97 return;
98 } else {
99 self.actions.push(Hunk::Edit {
100 change: c,
101 local,
102 encoding: encoding.clone(),
103 })
104 }
105 }
106 Some(c) => self.actions.push(c),
107 None => {}
108 }
109 }
110 self.actions.push(Hunk::Edit {
111 local: LocalByte {
112 line: from_new + 1,
113 path: diff.path.clone(),
114 inode,
115 byte: Some(bytes_pos(lines_b, from_new)),
116 },
117 change: Atom::NewVertex(change),
118 encoding: encoding.clone(),
119 });
120 }
121 }
122
get_up_context( diff: &Diff, conflict_contexts: &mut ConflictContexts, lines_a: &[Line], old: usize, ) -> Vec<Position<Option<ChangeId>>>123 pub(super) fn get_up_context(
124 diff: &Diff,
125 conflict_contexts: &mut ConflictContexts,
126 lines_a: &[Line],
127 old: usize,
128 ) -> Vec<Position<Option<ChangeId>>> {
129 if let Some(&pos) = conflict_contexts.reorderings.get(&old) {
130 return vec![Position { change: None, pos }];
131 }
132 let old_bytes = if old == 0 {
133 return vec![diff.pos_a[0].vertex.end_pos().to_option()];
134 } else if old < lines_a.len() {
135 bytes_pos(lines_a, old)
136 } else {
137 diff.contents_a.len()
138 };
139 debug!("old_bytes {:?}", old_bytes);
140 let mut up_context_idx = diff.last_vertex_containing(old_bytes - 1);
141 let mut seen_conflict_markers = false;
142 loop {
143 debug!("up_context_idx = {:?}", up_context_idx);
144 debug!("{:?}", diff.marker.get(&diff.pos_a[up_context_idx].pos));
145 match diff.marker.get(&diff.pos_a[up_context_idx].pos) {
146 None if seen_conflict_markers => {
147 return vec![diff.pos_a[up_context_idx].vertex.end_pos().to_option()]
148 }
149 None => {
150 let change = diff.pos_a[up_context_idx].vertex.change;
151 let pos = diff.pos_a[up_context_idx].vertex.start;
152 let offset = old_bytes - diff.pos_a[up_context_idx].pos;
153 debug!("offset {:?} {:?}", pos.0, offset);
154 return vec![Position {
155 change: Some(change),
156 pos: ChangePosition(pos.0 + offset),
157 }];
158 }
159 Some(ConflictMarker::End) => {
160 debug!("get_up_context_conflict");
161 return get_up_context_conflict(diff, conflict_contexts, up_context_idx);
162 }
163 _ => {
164 let conflict = diff.pos_a[up_context_idx].conflict;
165 debug!(
166 "conflict = {:?} {:?}",
167 conflict, diff.conflict_ends[conflict]
168 );
169 if let Some(&pos) = conflict_contexts.up.get(&conflict) {
170 return vec![Position { change: None, pos }];
171 }
172 seen_conflict_markers = true;
173 if diff.conflict_ends[conflict].start > 0 {
174 up_context_idx = diff.conflict_ends[conflict].start - 1
175 } else {
176 return vec![diff.pos_a[0].vertex.end_pos().to_option()];
177 }
178 }
179 }
180 }
181 }
get_up_context_conflict( diff: &Diff, conflict_contexts: &mut ConflictContexts, mut up_context_idx: usize, ) -> Vec<Position<Option<ChangeId>>>182 fn get_up_context_conflict(
183 diff: &Diff,
184 conflict_contexts: &mut ConflictContexts,
185 mut up_context_idx: usize,
186 ) -> Vec<Position<Option<ChangeId>>> {
187 let conflict = diff.pos_a[up_context_idx].conflict;
188 let conflict_start = diff.conflict_ends[conflict].start;
189 let mut up_context = Vec::new();
190 if let Some(ref up) = conflict_contexts.side_ends.get(&up_context_idx) {
191 up_context.extend(up.iter().map(|&pos| Position { change: None, pos }));
192 }
193 let mut on = true;
194 conflict_contexts.active.clear();
195 conflict_contexts.active.insert(conflict);
196 while up_context_idx > conflict_start {
197 match diff.marker.get(&diff.pos_a[up_context_idx].pos) {
198 None if on => {
199 let change = diff.pos_a[up_context_idx].vertex.change;
200 let pos = diff.pos_a[up_context_idx].vertex.end;
201 up_context.push(Position {
202 change: Some(change),
203 pos,
204 });
205 on = false
206 }
207 Some(ConflictMarker::End) if on => {
208 conflict_contexts
209 .active
210 .insert(diff.pos_a[up_context_idx].conflict);
211 }
212 Some(ConflictMarker::Next)
213 if conflict_contexts
214 .active
215 .contains(&diff.pos_a[up_context_idx].conflict) =>
216 {
217 on = true
218 }
219 _ => {}
220 }
221 up_context_idx -= 1;
222 }
223 assert!(!up_context.is_empty());
224 up_context
225 }
get_down_context( diff: &Diff, conflict_contexts: &mut ConflictContexts, dd: &D, lines_a: &[Line], lines_b: &[Line], old: usize, old_len: usize, from_new: usize, new_len: usize, contents_len: usize, ) -> Vec<Position<Option<ChangeId>>>226 pub(super) fn get_down_context(
227 diff: &Diff,
228 conflict_contexts: &mut ConflictContexts,
229 dd: &D,
230 lines_a: &[Line],
231 lines_b: &[Line],
232 old: usize,
233 old_len: usize,
234 from_new: usize,
235 new_len: usize,
236 contents_len: usize,
237 ) -> Vec<Position<Option<ChangeId>>> {
238 if old + old_len >= lines_a.len() {
239 return Vec::new();
240 }
241 let mut down_context_idx = 1;
242 let mut pos_bytes = if old + old_len == 0 {
243 0
244 } else {
245 let pos_bytes = bytes_pos(lines_a, old) + bytes_len(lines_a, old, old_len);
246 down_context_idx = diff.first_vertex_containing(pos_bytes);
247 pos_bytes
248 };
249 while down_context_idx < diff.pos_a.len() {
250 match diff.marker.get(&(diff.pos_a[down_context_idx].pos)) {
251 Some(ConflictMarker::Begin) => {
252 return get_down_context_conflict(
253 diff,
254 dd,
255 conflict_contexts,
256 lines_a,
257 lines_b,
258 from_new,
259 new_len,
260 down_context_idx,
261 )
262 }
263 Some(marker) => {
264 if let ConflictMarker::Next = marker {
265 let conflict = diff.pos_a[down_context_idx].conflict;
266 down_context_idx = diff.conflict_ends[conflict].end;
267 }
268 let e = conflict_contexts
269 .side_ends
270 .entry(down_context_idx)
271 .or_default();
272 let b_len_bytes = bytes_len(lines_b, from_new, new_len);
273 e.push(ChangePosition((contents_len + b_len_bytes).into()));
274 down_context_idx += 1
275 }
276 None => {
277 pos_bytes = pos_bytes.max(diff.pos_a[down_context_idx].pos);
278 let next_vertex_pos = if down_context_idx + 1 >= diff.pos_a.len() {
279 diff.contents_a.len()
280 } else {
281 diff.pos_a[down_context_idx + 1].pos
282 };
283 while pos_bytes < next_vertex_pos {
284 match dd.is_deleted(lines_a, pos_bytes) {
285 Some(Deleted { replaced: true, .. }) => return Vec::new(),
286 Some(Deleted {
287 replaced: false,
288 next,
289 }) => pos_bytes = next,
290 None => {
291 return vec![diff.position(down_context_idx, pos_bytes).to_option()]
292 }
293 }
294 }
295 down_context_idx += 1;
296 }
297 }
298 }
299 Vec::new()
300 }
get_down_context_conflict( diff: &Diff, dd: &D, conflict_contexts: &mut ConflictContexts, lines_a: &[Line], lines_b: &[Line], from_new: usize, new_len: usize, mut down_context_idx: usize, ) -> Vec<Position<Option<ChangeId>>>301 fn get_down_context_conflict(
302 diff: &Diff,
303 dd: &D,
304 conflict_contexts: &mut ConflictContexts,
305 lines_a: &[Line],
306 lines_b: &[Line],
307 from_new: usize,
308 new_len: usize,
309 mut down_context_idx: usize,
310 ) -> Vec<Position<Option<ChangeId>>> {
311 let conflict = diff.pos_a[down_context_idx].conflict;
312 let len_bytes = bytes_len(lines_b, from_new, new_len);
313 conflict_contexts
314 .up
315 .insert(conflict, ChangePosition(len_bytes.into()));
316 conflict_contexts.active.clear();
317 conflict_contexts.active.insert(conflict);
318 assert!(!diff.pos_a.is_empty());
319 let conflict_end = diff.conflict_ends[conflict].end.min(diff.pos_a.len() - 1);
320 let mut down_context = Vec::new();
321 let mut on = true;
322 let mut pos = diff.pos_a[down_context_idx].pos;
323 loop {
324 match diff.marker.get(&pos) {
325 None if on => match dd.is_deleted(lines_a, pos) {
326 Some(Deleted { replaced: true, .. }) => on = false,
327 Some(Deleted { next, .. }) => {
328 pos = next;
329 let next_pos = if down_context_idx + 1 < diff.pos_a.len() {
330 diff.pos_a[down_context_idx + 1].pos
331 } else {
332 diff.contents_a.len()
333 };
334 if pos < next_pos {
335 continue;
336 }
337 }
338 None => {
339 down_context.push(diff.position(down_context_idx, pos).to_option());
340 on = false;
341 }
342 },
343 Some(ConflictMarker::Begin) if on => {
344 conflict_contexts
345 .active
346 .insert(diff.pos_a[down_context_idx].conflict);
347 }
348 Some(ConflictMarker::Next)
349 if conflict_contexts
350 .active
351 .contains(&diff.pos_a[down_context_idx].conflict) =>
352 {
353 on = true
354 }
355 _ => {}
356 }
357 down_context_idx += 1;
358 if down_context_idx > conflict_end {
359 break;
360 } else {
361 pos = diff.pos_a[down_context_idx].pos
362 }
363 }
364 down_context
365 }
366