Combine adjacent edits in buffer's diff
This commit is contained in:
parent
f9650b3111
commit
b2451d9dd6
1 changed files with 47 additions and 14 deletions
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue