diff --git a/crates/editor/src/display_map/patch.rs b/crates/editor/src/display_map/patch.rs index 6d67be629c..835c9f4c5c 100644 --- a/crates/editor/src/display_map/patch.rs +++ b/crates/editor/src/display_map/patch.rs @@ -1,12 +1,16 @@ -use std::{cmp, iter::Peekable, mem, ops::Range}; +use std::{cmp, mem, slice}; type Edit = buffer::Edit; #[derive(Default, Debug, PartialEq, Eq)] -struct Patch(Vec); +pub struct Patch(Vec); impl Patch { - fn compose(&self, other: &Self) -> Self { + pub unsafe fn new_unchecked(edits: Vec) -> Self { + Self(edits) + } + + pub fn compose(&self, other: &Self) -> Self { let mut old_edits_iter = self.0.iter().cloned().peekable(); let mut new_edits_iter = other.0.iter().cloned().peekable(); let mut composed = Patch(Vec::new()); @@ -61,7 +65,6 @@ impl Patch { old_start = old_end; new_start = new_end; old_edits_iter.next(); - continue; } else if new_edit.old.end < old_edit.new.start { let catchup = new_edit.new.start - new_start; old_start += catchup; @@ -114,10 +117,8 @@ impl Patch { } if old_edit.new.end > new_edit.old.end { - let old_len = - cmp::min(old_edit.old.len() as u32, new_edit.old.len() as u32); - - let old_end = old_start + old_len; + let old_end = old_start + + cmp::min(old_edit.old.len() as u32, new_edit.old.len() as u32); let new_end = new_start + new_edit.new.len() as u32; composed.push(Edit { old: old_start..old_end, @@ -130,11 +131,9 @@ impl Patch { new_start = new_end; new_edits_iter.next(); } else { - let new_len = - cmp::min(old_edit.new.len() as u32, new_edit.new.len() as u32); - let old_end = old_start + old_edit.old.len() as u32; - let new_end = new_start + new_len; + let new_end = new_start + + cmp::min(old_edit.new.len() as u32, new_edit.new.len() as u32); composed.push(Edit { old: old_start..old_end, new: new_start..new_end, @@ -154,6 +153,17 @@ impl Patch { composed } + pub fn invert(&mut self) -> &mut Self { + for edit in &mut self.0 { + mem::swap(&mut edit.old, &mut edit.new); + } + self + } + + pub fn clear(&mut self) { + self.0.clear(); + } + fn push(&mut self, edit: Edit) { if edit.old.len() == 0 && edit.new.len() == 0 { return; @@ -172,6 +182,15 @@ impl Patch { } } +impl<'a> IntoIterator for &'a Patch { + type Item = &'a Edit; + type IntoIter = slice::Iter<'a, Edit>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + #[cfg(test)] mod tests { use super::*; @@ -399,13 +418,13 @@ mod tests { ); } - #[gpui::test(iterations = 100, seed = 1)] + #[gpui::test(iterations = 100)] fn test_random_patch_compositions(mut rng: StdRng) { let operations = env::var("OPERATIONS") .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(5); + .unwrap_or(20); - let initial_chars = (0..rng.gen_range(0..=10)) + let initial_chars = (0..rng.gen_range(0..=100)) .map(|_| rng.gen_range(b'a'..=b'z') as char) .collect::>(); println!("initial chars: {:?}", initial_chars);