WIP: Start representing edit operations with versions and multiple ranges

Nathan Sobo and Max Brunsfeld created

Compiling, long way to go though.

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>

Change summary

zed/src/editor/buffer.rs | 854 +++++++++++++++--------------------------
1 file changed, 319 insertions(+), 535 deletions(-)

Detailed changes

zed/src/editor/buffer.rs 🔗

@@ -781,12 +781,11 @@ impl Buffer {
                 match tag {
                     ChangeTag::Equal => offset += len,
                     ChangeTag::Delete => {
-                        operations.extend_from_slice(&self.edit(Some(range), "", Some(cx)).unwrap())
+                        operations.push(self.edit(Some(range), "", Some(cx)).unwrap())
                     }
                     ChangeTag::Insert => {
-                        operations.extend_from_slice(
-                            &self
-                                .edit(Some(offset..offset), &diff.new_text[range], Some(cx))
+                        operations.push(
+                            self.edit(Some(offset..offset), &diff.new_text[range], Some(cx))
                                 .unwrap(),
                         );
                         offset += len;
@@ -952,10 +951,10 @@ impl Buffer {
 
     pub fn edit<I, S, T>(
         &mut self,
-        old_ranges: I,
+        ranges: I,
         new_text: T,
         cx: Option<&mut ModelContext<Self>>,
-    ) -> Result<Vec<Operation>>
+    ) -> Result<Operation>
     where
         I: IntoIterator<Item = Range<S>>,
         S: ToOffset,
@@ -964,44 +963,45 @@ impl Buffer {
         self.start_transaction_at(None, Instant::now())?;
 
         let new_text = new_text.into();
-        let old_ranges = old_ranges
-            .into_iter()
-            .map(|range| range.start.to_offset(self)..range.end.to_offset(self))
-            .collect::<Vec<Range<usize>>>();
-
         let new_text = if new_text.len() > 0 {
             Some(new_text)
         } else {
             None
         };
-
         let has_new_text = new_text.is_some();
-        let ops = self.splice_fragments(
-            old_ranges
-                .into_iter()
-                .filter(|old_range| has_new_text || old_range.end > old_range.start),
-            new_text.into(),
-        );
+        let ranges = ranges
+            .into_iter()
+            .filter_map(|range| {
+                let range = range.start.to_offset(self)..range.end.to_offset(self);
+                if has_new_text || !range.is_empty() {
+                    Some(range)
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<Range<usize>>>();
 
-        for op in &ops {
-            if let Operation::Edit { edit, .. } = op {
-                self.history.push(edit.clone());
-                self.history.push_undo(edit.id);
-            }
-        }
+        let edit_id = self.local_clock.tick();
+        let lamport_timestamp = self.lamport_clock.tick();
+        self.splice_fragments(&ranges, new_text.clone(), edit_id, lamport_timestamp);
 
-        if let Some(op) = ops.last() {
-            if let Operation::Edit { edit, .. } = op {
-                self.last_edit = edit.id;
-                self.version.observe(edit.id);
-            } else {
-                unreachable!()
-            }
-        }
+        let edit = EditOperation {
+            id: edit_id,
+            version: self.version.clone(),
+            ranges,
+            new_text,
+        };
+        self.history.push(edit.clone());
+        self.history.push_undo(edit.id);
+        self.last_edit = edit.id;
+        self.version.observe(edit.id);
 
         self.end_transaction_at(None, Instant::now(), cx)?;
 
-        Ok(ops)
+        Ok(Operation::Edit {
+            edit,
+            lamport_timestamp,
+        })
     }
 
     fn did_edit(&self, was_dirty: bool, cx: &mut ModelContext<Self>) {
@@ -1128,8 +1128,8 @@ impl Buffer {
             } => {
                 if !self.version.observed(edit.id) {
                     self.apply_edit(
-                        edit.version,
-                        edit.ranges,
+                        &edit.version,
+                        &edit.ranges,
                         edit.new_text.as_deref(),
                         edit.id,
                         lamport_timestamp,
@@ -1167,73 +1167,180 @@ impl Buffer {
 
     fn apply_edit(
         &mut self,
-        version: time::Global,
-        ranges: Vec<Range<usize>>,
-        mut new_text: Option<&str>,
+        version: &time::Global,
+        ranges: &[Range<usize>],
+        new_text: Option<&str>,
         local_timestamp: time::Local,
         lamport_timestamp: time::Lamport,
     ) -> Result<()> {
-        let mut old_visible_text = mem::take(&mut self.visible_text);
-        let mut old_deleted_text = mem::take(&mut self.deleted_text);
-        let mut old_fragments = mem::take(&mut self.fragments);
+        let old_visible_text = mem::take(&mut self.visible_text);
+        let old_deleted_text = mem::take(&mut self.deleted_text);
+        let old_fragments = mem::take(&mut self.fragments);
         let mut old_fragments = old_fragments.cursor::<VersionedOffset, VersionedOffset>();
-
-        let version = Some(version);
+        let old_fragments_cx = Some(version.clone());
 
         let mut new_fragments = SumTree::new();
         let mut new_ropes =
             RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
-        let mut pending_fragment = None;
-        let mut pending_fragment_start_offset = 0;
-
-        for range in ranges {
-            let preceding_fragments = old_fragments.slice(
-                &VersionedOffset::Offset(range.start),
+        let mut ranges = ranges.iter().peekable();
+        let mut fragment_start_offset = 0;
+
+        // Push the fragments that precede the first edit and park the cursor over the fragment
+        // containing the start of the first edit.
+        if let Some(first_range) = ranges.peek() {
+            let prefix_fragments = old_fragments.slice(
+                &VersionedOffset::Offset(first_range.start),
                 SeekBias::Right,
-                &version,
+                &old_fragments_cx,
             );
-            new_fragments.push_tree(preceding_fragments, &None);
-            new_ropes.push_tree(new_fragments.summary().text);
+            new_ropes.push_tree(prefix_fragments.summary().text);
+            new_fragments.push_tree(prefix_fragments, &None);
+            fragment_start_offset = old_fragments.start().offset();
+        }
+
+        while let Some(range) = ranges.peek() {
+            let fragment = old_fragments.item();
+            let fragment_end_offset = old_fragments.end(&old_fragments_cx).offset();
+
+            if let Some(fragment) = fragment {
+                // Was this fragment visible in the edit's base version? If not, push it into
+                // the new fragments, skip it, and continue the loop.
+                if !version.observed(fragment.insertion.id) {
+                    new_ropes.push_fragment(fragment, fragment.visible);
+                    new_fragments.push(fragment.clone(), &None);
+                    old_fragments.next(&old_fragments_cx);
+                    continue;
+                }
 
-            let mut fragment_start_offset = old_fragments.start().offset();
-            let mut fragment_end_offset = old_fragments.end(&version).offset();
-            let mut fragment = if let Some(fragment) = old_fragments.item() {
-                fragment.clone()
+                // If the current fragment doesn't intersect the current range, push the remainder
+                // of the fragment and then slice to the fragment containing the start of the
+                // current range.
+                if range.start > fragment_end_offset {
+                    if fragment_end_offset > fragment_start_offset {
+                        let suffix = Fragment {
+                            len: fragment_end_offset - fragment_start_offset,
+                            deletions: fragment.deletions.clone(),
+                            max_undos: fragment.max_undos.clone(),
+                            visible: fragment.visible,
+                            // DELETE
+                            id: Default::default(),
+                            insertion: fragment.insertion.clone(),
+                            range_in_insertion: Default::default(),
+                        };
+                        new_ropes.push_fragment(&suffix, fragment.visible);
+                        new_fragments.push(suffix, &None);
+                    }
+
+                    let prefix_fragments = old_fragments.slice(
+                        &VersionedOffset::Offset(range.start),
+                        SeekBias::Right,
+                        &old_fragments_cx,
+                    );
+                    new_ropes.push_tree(prefix_fragments.summary().text);
+                    new_fragments.push_tree(prefix_fragments, &None);
+                    fragment_start_offset = old_fragments.start().offset();
+                }
+
+                // Now the current range intersects the current fragment.
+                // If there is a piece of the fragment preceding the current range, consume it.
+                if range.start > fragment_start_offset {
+                    let prefix = Fragment {
+                        len: range.start - fragment_start_offset,
+                        deletions: fragment.deletions.clone(),
+                        max_undos: fragment.max_undos.clone(),
+                        visible: fragment.visible,
+
+                        // TODO: Delete these
+                        id: Default::default(),
+                        insertion: fragment.insertion.clone(),
+                        range_in_insertion: Default::default(),
+                    };
+                    fragment_start_offset += prefix.len;
+                    new_ropes.push_fragment(&prefix, fragment.visible);
+                    new_fragments.push(prefix, &None);
+                }
+
+                // Push the portion of the current fragment that intersects the current range,
+                // marking it as deleted.
+                if range.end > range.start {
+                    let deleted_end = cmp::min(range.end, fragment_end_offset);
+
+                    let mut deletions = fragment.deletions.clone();
+                    deletions.insert(local_timestamp);
+
+                    let deleted = Fragment {
+                        len: deleted_end - fragment_start_offset,
+                        deletions,
+                        max_undos: fragment.max_undos.clone(),
+                        visible: false,
+
+                        // TODO: Delete these
+                        id: Default::default(),
+                        insertion: fragment.insertion.clone(),
+                        range_in_insertion: Default::default(),
+                    };
+                    fragment_start_offset += deleted.len;
+                    new_ropes.push_fragment(&deleted, fragment.visible);
+                    new_fragments.push(deleted, &None);
+                }
+
+                // Push any new text
+                if let Some(new_next) = new_text {
+                    new_ropes.push_str(new_next);
+                    new_fragments.push(
+                        Fragment {
+                            len: new_next.len(),
+                            deletions: Default::default(),
+                            max_undos: Default::default(), // TODO: Is this right?
+                            visible: true,
+
+                            // TODO: Delete these
+                            id: Default::default(),
+                            insertion: fragment.insertion.clone(),
+                            range_in_insertion: Default::default(),
+                        },
+                        &None,
+                    );
+                }
+
+                // Which ends first? The current fragment or the current range? If the current range
+                // ends before the current fragment, advance to the next range and preserve the
+                // current fragment. Otherwise, advance to next fragment and preserve the current
+                // range.
+                if range.end < fragment_end_offset {
+                    ranges.next();
+                } else {
+                    old_fragments.next(&old_fragments_cx);
+                    fragment_start_offset = fragment_end_offset;
+                }
             } else {
-                todo!()
-            };
+                // Push a fragment containing the new text
+            }
+        }
 
-            if fragment_start_offset < range.start {
-                let prefix_fragment = Fragment {
-                    len: range.start - fragment_start_offset,
-                    visible: fragment.visible,
+        if let Some(fragment) = old_fragments.item() {
+            let fragment_end_offset = old_fragments.end(&old_fragments_cx).offset();
+            if fragment_end_offset > fragment_start_offset {
+                let suffix = Fragment {
+                    len: fragment_end_offset - fragment_start_offset,
                     deletions: fragment.deletions.clone(),
                     max_undos: fragment.max_undos.clone(),
-
-                    // TODO - remove
-                    id: fragment.id.clone(),
+                    visible: fragment.visible,
+                    // DELETE
+                    id: Default::default(),
                     insertion: fragment.insertion.clone(),
                     range_in_insertion: Default::default(),
                 };
-
-                new_ropes.push_fragment(&prefix_fragment, prefix_fragment.visible);
-                new_fragments.push(prefix_fragment, &None);
-                fragment.len -= prefix_fragment.len;
+                new_ropes.push_fragment(&suffix, fragment.visible);
+                new_fragments.push(suffix, &None);
             }
 
-            let suffix_fragment = if fragment_end_offset > range.end {
-                fragment.visible = false;
-
-                //
-
-                Some(Fragment {});
-            } else {
-                None
-            };
+            let suffix_fragments = old_fragments.suffix(&None);
+            new_ropes.push_tree(suffix_fragments.summary().text);
+            new_fragments.push_tree(suffix_fragments, &None);
         }
 
         let (visible_text, deleted_text) = new_ropes.finish();
-        new_fragments.push_tree(old_fragments.suffix(&None), &None);
 
         self.fragments = new_fragments;
         self.visible_text = visible_text;
@@ -1243,134 +1350,6 @@ impl Buffer {
         Ok(())
     }
 
-    //     let mut new_fragments = fragments_cursor.slice(
-    //     &VersionedOffset::Offset(range.start),
-    //     SeekBias::Left,
-    //     &version_cx,
-    // );
-    // new_ropes.push_tree(new_fragments.summary().text);
-
-    // if range.start == fragments_cursor.end(&version_cx).offset() {
-    //     let fragment = fragments_cursor.item().unwrap().clone();
-    //     new_ropes.push_fragment(&fragment, fragment.visible);
-    //     new_fragments.push(fragment, &None);
-    //     fragments_cursor.next(&None);
-    // }
-
-    // while let Some(fragment) = fragments_cursor.item() {
-    //     let fragment_start_offset = fragments_cursor.start().offset();
-    //     let fragment_end_offset = fragments_cursor.end(&version_cx).offset();
-
-    //     if new_text.is_none() && fragment_start_offset > range.end {
-    //         break;
-    //     }
-
-    //     if fragment_start_offset
-
-    // if cursor_start_offset < range.start || cursor_end_offset > range.end {
-    //     let split_start = if start_fragment_id == fragment.id {
-    //         start_offset
-    //     } else {
-    //         fragment.range_in_insertion.start
-    //     };
-    //     let split_end = if end_fragment_id == fragment.id {
-    //         end_offset
-    //     } else {
-    //         fragment.range_in_insertion.end
-    //     };
-    //     let (before_range, within_range, after_range) = self.split_fragment(
-    //         fragments_cursor.prev_item().as_ref().unwrap(),
-    //         &fragment,
-    //         split_start..split_end,
-    //     );
-    //     let insertion = if let Some(new_text) = new_text {
-    //         let prev_fragment = fragments_cursor.prev_item();
-    //         Some(self.build_fragment_to_insert(
-    //             before_range.as_ref().or(prev_fragment).unwrap(),
-    //             within_range.as_ref().or(after_range.as_ref()),
-    //             new_text,
-    //             local_timestamp,
-    //             lamport_timestamp,
-    //         ))
-    //     } else {
-    //         None
-    //     };
-    //     if let Some(fragment) = before_range {
-    //         new_ropes.push_fragment(&fragment, fragment.visible);
-    //         new_fragments.push(fragment, &None);
-    //     }
-    //     if let Some(fragment) = insertion {
-    //         new_ropes.push_str(new_text.take().unwrap());
-    //         new_fragments.push(fragment, &None);
-    //     }
-    //     if let Some(mut fragment) = within_range {
-    //         let fragment_was_visible = fragment.visible;
-    //         if fragment.was_visible(&version_in_range, &self.undo_map) {
-    //             fragment.deletions.insert(local_timestamp);
-    //             if fragment.visible {
-    //                 fragment.visible = false;
-    //             }
-    //         }
-    //         new_ropes.push_fragment(&fragment, fragment_was_visible);
-    //         new_fragments.push(fragment, &None);
-    //     }
-    //     if let Some(fragment) = after_range {
-    //         new_ropes.push_fragment(&fragment, fragment.visible);
-    //         new_fragments.push(fragment, &None);
-    //     }
-    // } else {
-    //     if new_text.is_some() && lamport_timestamp > fragment.insertion.lamport_timestamp {
-    //         let new_text = new_text.take().unwrap();
-    //         let fragment = self.build_fragment_to_insert(
-    //             fragments_cursor.prev_item().as_ref().unwrap(),
-    //             Some(&fragment),
-    //             new_text,
-    //             local_timestamp,
-    //             lamport_timestamp,
-    //         );
-    //         new_ropes.push_str(new_text);
-    //         new_fragments.push(fragment, &None);
-    //     }
-
-    //     let fragment_was_visible = fragment.visible;
-    //     if fragment.id < end_fragment_id
-    //         && fragment.was_visible(&version_in_range, &self.undo_map)
-    //     {
-    //         fragment.deletions.insert(local_timestamp);
-    //         if fragment.visible {
-    //             fragment.visible = false;
-    //         }
-    //     }
-
-    //     new_ropes.push_fragment(&fragment, fragment_was_visible);
-    //     new_fragments.push(fragment, &None);
-    // }
-    // fragments_cursor.next(&None);
-    // }
-
-    // if let Some(new_text) = new_text {
-    //     let fragment = self.build_fragment_to_insert(
-    //         fragments_cursor.prev_item().as_ref().unwrap(),
-    //         None,
-    //         new_text,
-    //         local_timestamp,
-    //         lamport_timestamp,
-    //     );
-    //     new_ropes.push_str(new_text);
-    //     new_fragments.push(fragment, &None);
-    // }
-
-    // let (visible_text, deleted_text) = new_ropes.finish();
-    // new_fragments.push_tree(fragments_cursor.suffix(&None), &None);
-
-    // self.fragments = new_fragments;
-    // self.visible_text = visible_text;
-    // self.deleted_text = deleted_text;
-    // self.local_clock.observe(local_timestamp);
-    // self.lamport_clock.observe(lamport_timestamp);
-    // Ok(())
-    // }
-
     pub fn undo(&mut self, mut cx: Option<&mut ModelContext<Self>>) -> Vec<Operation> {
         let was_dirty = self.is_dirty();
         let old_version = self.version.clone();
@@ -1441,90 +1420,94 @@ impl Buffer {
     }
 
     fn apply_undo(&mut self, undo: UndoOperation) -> Result<()> {
-        let mut new_fragments;
-        let mut old_visible_text = Rope::new();
-        let mut old_deleted_text = Rope::new();
-        mem::swap(&mut old_visible_text, &mut self.visible_text);
-        mem::swap(&mut old_deleted_text, &mut self.deleted_text);
-        let mut new_ropes =
-            RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
-
-        self.undo_map.insert(undo);
-        let edit = &self.history.ops[&undo.edit_id];
-        let start_fragment_id = self.resolve_fragment_id(edit.start_id, edit.start_offset)?;
-        let end_fragment_id = self.resolve_fragment_id(edit.end_id, edit.end_offset)?;
-
-        let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, ()>();
-
-        if edit.start_id == edit.end_id && edit.start_offset == edit.end_offset {
-            let splits = &self.insertion_splits[&undo.edit_id];
-            let mut insertion_splits = splits.cursor::<(), ()>().map(|s| &s.fragment_id).peekable();
-
-            let first_split_id = insertion_splits.next().unwrap();
-            new_fragments =
-                fragments_cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &None);
-            new_ropes.push_tree(new_fragments.summary().text);
-
-            loop {
-                let mut fragment = fragments_cursor.item().unwrap().clone();
-                let was_visible = fragment.visible;
-                fragment.visible = fragment.is_visible(&self.undo_map);
-                fragment.max_undos.observe(undo.id);
-
-                new_ropes.push_fragment(&fragment, was_visible);
-                new_fragments.push(fragment.clone(), &None);
-
-                fragments_cursor.next(&None);
-                if let Some(split_id) = insertion_splits.next() {
-                    let slice = fragments_cursor.slice(
-                        &FragmentIdRef::new(split_id),
-                        SeekBias::Left,
-                        &None,
-                    );
-                    new_ropes.push_tree(slice.summary().text);
-                    new_fragments.push_tree(slice, &None);
-                } else {
-                    break;
-                }
-            }
-        } else {
-            new_fragments = fragments_cursor.slice(
-                &FragmentIdRef::new(&start_fragment_id),
-                SeekBias::Left,
-                &None,
-            );
-            new_ropes.push_tree(new_fragments.summary().text);
-
-            while let Some(fragment) = fragments_cursor.item() {
-                if fragment.id > end_fragment_id {
-                    break;
-                } else {
-                    let mut fragment = fragment.clone();
-                    let fragment_was_visible = fragment.visible;
-                    if edit.version_in_range.observed(fragment.insertion.id)
-                        || fragment.insertion.id == undo.edit_id
-                    {
-                        fragment.visible = fragment.is_visible(&self.undo_map);
-                        fragment.max_undos.observe(undo.id);
-                    }
+        Ok(())
+    }
 
-                    new_ropes.push_fragment(&fragment, fragment_was_visible);
-                    new_fragments.push(fragment, &None);
-                    fragments_cursor.next(&None);
-                }
-            }
-        }
+    // {
+    //     let mut new_fragments;
+    //     let mut old_visible_text = Rope::new();
+    //     let mut old_deleted_text = Rope::new();
+    //     mem::swap(&mut old_visible_text, &mut self.visible_text);
+    //     mem::swap(&mut old_deleted_text, &mut self.deleted_text);
+    //     let mut new_ropes =
+    //         RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
+
+    //     self.undo_map.insert(undo);
+    //     let edit = &self.history.ops[&undo.edit_id];
+    //     let start_fragment_id = self.resolve_fragment_id(edit.start_id, edit.start_offset)?;
+    //     let end_fragment_id = self.resolve_fragment_id(edit.end_id, edit.end_offset)?;
+
+    //     let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, ()>();
+
+    //     if edit.start_id == edit.end_id && edit.start_offset == edit.end_offset {
+    //         let splits = &self.insertion_splits[&undo.edit_id];
+    //         let mut insertion_splits = splits.cursor::<(), ()>().map(|s| &s.fragment_id).peekable();
+
+    //         let first_split_id = insertion_splits.next().unwrap();
+    //         new_fragments =
+    //             fragments_cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &None);
+    //         new_ropes.push_tree(new_fragments.summary().text);
+
+    //         loop {
+    //             let mut fragment = fragments_cursor.item().unwrap().clone();
+    //             let was_visible = fragment.visible;
+    //             fragment.visible = fragment.is_visible(&self.undo_map);
+    //             fragment.max_undos.observe(undo.id);
+
+    //             new_ropes.push_fragment(&fragment, was_visible);
+    //             new_fragments.push(fragment.clone(), &None);
+
+    //             fragments_cursor.next(&None);
+    //             if let Some(split_id) = insertion_splits.next() {
+    //                 let slice = fragments_cursor.slice(
+    //                     &FragmentIdRef::new(split_id),
+    //                     SeekBias::Left,
+    //                     &None,
+    //                 );
+    //                 new_ropes.push_tree(slice.summary().text);
+    //                 new_fragments.push_tree(slice, &None);
+    //             } else {
+    //                 break;
+    //             }
+    //         }
+    //     } else {
+    //         new_fragments = fragments_cursor.slice(
+    //             &FragmentIdRef::new(&start_fragment_id),
+    //             SeekBias::Left,
+    //             &None,
+    //         );
+    //         new_ropes.push_tree(new_fragments.summary().text);
+
+    //         while let Some(fragment) = fragments_cursor.item() {
+    //             if fragment.id > end_fragment_id {
+    //                 break;
+    //             } else {
+    //                 let mut fragment = fragment.clone();
+    //                 let fragment_was_visible = fragment.visible;
+    //                 if edit.version_in_range.observed(fragment.insertion.id)
+    //                     || fragment.insertion.id == undo.edit_id
+    //                 {
+    //                     fragment.visible = fragment.is_visible(&self.undo_map);
+    //                     fragment.max_undos.observe(undo.id);
+    //                 }
+
+    //                 new_ropes.push_fragment(&fragment, fragment_was_visible);
+    //                 new_fragments.push(fragment, &None);
+    //                 fragments_cursor.next(&None);
+    //             }
+    //         }
+    //     }
 
-        new_fragments.push_tree(fragments_cursor.suffix(&None), &None);
-        let (visible_text, deleted_text) = new_ropes.finish();
-        drop(fragments_cursor);
+    //     new_fragments.push_tree(fragments_cursor.suffix(&None), &None);
+    //     let (visible_text, deleted_text) = new_ropes.finish();
+    //     drop(fragments_cursor);
 
-        self.fragments = new_fragments;
-        self.visible_text = visible_text;
-        self.deleted_text = deleted_text;
+    //     self.fragments = new_fragments;
+    //     self.visible_text = visible_text;
+    //     self.deleted_text = deleted_text;
 
-        Ok(())
-    }
+    //     Ok(())
+    // }
 
     fn flush_deferred_ops(&mut self) -> Result<()> {
         self.deferred_replicas.clear();
@@ -1542,69 +1525,54 @@ impl Buffer {
     }
 
     fn can_apply_op(&self, op: &Operation) -> bool {
-        if self.deferred_replicas.contains(&op.replica_id()) {
-            false
-        } else {
-            match op {
-                Operation::Edit { edit, .. } => {
-                    self.version.observed(edit.start_id)
-                        && self.version.observed(edit.end_id)
-                        && edit.version_in_range <= self.version
-                }
-                Operation::Undo { undo, .. } => self.version.observed(undo.edit_id),
-                Operation::UpdateSelections { selections, .. } => {
-                    if let Some(selections) = selections {
-                        selections.iter().all(|selection| {
-                            let contains_start = match &selection.start {
-                                Anchor::Middle { version, .. } => self.version >= *version,
-                                _ => true,
-                            };
-                            let contains_end = match &selection.end {
-                                Anchor::Middle { version, .. } => self.version >= *version,
-                                _ => true,
-                            };
-                            contains_start && contains_end
-                        })
-                    } else {
-                        true
-                    }
-                }
-            }
-        }
-    }
-
-    fn resolve_fragment_id(&self, edit_id: time::Local, offset: usize) -> Result<FragmentId> {
-        let split_tree = self
-            .insertion_splits
-            .get(&edit_id)
-            .ok_or_else(|| anyhow!("invalid operation"))?;
-        let mut cursor = split_tree.cursor::<usize, ()>();
-        cursor.seek(&offset, SeekBias::Left, &());
-        Ok(cursor
-            .item()
-            .ok_or_else(|| anyhow!("invalid operation"))?
-            .fragment_id
-            .clone())
-    }
-
-    fn splice_fragments<I>(&mut self, mut old_ranges: I, new_text: Option<String>) -> Vec<Operation>
-    where
-        I: Iterator<Item = Range<usize>>,
-    {
+        true
+        // if self.deferred_replicas.contains(&op.replica_id()) {
+        //     false
+        // } else {
+        //     match op {
+        //         Operation::Edit { edit, .. } => {
+        //             self.version.observed(edit.start_id)
+        //                 && self.version.observed(edit.end_id)
+        //                 && edit.version_in_range <= self.version
+        //         }
+        //         Operation::Undo { undo, .. } => self.version.observed(undo.edit_id),
+        //         Operation::UpdateSelections { selections, .. } => {
+        //             if let Some(selections) = selections {
+        //                 selections.iter().all(|selection| {
+        //                     let contains_start = match &selection.start {
+        //                         Anchor::Middle { version, .. } => self.version >= *version,
+        //                         _ => true,
+        //                     };
+        //                     let contains_end = match &selection.end {
+        //                         Anchor::Middle { version, .. } => self.version >= *version,
+        //                         _ => true,
+        //                     };
+        //                     contains_start && contains_end
+        //                 })
+        //             } else {
+        //                 true
+        //             }
+        //         }
+        //     }
+        // }
+    }
+
+    fn splice_fragments(
+        &mut self,
+        old_ranges: &[Range<usize>],
+        new_text: Option<String>,
+        edit_id: time::Local,
+        lamport_timestamp: time::Lamport,
+    ) {
+        let mut old_ranges = old_ranges.iter();
         let mut cur_range = old_ranges.next();
         if cur_range.is_none() {
-            return Vec::new();
+            return;
         }
 
-        let version = &self.version;
-        let mut ops = Vec::with_capacity(old_ranges.size_hint().0);
-
-        let mut old_fragments = SumTree::new();
-        let mut old_visible_text = Rope::new();
-        let mut old_deleted_text = Rope::new();
-        mem::swap(&mut old_visible_text, &mut self.visible_text);
-        mem::swap(&mut old_deleted_text, &mut self.deleted_text);
-        mem::swap(&mut old_fragments, &mut self.fragments);
+        let old_fragments = mem::take(&mut self.fragments);
+        let old_visible_text = mem::take(&mut self.visible_text);
+        let old_deleted_text = mem::take(&mut self.deleted_text);
 
         let mut fragments_cursor = old_fragments.cursor::<usize, usize>();
         let mut new_fragments =
@@ -1614,18 +1582,8 @@ impl Buffer {
             RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
         new_ropes.push_tree(new_fragments.summary().text);
 
-        let mut start_id = None;
-        let mut start_offset = None;
-        let mut end_id = None;
-        let mut end_offset = None;
-        let mut version_in_range = time::Global::new();
-
-        let mut local_timestamp = self.local_clock.tick();
-        let mut lamport_timestamp = self.lamport_clock.tick();
-
         while cur_range.is_some() && fragments_cursor.item().is_some() {
             let mut fragment = fragments_cursor.item().unwrap().clone();
-            let fragment_summary = fragments_cursor.item_summary().unwrap();
             let mut fragment_start = *fragments_cursor.start();
             let mut fragment_end = fragment_start + fragment.visible_len();
             let fragment_was_visible = fragment.visible;
@@ -1663,24 +1621,13 @@ impl Buffer {
                     fragment_start = range.start;
                 }
 
-                if range.end == fragment_start {
-                    end_id = Some(new_fragments.last().unwrap().insertion.id);
-                    end_offset = Some(new_fragments.last().unwrap().range_in_insertion.end);
-                } else if range.end == fragment_end {
-                    end_id = Some(fragment.insertion.id);
-                    end_offset = Some(fragment.range_in_insertion.end);
-                }
-
                 if range.start == fragment_start {
-                    start_id = Some(new_fragments.last().unwrap().insertion.id);
-                    start_offset = Some(new_fragments.last().unwrap().range_in_insertion.end);
-
                     if let Some(new_text) = new_text.clone() {
                         let new_fragment = self.build_fragment_to_insert(
                             &new_fragments.last().unwrap(),
                             Some(&fragment),
                             &new_text,
-                            local_timestamp,
+                            edit_id,
                             lamport_timestamp,
                         );
 
@@ -1696,9 +1643,8 @@ impl Buffer {
                             prefix.range_in_insertion.start + (range.end - fragment_start);
                         prefix.id =
                             FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id);
-                        version_in_range.join(&fragment_summary.max_version);
                         if prefix.visible {
-                            prefix.deletions.insert(local_timestamp);
+                            prefix.deletions.insert(edit_id);
                             prefix.visible = false;
                         }
                         fragment.range_in_insertion.start = prefix.range_in_insertion.end;
@@ -1713,13 +1659,10 @@ impl Buffer {
                             &(),
                         );
                         fragment_start = range.end;
-                        end_id = Some(fragment.insertion.id);
-                        end_offset = Some(fragment.range_in_insertion.start);
                     }
                 } else {
-                    version_in_range.join(&fragment_summary.max_version);
                     if fragment.visible {
-                        fragment.deletions.insert(local_timestamp);
+                        fragment.deletions.insert(edit_id);
                         fragment.visible = false;
                     }
                 }
@@ -1728,26 +1671,7 @@ impl Buffer {
                 // check if it also intersects the current fragment. Otherwise we break out of the
                 // loop and find the first fragment that the splice does not contain fully.
                 if range.end <= fragment_end {
-                    ops.push(Operation::Edit {
-                        edit: EditOperation {
-                            id: local_timestamp,
-                            version,
-                            range,
-                            new_text: new_text.clone(),
-                        },
-                        lamport_timestamp,
-                    });
-
-                    start_id = None;
-                    start_offset = None;
-                    end_id = None;
-                    end_offset = None;
-                    version_in_range = time::Global::new();
                     cur_range = old_ranges.next();
-                    if cur_range.is_some() {
-                        local_timestamp = self.local_clock.tick();
-                        lamport_timestamp = self.lamport_clock.tick();
-                    }
                 } else {
                     break;
                 }
@@ -1774,15 +1698,13 @@ impl Buffer {
             fragments_cursor.next(&None);
             if let Some(range) = cur_range.clone() {
                 while let Some(fragment) = fragments_cursor.item() {
-                    let fragment_summary = fragments_cursor.item_summary().unwrap();
                     let fragment_was_visible = fragment.visible;
                     fragment_start = *fragments_cursor.start();
                     fragment_end = fragment_start + fragment.visible_len();
                     if range.start < fragment_start && range.end >= fragment_end {
                         let mut new_fragment = fragment.clone();
-                        version_in_range.join(&fragment_summary.max_version);
                         if new_fragment.visible {
-                            new_fragment.deletions.insert(local_timestamp);
+                            new_fragment.deletions.insert(edit_id);
                             new_fragment.visible = false;
                         }
 
@@ -1791,32 +1713,7 @@ impl Buffer {
                         fragments_cursor.next(&None);
 
                         if range.end == fragment_end {
-                            end_id = Some(fragment.insertion.id);
-                            end_offset = Some(fragment.range_in_insertion.end);
-                            ops.push(Operation::Edit {
-                                edit: EditOperation {
-                                    id: local_timestamp,
-                                    start_id: start_id.unwrap(),
-                                    start_offset: start_offset.unwrap(),
-                                    end_id: end_id.unwrap(),
-                                    end_offset: end_offset.unwrap(),
-                                    version_in_range,
-                                    new_text: new_text.clone(),
-                                },
-                                lamport_timestamp,
-                            });
-
-                            start_id = None;
-                            start_offset = None;
-                            end_id = None;
-                            end_offset = None;
-                            version_in_range = time::Global::new();
-
                             cur_range = old_ranges.next();
-                            if cur_range.is_some() {
-                                local_timestamp = self.local_clock.tick();
-                                lamport_timestamp = self.lamport_clock.tick();
-                            }
                             break;
                         }
                     } else {
@@ -1844,26 +1741,13 @@ impl Buffer {
         if cur_range.is_some() {
             debug_assert_eq!(old_ranges.next(), None);
             let last_fragment = new_fragments.last().unwrap();
-            ops.push(Operation::Edit {
-                edit: EditOperation {
-                    id: local_timestamp,
-                    start_id: last_fragment.insertion.id,
-                    start_offset: last_fragment.range_in_insertion.end,
-                    end_id: last_fragment.insertion.id,
-                    end_offset: last_fragment.range_in_insertion.end,
-                    version_in_range: time::Global::new(),
-                    // TODO: avoid cloning the String.
-                    new_text: new_text.clone(),
-                },
-                lamport_timestamp,
-            });
 
             if let Some(new_text) = new_text {
                 let new_fragment = self.build_fragment_to_insert(
                     &last_fragment,
                     None,
                     &new_text,
-                    local_timestamp,
+                    edit_id,
                     lamport_timestamp,
                 );
 
@@ -1878,106 +1762,6 @@ impl Buffer {
         self.fragments = new_fragments;
         self.visible_text = visible_text;
         self.deleted_text = deleted_text;
-        ops
-    }
-
-    fn split_fragment(
-        &mut self,
-        prev_fragment: &Fragment,
-        fragment: &Fragment,
-        range: Range<usize>,
-    ) -> (Option<Fragment>, Option<Fragment>, Option<Fragment>) {
-        debug_assert!(range.start >= fragment.range_in_insertion.start);
-        debug_assert!(range.start <= fragment.range_in_insertion.end);
-        debug_assert!(range.end <= fragment.range_in_insertion.end);
-        debug_assert!(range.end >= fragment.range_in_insertion.start);
-
-        if range.end == fragment.range_in_insertion.start {
-            (None, None, Some(fragment.clone()))
-        } else if range.start == fragment.range_in_insertion.end {
-            (Some(fragment.clone()), None, None)
-        } else if range.start == fragment.range_in_insertion.start
-            && range.end == fragment.range_in_insertion.end
-        {
-            (None, Some(fragment.clone()), None)
-        } else {
-            let mut prefix = fragment.clone();
-
-            let after_range = if range.end < fragment.range_in_insertion.end {
-                let mut suffix = prefix.clone();
-                suffix.range_in_insertion.start = range.end;
-                prefix.range_in_insertion.end = range.end;
-                prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id);
-                Some(suffix)
-            } else {
-                None
-            };
-
-            let within_range = if range.start != range.end {
-                let mut suffix = prefix.clone();
-                suffix.range_in_insertion.start = range.start;
-                prefix.range_in_insertion.end = range.start;
-                prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id);
-                Some(suffix)
-            } else {
-                None
-            };
-
-            let before_range = if range.start > fragment.range_in_insertion.start {
-                Some(prefix)
-            } else {
-                None
-            };
-
-            let old_split_tree = self
-                .insertion_splits
-                .remove(&fragment.insertion.id)
-                .unwrap();
-            let mut cursor = old_split_tree.cursor::<usize, ()>();
-            let mut new_split_tree =
-                cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &());
-
-            if let Some(ref fragment) = before_range {
-                new_split_tree.push(
-                    InsertionSplit {
-                        extent: range.start - fragment.range_in_insertion.start,
-                        fragment_id: fragment.id.clone(),
-                    },
-                    &(),
-                );
-            }
-
-            if let Some(ref fragment) = within_range {
-                new_split_tree.push(
-                    InsertionSplit {
-                        extent: range.end - range.start,
-                        fragment_id: fragment.id.clone(),
-                    },
-                    &(),
-                );
-            }
-
-            if let Some(ref fragment) = after_range {
-                new_split_tree.push(
-                    InsertionSplit {
-                        extent: fragment.range_in_insertion.end - range.end,
-                        fragment_id: fragment.id.clone(),
-                    },
-                    &(),
-                );
-            }
-
-            cursor.next(&());
-            new_split_tree.push_tree(
-                cursor.slice(&old_split_tree.extent::<usize>(&()), SeekBias::Right, &()),
-                &(),
-            );
-
-            self.insertion_splits
-                .insert(fragment.insertion.id, new_split_tree);
-
-            (before_range, within_range, after_range)
-        }
     }
 
     fn build_fragment_to_insert(