diff --git a/zed/src/editor/display_map/tab_map.rs b/zed/src/editor/display_map/tab_map.rs index a265adef3f..c662796c81 100644 --- a/zed/src/editor/display_map/tab_map.rs +++ b/zed/src/editor/display_map/tab_map.rs @@ -261,6 +261,12 @@ impl OutputPoint { } } +impl From for OutputPoint { + fn from(point: super::Point) -> Self { + Self(point) + } +} + impl AddAssign for OutputPoint { fn add_assign(&mut self, rhs: Self) { self.0 += &rhs.0; diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index d2b55c4345..ae4f994e69 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -62,7 +62,6 @@ impl Sub for OutputPoint { pub struct Snapshot { transforms: SumTree, input: InputSnapshot, - version: usize, } impl Snapshot { @@ -78,11 +77,67 @@ impl Snapshot { }, &(), ), - version: input.version(), input, } } + fn interpolate(&mut self, new_snapshot: InputSnapshot, edits: &[InputEdit]) { + if edits.is_empty() { + return; + } + + let mut new_transforms; + { + let mut old_cursor = self.transforms.cursor::(); + let mut edits = edits.into_iter().peekable(); + new_transforms = + old_cursor.slice(&edits.peek().unwrap().old_lines.start, Bias::Right, &()); + + while let Some(edit) = edits.next() { + if edit.new_lines.start > InputPoint::from(new_transforms.summary().input.lines) { + let summary = new_snapshot.text_summary_for_range( + InputPoint::from(new_transforms.summary().input.lines) + ..edit.new_lines.start, + ); + new_transforms.push_or_extend(Transform::isomorphic(summary)); + } + + new_transforms.push_or_extend(Transform::isomorphic( + new_snapshot.text_summary_for_range(edit.new_lines.clone()), + )); + + old_cursor.seek_forward(&edit.old_lines.end, Bias::Right, &()); + if let Some(next_edit) = edits.peek() { + if next_edit.old_lines.start > old_cursor.seek_end(&()) { + if old_cursor.seek_end(&()) > edit.old_lines.end { + let summary = self.input.text_summary_for_range( + edit.old_lines.end..old_cursor.seek_end(&()), + ); + new_transforms.push_or_extend(Transform::isomorphic(summary)); + } + old_cursor.next(&()); + new_transforms.push_tree( + old_cursor.slice(&next_edit.old_lines.start, Bias::Right, &()), + &(), + ); + } + } else { + if old_cursor.seek_end(&()) > edit.old_lines.end { + let summary = self + .input + .text_summary_for_range(edit.old_lines.end..old_cursor.seek_end(&())); + new_transforms.push_or_extend(Transform::isomorphic(summary)); + } + old_cursor.next(&()); + new_transforms.push_tree(old_cursor.suffix(&()), &()); + } + } + } + + self.transforms = new_transforms; + self.input = new_snapshot; + } + pub fn chunks_at(&self, point: OutputPoint) -> Chunks { let mut transforms = self.transforms.cursor(); transforms.seek(&point, Bias::Right, &()); @@ -145,7 +200,6 @@ impl<'a> Iterator for Chunks<'a> { struct State { snapshot: Snapshot, - interpolated_version: usize, } #[derive(Clone)] @@ -179,10 +233,7 @@ impl WrapMap { }; Self { - state: Mutex::new(State { - interpolated_version: snapshot.version, - snapshot, - }), + state: Mutex::new(State { snapshot }), edits_tx, background_snapshots: background_snapshots_rx, _background_task: background_task, @@ -190,7 +241,10 @@ impl WrapMap { } pub fn sync(&self, input: InputSnapshot, edits: Vec) -> Snapshot { - // TODO: interpolate + self.state + .lock() + .snapshot + .interpolate(input.clone(), &edits); self.edits_tx.try_send((input, edits)).unwrap(); self.state.lock().snapshot.clone() } @@ -378,30 +432,8 @@ impl BackgroundWrapper { self.snapshot = Snapshot { transforms: new_transforms, - version: new_snapshot.version(), input: new_snapshot, }; - self.check_invariants(); - } - - fn check_invariants(&self) { - #[cfg(debug_assertions)] - { - let summary = self.snapshot.transforms.summary(); - assert_eq!( - InputPoint::new(summary.input.lines.row, summary.input.lines.column), - self.snapshot.input.max_point() - ); - - let mut transforms = self.snapshot.transforms.cursor::<(), ()>().peekable(); - while let Some(transform) = transforms.next() { - let next_transform = transforms.peek(); - assert!( - !transform.is_isomorphic() - || next_transform.map_or(true, |t| !t.is_isomorphic()) - ); - } - } } } @@ -613,10 +645,14 @@ mod tests { unwrapped_text ); + let mut interpolated_snapshot = wrapper.snapshot.clone(); for _i in 0..operations { buffer.update(cx, |buffer, cx| buffer.randomly_mutate(&mut rng, cx)); let (snapshot, edits) = fold_map.read(cx.as_ref()); let (snapshot, edits) = tab_map.sync(snapshot, edits); + interpolated_snapshot.interpolate(snapshot.clone(), &edits); + interpolated_snapshot.check_invariants(); + let unwrapped_text = snapshot.text(); let expected_text = wrap_text( &unwrapped_text, @@ -625,7 +661,7 @@ mod tests { font_system.as_ref(), ); wrapper.sync(snapshot, edits); - + wrapper.snapshot.check_invariants(); let actual_text = wrapper .snapshot .chunks_at(OutputPoint::zero()) @@ -635,6 +671,8 @@ mod tests { "unwrapped text is: {:?}", unwrapped_text ); + + interpolated_snapshot = wrapper.snapshot.clone(); } } } @@ -661,4 +699,22 @@ mod tests { } wrapped_text } + + impl Snapshot { + fn check_invariants(&self) { + assert_eq!( + InputPoint::from(self.transforms.summary().input.lines), + self.input.max_point() + ); + + let mut transforms = self.transforms.cursor::<(), ()>().peekable(); + while let Some(transform) = transforms.next() { + let next_transform = transforms.peek(); + assert!( + !transform.is_isomorphic() + || next_transform.map_or(true, |t| !t.is_isomorphic()) + ); + } + } + } }