diff --git a/helix-core/src/diff.rs b/helix-core/src/diff.rs index 9c1fc999..a83db333 100644 --- a/helix-core/src/diff.rs +++ b/helix-core/src/diff.rs @@ -1,6 +1,4 @@ -use ropey::Rope; - -use crate::{Change, Transaction}; +use crate::{Rope, Transaction}; /// Compares `old` and `new` to generate a [`Transaction`] describing /// the steps required to get from `old` to `new`. @@ -25,34 +23,34 @@ pub fn compare_ropes(old: &Rope, new: &Rope) -> Transaction { // The current position of the change needs to be tracked to // construct the `Change`s. let mut pos = 0; - let changes: Vec = diff - .ops() - .iter() - .map(|op| op.as_tag_tuple()) - .filter_map(|(tag, old_range, new_range)| { - // `old_pos..pos` is equivalent to `start..end` for where - // the change should be applied. - let old_pos = pos; - pos += old_range.end - old_range.start; + Transaction::change( + old, + diff.ops() + .iter() + .map(|op| op.as_tag_tuple()) + .filter_map(|(tag, old_range, new_range)| { + // `old_pos..pos` is equivalent to `start..end` for where + // the change should be applied. + let old_pos = pos; + pos += old_range.end - old_range.start; - match tag { - // Semantically, inserts and replacements are the same thing. - similar::DiffTag::Insert | similar::DiffTag::Replace => { - // This is the text from the `new` rope that should be - // inserted into `old`. - let text: &str = { - let start = new.char_to_byte(new_range.start); - let end = new.char_to_byte(new_range.end); - &new_converted[start..end] - }; - Some((old_pos, pos, Some(text.into()))) + match tag { + // Semantically, inserts and replacements are the same thing. + similar::DiffTag::Insert | similar::DiffTag::Replace => { + // This is the text from the `new` rope that should be + // inserted into `old`. + let text: &str = { + let start = new.char_to_byte(new_range.start); + let end = new.char_to_byte(new_range.end); + &new_converted[start..end] + }; + Some((old_pos, pos, Some(text.into()))) + } + similar::DiffTag::Delete => Some((old_pos, pos, None)), + similar::DiffTag::Equal => None, } - similar::DiffTag::Delete => Some((old_pos, pos, None)), - similar::DiffTag::Equal => None, - } - }) - .collect(); - Transaction::change(old, changes.into_iter()) + }), + ) } #[cfg(test)] diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index 048839b3..e20e550f 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -473,11 +473,13 @@ impl Transaction { /// Generate a transaction from a set of changes. pub fn change(doc: &Rope, changes: I) -> Self where - I: IntoIterator + ExactSizeIterator, + I: IntoIterator + Iterator, { let len = doc.len_chars(); - let mut changeset = ChangeSet::with_capacity(2 * changes.len() + 1); // rough estimate + let (lower, upper) = changes.size_hint(); + let size = upper.unwrap_or(lower); + let mut changeset = ChangeSet::with_capacity(2 * size + 1); // rough estimate // TODO: verify ranges are ordered and not overlapping or change will panic.