diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index 7fd9c4c9d6d81f0511dc430eea4afbce0dc70d60..390149646e34d017196ec99ac68b96f6403cd4c0 100644 --- a/zed/src/editor/buffer.rs +++ b/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::(); - 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::(); - 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::(); - 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::(); - 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) } } diff --git a/zed/src/editor/buffer/anchor.rs b/zed/src/editor/buffer/anchor.rs index 3b2687f96daf63e6149d3400f4034fe8b8e94359..607c5d4aa884e8676fc1a8fe11dda553e4b63146 100644 --- a/zed/src/editor/buffer/anchor.rs +++ b/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)) + } }) } diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 6fc3c7175beb92626312209897e8c505cd0a4e20..1866e86608d32e7609d4b2a89b06ed9b92d87129 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/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); diff --git a/zed/src/time.rs b/zed/src/time.rs index f1cf4eef916c9c7995cbc333a18d3a2d51a1ccd2..8668ebfe9cfaed30a66dca3a22aec8ba18e01891 100644 --- a/zed/src/time.rs +++ b/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 {