WIP
This commit is contained in:
+42
-80
@@ -1498,16 +1498,12 @@ impl Buffer {
|
|||||||
Operation::UpdateSelections { selections, .. } => {
|
Operation::UpdateSelections { selections, .. } => {
|
||||||
if let Some(selections) = selections {
|
if let Some(selections) = selections {
|
||||||
selections.iter().all(|selection| {
|
selections.iter().all(|selection| {
|
||||||
let contains_start = match selection.start {
|
let contains_start = match &selection.start {
|
||||||
Anchor::Middle { insertion_id, .. } => {
|
Anchor::Middle { version, .. } => self.version >= *version,
|
||||||
self.version.observed(insertion_id)
|
|
||||||
}
|
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
let contains_end = match selection.end {
|
let contains_end = match &selection.end {
|
||||||
Anchor::Middle { insertion_id, .. } => {
|
Anchor::Middle { version, .. } => self.version >= *version,
|
||||||
self.version.observed(insertion_id)
|
|
||||||
}
|
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
contains_start && contains_end
|
contains_start && contains_end
|
||||||
@@ -1980,62 +1976,15 @@ impl Buffer {
|
|||||||
let max_offset = self.len();
|
let max_offset = self.len();
|
||||||
assert!(offset <= max_offset, "offset is out of range");
|
assert!(offset <= max_offset, "offset is out of range");
|
||||||
|
|
||||||
let seek_bias;
|
if offset == 0 && bias == AnchorBias::Left {
|
||||||
match bias {
|
Anchor::Start
|
||||||
AnchorBias::Left => {
|
} else if offset == max_offset && bias == AnchorBias::Right {
|
||||||
if offset == 0 {
|
Anchor::End
|
||||||
return Anchor::Start;
|
} else {
|
||||||
} 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()),
|
|
||||||
Anchor::Middle {
|
Anchor::Middle {
|
||||||
insertion_id,
|
|
||||||
offset,
|
offset,
|
||||||
bias,
|
bias,
|
||||||
..
|
version: self.version(),
|
||||||
} => {
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2045,31 +1994,44 @@ impl Buffer {
|
|||||||
Anchor::Start => TextSummary::default(),
|
Anchor::Start => TextSummary::default(),
|
||||||
Anchor::End => self.text_summary(),
|
Anchor::End => self.text_summary(),
|
||||||
Anchor::Middle {
|
Anchor::Middle {
|
||||||
insertion_id,
|
|
||||||
offset,
|
offset,
|
||||||
bias,
|
bias,
|
||||||
|
version,
|
||||||
} => {
|
} => {
|
||||||
let seek_bias = match bias {
|
let mut cursor = self
|
||||||
AnchorBias::Left => SeekBias::Left,
|
.fragments
|
||||||
AnchorBias::Right => SeekBias::Right,
|
.filter::<_, usize>(|summary| !(*version >= summary.max_version), &());
|
||||||
};
|
|
||||||
|
|
||||||
let splits = self
|
let mut old_offset = 0;
|
||||||
.insertion_splits
|
let mut new_offset = 0;
|
||||||
.get(&insertion_id)
|
while let Some(fragment) = cursor.item() {
|
||||||
.expect("split does not exist for insertion id");
|
let bytes_since_last_fragment = *cursor.start() - new_offset;
|
||||||
let mut splits_cursor = splits.cursor::<usize, ()>();
|
let comparison = offset.cmp(&(old_offset + bytes_since_last_fragment));
|
||||||
splits_cursor.seek(offset, seek_bias, &());
|
if comparison == cmp::Ordering::Greater
|
||||||
let split = splits_cursor.item().expect("split offset is out of range");
|
|| (comparison == cmp::Ordering::Equal && *bias == AnchorBias::Right)
|
||||||
|
{
|
||||||
|
old_offset += bytes_since_last_fragment;
|
||||||
|
new_offset += bytes_since_last_fragment;
|
||||||
|
|
||||||
let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, usize>();
|
if fragment.was_visible(version, &self.undo_map) {
|
||||||
fragments_cursor.seek(&FragmentIdRef::new(&split.fragment_id), SeekBias::Left, &());
|
let comparison = offset.cmp(&(old_offset + fragment.visible_len()));
|
||||||
let fragment = fragments_cursor.item().expect("fragment id does not exist");
|
if comparison == cmp::Ordering::Greater
|
||||||
|
|| (comparison == cmp::Ordering::Equal
|
||||||
let mut ix = *fragments_cursor.start();
|
&& *bias == AnchorBias::Right)
|
||||||
if fragment.visible {
|
{
|
||||||
ix += offset - fragment.range_in_insertion.start;
|
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)
|
self.text_summary_for_range(0..ix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
use super::Buffer;
|
use super::{Buffer, ToOffset};
|
||||||
use crate::time;
|
use crate::time;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::cmp::Ordering;
|
use std::{cmp::Ordering, ops::Range};
|
||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
|
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
|
||||||
pub enum Anchor {
|
pub enum Anchor {
|
||||||
Start,
|
Start,
|
||||||
End,
|
End,
|
||||||
Middle {
|
Middle {
|
||||||
insertion_id: time::Local,
|
|
||||||
offset: usize,
|
offset: usize,
|
||||||
bias: AnchorBias,
|
bias: AnchorBias,
|
||||||
|
version: time::Global,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,18 +54,22 @@ impl Anchor {
|
|||||||
Anchor::Middle {
|
Anchor::Middle {
|
||||||
offset: self_offset,
|
offset: self_offset,
|
||||||
bias: self_bias,
|
bias: self_bias,
|
||||||
..
|
version: self_version,
|
||||||
},
|
},
|
||||||
Anchor::Middle {
|
Anchor::Middle {
|
||||||
offset: other_offset,
|
offset: other_offset,
|
||||||
bias: other_bias,
|
bias: other_bias,
|
||||||
..
|
version: other_version,
|
||||||
},
|
},
|
||||||
) => buffer
|
) => {
|
||||||
.fragment_id_for_anchor(self)?
|
let offset_comparison = if self_version == other_version {
|
||||||
.cmp(buffer.fragment_id_for_anchor(other)?)
|
self_offset.cmp(other_offset)
|
||||||
.then_with(|| self_offset.cmp(other_offset))
|
} else {
|
||||||
.then_with(|| self_bias.cmp(other_bias)),
|
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 {
|
for _ in 0..operations {
|
||||||
log::info!("text: {:?}", buffer.read(cx).text());
|
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) {
|
match rng.gen_range(0..=100) {
|
||||||
0..=34 => {
|
0..=34 => {
|
||||||
let buffer = buffer.read(cx);
|
let buffer = buffer.read(cx);
|
||||||
let mut to_fold = Vec::new();
|
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 end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
|
||||||
let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
|
let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
|
||||||
to_fold.push(start..end);
|
to_fold.push(start..end);
|
||||||
|
|||||||
+1
-1
@@ -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]>);
|
pub struct Global(SmallVec<[Local; 3]>);
|
||||||
|
|
||||||
impl Global {
|
impl Global {
|
||||||
|
|||||||
Reference in New Issue
Block a user