@@ -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)
}
}
@@ -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))
+ }
})
}
@@ -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);
@@ -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 {