Always represent anchor as a versioned offset

Remove the `Start` and `End` variants, and always
use the structure that was previously called `Middle`.
This makes Anchors simpler to serialize and deserialize.
This commit is contained in:
Max Brunsfeld
2021-06-25 17:02:48 -07:00
parent b9952bad8b
commit 60ee97be24
4 changed files with 91 additions and 155 deletions
+4 -4
View File
@@ -1629,7 +1629,7 @@ impl Editor {
pub fn select_to_beginning(&mut self, _: &(), cx: &mut ViewContext<Self>) {
let mut selection = self.selections(cx.as_ref()).last().unwrap().clone();
selection.set_head(self.buffer.read(cx), Anchor::Start);
selection.set_head(self.buffer.read(cx), Anchor::min());
self.update_selections(vec![selection], true, cx);
}
@@ -1648,15 +1648,15 @@ impl Editor {
pub fn select_to_end(&mut self, _: &(), cx: &mut ViewContext<Self>) {
let mut selection = self.selections(cx.as_ref()).last().unwrap().clone();
selection.set_head(self.buffer.read(cx), Anchor::End);
selection.set_head(self.buffer.read(cx), Anchor::max());
self.update_selections(vec![selection], true, cx);
}
pub fn select_all(&mut self, _: &(), cx: &mut ViewContext<Self>) {
let selection = Selection {
id: post_inc(&mut self.next_selection_id),
start: Anchor::Start,
end: Anchor::End,
start: Anchor::min(),
end: Anchor::max(),
reversed: false,
goal: SelectionGoal::None,
};
+45 -100
View File
@@ -1493,14 +1493,8 @@ impl Buffer {
Operation::UpdateSelections { selections, .. } => {
if let Some(selections) = selections {
selections.iter().all(|selection| {
let contains_start = match &selection.start {
Anchor::Middle { version, .. } => self.version >= *version,
_ => true,
};
let contains_end = match &selection.end {
Anchor::Middle { version, .. } => self.version >= *version,
_ => true,
};
let contains_start = self.version >= selection.start.version;
let contains_end = self.version >= selection.end.version;
contains_start && contains_end
})
} else {
@@ -1645,76 +1639,42 @@ impl Buffer {
let offset = position.to_offset(self);
let max_offset = self.len();
assert!(offset <= max_offset, "offset is out of range");
if offset == 0 && bias == Bias::Left {
Anchor::Start
} else if offset == max_offset && bias == Bias::Right {
Anchor::End
} else {
let mut cursor = self.fragments.cursor::<usize, FragmentTextSummary>();
cursor.seek(&offset, bias, &None);
Anchor::Middle {
offset: offset + cursor.start().deleted,
bias,
version: self.version(),
}
let mut cursor = self.fragments.cursor::<usize, FragmentTextSummary>();
cursor.seek(&offset, bias, &None);
Anchor {
offset: offset + cursor.start().deleted,
bias,
version: self.version(),
}
}
fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary {
match anchor {
Anchor::Start => TextSummary::default(),
Anchor::End => self.text_summary(),
Anchor::Middle {
offset,
bias,
version,
} => {
let mut cursor = self
.fragments
.cursor::<VersionedOffset, (VersionedOffset, usize)>();
cursor.seek(
&VersionedOffset::Offset(*offset),
*bias,
&Some(version.clone()),
);
let fragment = cursor.item().unwrap();
let overshoot = if fragment.visible {
offset - cursor.start().0.offset()
} else {
0
};
self.text_summary_for_range(0..cursor.start().1 + overshoot)
}
}
let cx = Some(anchor.version.clone());
let mut cursor = self
.fragments
.cursor::<VersionedOffset, (VersionedOffset, usize)>();
cursor.seek(&VersionedOffset::Offset(anchor.offset), anchor.bias, &cx);
let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) {
anchor.offset - cursor.start().0.offset()
} else {
0
};
self.text_summary_for_range(0..cursor.start().1 + overshoot)
}
fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize {
match anchor {
Anchor::Start => 0,
Anchor::End => {
let summary = self.fragments.summary();
summary.text.visible + summary.text.deleted
}
Anchor::Middle {
offset,
bias,
version,
} => {
let mut cursor = self
.fragments
.cursor::<VersionedOffset, (VersionedOffset, FragmentTextSummary)>();
cursor.seek(
&VersionedOffset::Offset(*offset),
*bias,
&Some(version.clone()),
);
let overshoot = offset - cursor.start().0.offset();
let summary = cursor.start().1;
summary.visible + summary.deleted + overshoot
}
}
let cx = Some(anchor.version.clone());
let mut cursor = self
.fragments
.cursor::<VersionedOffset, (VersionedOffset, FragmentTextSummary)>();
cursor.seek(&VersionedOffset::Offset(anchor.offset), anchor.bias, &cx);
let overshoot = if cursor.item().is_some() {
anchor.offset - cursor.start().0.offset()
} else {
0
};
let summary = cursor.start().1;
summary.visible + summary.deleted + overshoot
}
pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
@@ -2311,34 +2271,19 @@ impl<'a> Into<proto::operation::Edit> for &'a EditOperation {
impl<'a> Into<proto::Anchor> for &'a Anchor {
fn into(self) -> proto::Anchor {
match self {
Anchor::Middle {
offset,
bias,
version,
} => proto::Anchor {
version: version
.iter()
.map(|entry| proto::VectorClockEntry {
replica_id: entry.replica_id as u32,
timestamp: entry.value,
})
.collect(),
offset: *offset as u64,
bias: match bias {
Bias::Left => proto::anchor::Bias::Left as i32,
Bias::Right => proto::anchor::Bias::Right as i32,
},
},
Anchor::Start => proto::Anchor {
version: Vec::new(),
bias: proto::anchor::Bias::Left as i32,
offset: 0,
},
Anchor::End => proto::Anchor {
version: Vec::new(),
bias: proto::anchor::Bias::Right as i32,
offset: u64::MAX,
proto::Anchor {
version: self
.version
.iter()
.map(|entry| proto::VectorClockEntry {
replica_id: entry.replica_id as u32,
timestamp: entry.value,
})
.collect(),
offset: self.offset as u64,
bias: match self.bias {
Bias::Left => proto::anchor::Bias::Left as i32,
Bias::Right => proto::anchor::Bias::Right as i32,
},
}
}
@@ -2449,7 +2394,7 @@ impl TryFrom<proto::Anchor> for Anchor {
});
}
Ok(Self::Middle {
Ok(Self {
offset: message.offset as usize,
bias: if message.bias == proto::anchor::Bias::Left as i32 {
Bias::Left
+36 -45
View File
@@ -4,67 +4,58 @@ use anyhow::Result;
use std::{cmp::Ordering, ops::Range};
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub enum Anchor {
Start,
End,
Middle {
offset: usize,
bias: Bias,
version: time::Global,
},
pub struct Anchor {
pub offset: usize,
pub bias: Bias,
pub version: time::Global,
}
impl Anchor {
pub fn min() -> Self {
Self {
offset: 0,
bias: Bias::Left,
version: Default::default(),
}
}
pub fn max() -> Self {
Self {
offset: usize::MAX,
bias: Bias::Right,
version: Default::default(),
}
}
pub fn cmp(&self, other: &Anchor, buffer: &Buffer) -> Result<Ordering> {
if self == other {
return Ok(Ordering::Equal);
}
Ok(match (self, other) {
(Anchor::Start, _) | (_, Anchor::End) => Ordering::Less,
(Anchor::End, _) | (_, Anchor::Start) => Ordering::Greater,
(
Anchor::Middle {
offset: self_offset,
bias: self_bias,
version: self_version,
},
Anchor::Middle {
offset: other_offset,
bias: other_bias,
version: other_version,
},
) => {
let offset_comparison = if self_version == other_version {
self_offset.cmp(other_offset)
} else {
buffer
.full_offset_for_anchor(self)
.cmp(&buffer.full_offset_for_anchor(other))
};
let offset_comparison = if self.version == other.version {
self.offset.cmp(&other.offset)
} else {
buffer
.full_offset_for_anchor(self)
.cmp(&buffer.full_offset_for_anchor(other))
};
offset_comparison.then_with(|| self_bias.cmp(&other_bias))
}
})
Ok(offset_comparison.then_with(|| self.bias.cmp(&other.bias)))
}
pub fn bias_left(&self, buffer: &Buffer) -> Anchor {
match self {
Anchor::Start
| Anchor::Middle {
bias: Bias::Left, ..
} => self.clone(),
_ => buffer.anchor_before(self),
if self.bias == Bias::Left {
self.clone()
} else {
buffer.anchor_before(self)
}
}
pub fn bias_right(&self, buffer: &Buffer) -> Anchor {
match self {
Anchor::End
| Anchor::Middle {
bias: Bias::Right, ..
} => self.clone(),
_ => buffer.anchor_after(self),
if self.bias == Bias::Right {
self.clone()
} else {
buffer.anchor_after(self)
}
}
}
+6 -6
View File
@@ -313,7 +313,7 @@ impl FoldMap {
let anchor = buffer.anchor_before(edit.new_range.start);
let mut folds_cursor = self.folds.cursor::<_, ()>();
folds_cursor.seek(&Fold(anchor..Anchor::End), Bias::Left, buffer);
folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, buffer);
let mut folds = iter::from_fn(move || {
let item = folds_cursor
.item()
@@ -597,7 +597,7 @@ struct Fold(Range<Anchor>);
impl Default for Fold {
fn default() -> Self {
Self(Anchor::Start..Anchor::End)
Self(Anchor::min()..Anchor::max())
}
}
@@ -627,10 +627,10 @@ struct FoldSummary {
impl Default for FoldSummary {
fn default() -> Self {
Self {
start: Anchor::Start,
end: Anchor::End,
min_start: Anchor::End,
max_end: Anchor::Start,
start: Anchor::min(),
end: Anchor::max(),
min_start: Anchor::max(),
max_end: Anchor::min(),
count: 0,
}
}