WIP

Antonio Scandurra created

Change summary

zed/src/editor/buffer.rs               | 126 +++++++++------------------
zed/src/editor/buffer/anchor.rs        |  25 +++--
zed/src/editor/display_map/fold_map.rs |  25 +++++
zed/src/time.rs                        |   2 
4 files changed, 83 insertions(+), 95 deletions(-)

Detailed changes

zed/src/editor/buffer.rs 🔗

@@ -1498,16 +1498,12 @@ impl Buffer {
                 Operation::UpdateSelections { selections, .. } => {
                     if let Some(selections) = selections {
                         selections.iter().all(|selection| {
-                            let contains_start = match selection.start {
-                                Anchor::Middle { insertion_id, .. } => {
-                                    self.version.observed(insertion_id)
-                                }
+                            let contains_start = match &selection.start {
+                                Anchor::Middle { version, .. } => self.version >= *version,
                                 _ => true,
                             };
-                            let contains_end = match selection.end {
-                                Anchor::Middle { insertion_id, .. } => {
-                                    self.version.observed(insertion_id)
-                                }
+                            let contains_end = match &selection.end {
+                                Anchor::Middle { version, .. } => self.version >= *version,
                                 _ => true,
                             };
                             contains_start && contains_end
@@ -1980,62 +1976,15 @@ impl Buffer {
         let max_offset = self.len();
         assert!(offset <= max_offset, "offset is out of range");
 
-        let seek_bias;
-        match bias {
-            AnchorBias::Left => {
-                if offset == 0 {
-                    return Anchor::Start;
-                } else {
-                    seek_bias = SeekBias::Left;
-                }
-            }
-            AnchorBias::Right => {
-                if offset == max_offset {
-                    return Anchor::End;
-                } else {
-                    seek_bias = SeekBias::Right;
-                }
-            }
-        };
-
-        let mut cursor = self.fragments.cursor::<usize, usize>();
-        cursor.seek(&offset, seek_bias, &());
-        let fragment = cursor.item().unwrap();
-        let offset_in_fragment = offset - cursor.start();
-        let offset_in_insertion = fragment.range_in_insertion.start + offset_in_fragment;
-        let anchor = Anchor::Middle {
-            insertion_id: fragment.insertion.id,
-            offset: offset_in_insertion,
-            bias,
-        };
-        anchor
-    }
-
-    fn fragment_id_for_anchor(&self, anchor: &Anchor) -> Result<&FragmentId> {
-        match anchor {
-            Anchor::Start => Ok(FragmentId::max_value()),
-            Anchor::End => Ok(FragmentId::min_value()),
+        if offset == 0 && bias == AnchorBias::Left {
+            Anchor::Start
+        } else if offset == max_offset && bias == AnchorBias::Right {
+            Anchor::End
+        } else {
             Anchor::Middle {
-                insertion_id,
                 offset,
                 bias,
-                ..
-            } => {
-                let seek_bias = match bias {
-                    AnchorBias::Left => SeekBias::Left,
-                    AnchorBias::Right => SeekBias::Right,
-                };
-
-                let splits = self
-                    .insertion_splits
-                    .get(&insertion_id)
-                    .ok_or_else(|| anyhow!("split does not exist for insertion id"))?;
-                let mut splits_cursor = splits.cursor::<usize, ()>();
-                splits_cursor.seek(offset, seek_bias, &());
-                splits_cursor
-                    .item()
-                    .ok_or_else(|| anyhow!("split offset is out of range"))
-                    .map(|split| &split.fragment_id)
+                version: self.version(),
             }
         }
     }
@@ -2045,31 +1994,44 @@ impl Buffer {
             Anchor::Start => TextSummary::default(),
             Anchor::End => self.text_summary(),
             Anchor::Middle {
-                insertion_id,
                 offset,
                 bias,
+                version,
             } => {
-                let seek_bias = match bias {
-                    AnchorBias::Left => SeekBias::Left,
-                    AnchorBias::Right => SeekBias::Right,
-                };
-
-                let splits = self
-                    .insertion_splits
-                    .get(&insertion_id)
-                    .expect("split does not exist for insertion id");
-                let mut splits_cursor = splits.cursor::<usize, ()>();
-                splits_cursor.seek(offset, seek_bias, &());
-                let split = splits_cursor.item().expect("split offset is out of range");
-
-                let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, usize>();
-                fragments_cursor.seek(&FragmentIdRef::new(&split.fragment_id), SeekBias::Left, &());
-                let fragment = fragments_cursor.item().expect("fragment id does not exist");
-
-                let mut ix = *fragments_cursor.start();
-                if fragment.visible {
-                    ix += offset - fragment.range_in_insertion.start;
+                let mut cursor = self
+                    .fragments
+                    .filter::<_, usize>(|summary| !(*version >= summary.max_version), &());
+
+                let mut old_offset = 0;
+                let mut new_offset = 0;
+                while let Some(fragment) = cursor.item() {
+                    let bytes_since_last_fragment = *cursor.start() - new_offset;
+                    let comparison = offset.cmp(&(old_offset + bytes_since_last_fragment));
+                    if comparison == cmp::Ordering::Greater
+                        || (comparison == cmp::Ordering::Equal && *bias == AnchorBias::Right)
+                    {
+                        old_offset += bytes_since_last_fragment;
+                        new_offset += bytes_since_last_fragment;
+
+                        if fragment.was_visible(version, &self.undo_map) {
+                            let comparison = offset.cmp(&(old_offset + fragment.visible_len()));
+                            if comparison == cmp::Ordering::Greater
+                                || (comparison == cmp::Ordering::Equal
+                                    && *bias == AnchorBias::Right)
+                            {
+                                old_offset += fragment.len();
+                            } else {
+                                break;
+                            }
+                        }
+                        new_offset += fragment.visible_len();
+                        cursor.next(&());
+                    } else {
+                        break;
+                    }
                 }
+
+                let ix = new_offset + offset.saturating_sub(old_offset);
                 self.text_summary_for_range(0..ix)
             }
         }

zed/src/editor/buffer/anchor.rs 🔗

@@ -1,17 +1,16 @@
-use super::Buffer;
+use super::{Buffer, ToOffset};
 use crate::time;
 use anyhow::Result;
-use std::cmp::Ordering;
-use std::ops::Range;
+use std::{cmp::Ordering, ops::Range};
 
 #[derive(Clone, Eq, PartialEq, Debug, Hash)]
 pub enum Anchor {
     Start,
     End,
     Middle {
-        insertion_id: time::Local,
         offset: usize,
         bias: AnchorBias,
+        version: time::Global,
     },
 }
 
@@ -55,18 +54,22 @@ impl Anchor {
                 Anchor::Middle {
                     offset: self_offset,
                     bias: self_bias,
-                    ..
+                    version: self_version,
                 },
                 Anchor::Middle {
                     offset: other_offset,
                     bias: other_bias,
-                    ..
+                    version: other_version,
                 },
-            ) => buffer
-                .fragment_id_for_anchor(self)?
-                .cmp(buffer.fragment_id_for_anchor(other)?)
-                .then_with(|| self_offset.cmp(other_offset))
-                .then_with(|| self_bias.cmp(other_bias)),
+            ) => {
+                let offset_comparison = if self_version == other_version {
+                    self_offset.cmp(other_offset)
+                } else {
+                    self.to_offset(buffer).cmp(&other.to_offset(buffer))
+                };
+
+                offset_comparison.then_with(|| self_bias.cmp(other_bias))
+            }
         })
     }
 

zed/src/editor/display_map/fold_map.rs 🔗

@@ -1027,11 +1027,34 @@ mod tests {
 
             for _ in 0..operations {
                 log::info!("text: {:?}", buffer.read(cx).text());
+                {
+                    let buffer = buffer.read(cx);
+                    let mut cursor = map.folds.cursor::<(), ()>();
+                    cursor.next(buffer);
+                    let mut prev_fold: Option<&Fold> = None;
+                    while let Some(fold) = cursor.item() {
+                        if let Some(prev_fold) = prev_fold {
+                            let prev_fold = prev_fold.0.start.to_offset(buffer)
+                                ..prev_fold.0.end.to_offset(buffer);
+                            let fold = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer);
+                            assert!(
+                                fold.start > prev_fold.start
+                                    || (fold.start == prev_fold.start && fold.end <= prev_fold.end),
+                                "prev fold {:?}\ncurr fold {:?}",
+                                prev_fold,
+                                fold
+                            );
+                        }
+
+                        prev_fold = Some(fold);
+                        cursor.next(buffer);
+                    }
+                }
                 match rng.gen_range(0..=100) {
                     0..=34 => {
                         let buffer = buffer.read(cx);
                         let mut to_fold = Vec::new();
-                        for _ in 0..rng.gen_range(1..=5) {
+                        for _ in 0..rng.gen_range(1..=2) {
                             let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
                             let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
                             to_fold.push(start..end);

zed/src/time.rs 🔗

@@ -54,7 +54,7 @@ impl<'a> AddAssign<&'a Local> for Local {
     }
 }
 
-#[derive(Clone, Debug, Default, Eq, PartialEq)]
+#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
 pub struct Global(SmallVec<[Local; 3]>);
 
 impl Global {