Combine adjacent edits in buffer's diff

This commit is contained in:
Max Brunsfeld 2023-11-16 14:44:32 -08:00
parent f9650b3111
commit b2451d9dd6

View file

@ -1122,26 +1122,59 @@ impl Buffer {
let old_text = old_text.to_string(); let old_text = old_text.to_string();
let line_ending = LineEnding::detect(&new_text); let line_ending = LineEnding::detect(&new_text);
LineEnding::normalize(&mut new_text); LineEnding::normalize(&mut new_text);
let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str()); let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str());
let mut edits = Vec::new();
let mut offset = 0;
let empty: Arc<str> = "".into(); let empty: Arc<str> = "".into();
for change in diff.iter_all_changes() {
let value = change.value(); let mut edits = Vec::new();
let end_offset = offset + value.len(); let mut old_offset = 0;
match change.tag() { let mut new_offset = 0;
ChangeTag::Equal => { let mut last_edit: Option<(Range<usize>, Range<usize>)> = None;
offset = end_offset; for change in diff.iter_all_changes().map(Some).chain([None]) {
if let Some(change) = &change {
let len = change.value().len();
match change.tag() {
ChangeTag::Equal => {
old_offset += len;
new_offset += len;
}
ChangeTag::Delete => {
let old_end_offset = old_offset + len;
if let Some((last_old_range, _)) = &mut last_edit {
last_old_range.end = old_end_offset;
} else {
last_edit =
Some((old_offset..old_end_offset, new_offset..new_offset));
}
old_offset = old_end_offset;
}
ChangeTag::Insert => {
let new_end_offset = new_offset + len;
if let Some((_, last_new_range)) = &mut last_edit {
last_new_range.end = new_end_offset;
} else {
last_edit =
Some((old_offset..old_offset, new_offset..new_end_offset));
}
new_offset = new_end_offset;
}
} }
ChangeTag::Delete => { }
edits.push((offset..end_offset, empty.clone()));
offset = end_offset; if let Some((old_range, new_range)) = &last_edit {
} if old_offset > old_range.end || new_offset > new_range.end || change.is_none()
ChangeTag::Insert => { {
edits.push((offset..offset, value.into())); let text = if new_range.is_empty() {
empty.clone()
} else {
new_text[new_range.clone()].into()
};
edits.push((old_range.clone(), text));
last_edit.take();
} }
} }
} }
Diff { Diff {
base_version, base_version,
line_ending, line_ending,