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:
+4
-4
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user