Convert an LCS to diff operations.
(lcs: &[LcsElement], old_len: usize, new_len: usize)
| 114 | |
| 115 | /// Convert an LCS to diff operations. |
| 116 | fn lcs_to_diff(lcs: &[LcsElement], old_len: usize, new_len: usize) -> DiffResult { |
| 117 | let mut result = DiffResult::new(); |
| 118 | let mut old_pos = 0; |
| 119 | let mut new_pos = 0; |
| 120 | |
| 121 | for elem in lcs { |
| 122 | // Handle deletions and insertions before this match |
| 123 | let del_count = elem.old_idx - old_pos; |
| 124 | let ins_count = elem.new_idx - new_pos; |
| 125 | |
| 126 | if del_count > 0 && ins_count > 0 { |
| 127 | // Replace operation |
| 128 | result.push(DiffOp::replace(old_pos, del_count, new_pos, ins_count)); |
| 129 | } else if del_count > 0 { |
| 130 | result.push(DiffOp::delete(old_pos, new_pos, del_count)); |
| 131 | } else if ins_count > 0 { |
| 132 | result.push(DiffOp::insert(old_pos, new_pos, ins_count)); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | // Recalculate to properly merge consecutive equals |
| 137 | result = DiffResult::new(); |
| 138 | old_pos = 0; |
| 139 | new_pos = 0; |
| 140 | let mut lcs_idx = 0; |
| 141 | |
| 142 | while old_pos < old_len || new_pos < new_len { |
| 143 | // Check if current position is part of LCS |
| 144 | if lcs_idx < lcs.len() && lcs[lcs_idx].old_idx == old_pos && lcs[lcs_idx].new_idx == new_pos |
| 145 | { |
| 146 | // Count consecutive matches |
| 147 | let start_old = old_pos; |
| 148 | let start_new = new_pos; |
| 149 | |
| 150 | while lcs_idx < lcs.len() |
| 151 | && lcs[lcs_idx].old_idx == old_pos |
| 152 | && lcs[lcs_idx].new_idx == new_pos |
| 153 | { |
| 154 | old_pos += 1; |
| 155 | new_pos += 1; |
| 156 | lcs_idx += 1; |
| 157 | } |
| 158 | |
| 159 | let match_len = old_pos - start_old; |
| 160 | result.push(DiffOp::equal(start_old, start_new, match_len)); |
| 161 | } else { |
| 162 | // Find the next LCS element or end |
| 163 | let next_old = if lcs_idx < lcs.len() { |
| 164 | lcs[lcs_idx].old_idx |
| 165 | } else { |
| 166 | old_len |
| 167 | }; |
| 168 | let next_new = if lcs_idx < lcs.len() { |
| 169 | lcs[lcs_idx].new_idx |
| 170 | } else { |
| 171 | new_len |
| 172 | }; |
| 173 |