WIP: Start on BlockMap

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/editor/src/display_map.rs           |   1 
crates/editor/src/display_map/block_map.rs | 142 ++++++++++++++++++++++++
crates/editor/src/display_map/wrap_map.rs  |   2 
3 files changed, 145 insertions(+)

Detailed changes

crates/editor/src/display_map/block_map.rs 🔗

@@ -0,0 +1,142 @@
+use std::cmp;
+
+use super::wrap_map::{Edit as WrapEdit, Snapshot as WrapSnapshot};
+use buffer::Bias;
+use parking_lot::Mutex;
+use sum_tree::SumTree;
+
+struct BlockMap {
+    transforms: Mutex<SumTree<Transform>>,
+}
+
+struct BlockMapWriter<'a>(&'a mut BlockMap);
+
+struct BlockSnapshot {}
+
+#[derive(Clone)]
+struct Transform {
+    summary: TransformSummary,
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+struct TransformSummary {
+    input_rows: u32,
+    output_rows: u32,
+}
+
+#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
+struct InputRow(u32);
+
+#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
+struct OutputRow(u32);
+
+impl BlockMap {
+    fn new(wrap_snapshot: WrapSnapshot) -> Self {
+        Self {
+            transforms: Mutex::new(SumTree::from_item(
+                Transform::isomorphic(wrap_snapshot.max_point().row() + 1),
+                &(),
+            )),
+        }
+    }
+
+    fn read(&self, wrap_snapshot: WrapSnapshot, edits: Vec<WrapEdit>) -> BlockSnapshot {
+        self.sync(wrap_snapshot, edits);
+        BlockSnapshot {}
+    }
+
+    fn write(&mut self, wrap_snapshot: WrapSnapshot, edits: Vec<WrapEdit>) -> BlockMapWriter {
+        self.sync(wrap_snapshot, edits);
+        BlockMapWriter(self)
+    }
+
+    fn sync(&self, wrap_snapshot: WrapSnapshot, edits: Vec<WrapEdit>) {
+        let transforms = self.transforms.lock();
+        let mut new_transforms = SumTree::new();
+        let mut cursor = transforms.cursor::<InputRow>();
+        let mut edits = edits.into_iter().peekable();
+        while let Some(mut edit) = edits.next() {
+            new_transforms.push_tree(
+                cursor.slice(&InputRow(edit.old.start), Bias::Left, &()),
+                &(),
+            );
+
+            let transform_start = cursor.start().0;
+            edit.new.start -= edit.old.start - transform_start;
+            edit.old.start = transform_start;
+
+            loop {
+                if edit.old.end > cursor.start().0 {
+                    cursor.seek(&InputRow(edit.old.end), Bias::Left, &());
+                    cursor.next(&());
+                    let transform_end = cursor.start().0;
+                    edit.new.end += transform_end - edit.old.end;
+                    edit.old.end = transform_end;
+                }
+
+                if let Some(next_edit) = edits.peek() {
+                    if edit.old.end >= next_edit.old.start {
+                        edit.old.end = cmp::max(next_edit.old.end, edit.old.end);
+                        edit.new.end += (edit.new.len() as i32 - edit.old.len() as i32) as u32;
+                        edits.next();
+                    } else {
+                        break;
+                    }
+                } else {
+                    break;
+                }
+            }
+
+            // TODO: process injections
+
+            let new_transforms_end = new_transforms.summary().input_rows;
+            if new_transforms_end < edit.new.end {
+                new_transforms.push(
+                    Transform::isomorphic(edit.new.end - new_transforms_end),
+                    &(),
+                );
+            }
+        }
+        new_transforms.push_tree(cursor.suffix(&()), &());
+    }
+}
+
+impl Transform {
+    fn isomorphic(rows: u32) -> Self {
+        Self {
+            summary: TransformSummary {
+                input_rows: rows,
+                output_rows: rows,
+            },
+        }
+    }
+}
+
+impl sum_tree::Item for Transform {
+    type Summary = TransformSummary;
+
+    fn summary(&self) -> Self::Summary {
+        self.summary
+    }
+}
+
+impl sum_tree::Summary for TransformSummary {
+    type Context = ();
+
+    fn add_summary(&mut self, summary: &Self, _: &()) {
+        self.input_rows += summary.input_rows;
+        self.output_rows += summary.output_rows;
+    }
+}
+
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for InputRow {
+    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
+        self.0 += summary.input_rows;
+    }
+}
+
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for OutputRow {
+    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
+        self.0 += summary.output_rows;
+    }
+}

crates/editor/src/display_map/wrap_map.rs 🔗

@@ -9,6 +9,8 @@ use smol::future::yield_now;
 use std::{collections::VecDeque, ops::Range, time::Duration};
 use sum_tree::{Bias, Cursor, SumTree};
 
+pub type Edit = buffer::Edit<u32>;
+
 pub struct WrapMap {
     snapshot: Snapshot,
     pending_edits: VecDeque<(TabSnapshot, Vec<TabEdit>)>,