Rewrite diff ops to convert positional shifts into Replace operations. When a line appears at the same content but a different position, and there are insertions that "pushed" it down, this is better represented as a modification of the original line plus an insertion of the new copy.
(
result: DiffResult,
old: &[Line<'a>],
new: &[Line<'a>],
)
| 257 | /// there are insertions that "pushed" it down, this is better represented |
| 258 | /// as a modification of the original line plus an insertion of the new copy. |
| 259 | fn rewrite_positional_shifts<'a>( |
| 260 | result: DiffResult, |
| 261 | old: &[Line<'a>], |
| 262 | new: &[Line<'a>], |
| 263 | ) -> DiffResult { |
| 264 | let ops = result.ops(); |
| 265 | if ops.len() < 2 { |
| 266 | return result; |
| 267 | } |
| 268 | |
| 269 | let mut new_ops: Vec<DiffOp> = Vec::with_capacity(ops.len()); |
| 270 | let mut i = 0; |
| 271 | |
| 272 | while i < ops.len() { |
| 273 | // Look for pattern: Insert then Equal where the Equal's old_pos |
| 274 | // matches where the Insert landed (the line "shifted down") |
| 275 | if i + 1 < ops.len() { |
| 276 | if let ( |
| 277 | DiffOp::Insert { |
| 278 | old_pos: ins_old_pos, |
| 279 | new_pos: ins_new_pos, |
| 280 | len: ins_len, |
| 281 | }, |
| 282 | DiffOp::Equal { |
| 283 | old_pos: eq_old_pos, |
| 284 | new_pos: eq_new_pos, |
| 285 | len: eq_len, |
| 286 | }, |
| 287 | ) = (&ops[i], &ops[i + 1]) |
| 288 | { |
| 289 | // The Equal starts at the same old position as the Insert, |
| 290 | // meaning the Insert "pushed" the Equal line to a new position. |
| 291 | // AND the Equal maps to a different new position than old position |
| 292 | // (the line shifted). |
| 293 | if *eq_old_pos == *ins_old_pos && *eq_new_pos > *eq_old_pos { |
| 294 | // The Insert occupies the old position, and the Equal |
| 295 | // line was "pushed down". This MIGHT be a modification |
| 296 | // (user changed the line and a copy of the old content |
| 297 | // ended up below it). We only rewrite when the inserted |
| 298 | // content is SIMILAR to the old line — sharing tokens |
| 299 | // indicates a word-level edit (e.g. "line two" → "line three"). |
| 300 | // If the content is completely different, it's a genuine |
| 301 | // insertion and we leave it alone. |
| 302 | let overlap = (*ins_len).min(*eq_len); |
| 303 | |
| 304 | if overlap > 0 { |
| 305 | let mut rewrote = false; |
| 306 | |
| 307 | for j in 0..overlap { |
| 308 | let o_idx = eq_old_pos + j; |
| 309 | let n_idx = ins_new_pos + j; |
| 310 | let eq_n_idx = eq_new_pos + j; |
| 311 | |
| 312 | if o_idx < old.len() && n_idx < new.len() && old[o_idx] != new[n_idx] { |
| 313 | // Check similarity: the inserted line should share |
| 314 | // significant content with the old line to qualify |
| 315 | // as a modification. Compare tokens (words). |
| 316 | let old_content = old[o_idx].content_without_newline(); |
no test coverage detected