Merge branch 'anchor-map-selections' into lsp

This commit is contained in:
Max Brunsfeld 2021-10-28 17:08:06 -07:00
commit e1556893f7
11 changed files with 956 additions and 848 deletions

View File

@ -1,8 +1,10 @@
use crate::FullOffset; use super::{Buffer, Content, FromAnchor, FullOffset, Point, ToOffset};
use super::{Buffer, Content, FromAnchor, Point, ToOffset};
use anyhow::Result; use anyhow::Result;
use std::{cmp::Ordering, ops::Range}; use std::{
cmp::Ordering,
fmt::{Debug, Formatter},
ops::Range,
};
use sum_tree::{Bias, SumTree}; use sum_tree::{Bias, SumTree};
#[derive(Clone, Eq, PartialEq, Debug, Hash)] #[derive(Clone, Eq, PartialEq, Debug, Hash)]
@ -112,7 +114,25 @@ impl Anchor {
} }
impl<T> AnchorMap<T> { impl<T> AnchorMap<T> {
pub fn to_points<'a>( pub fn version(&self) -> &clock::Global {
&self.version
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn offsets<'a>(
&'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = (usize, &'a T)> + 'a {
let content = content.into();
content
.summaries_for_anchors(self)
.map(move |(sum, value)| (sum.bytes, value))
}
pub fn points<'a>(
&'a self, &'a self,
content: impl Into<Content<'a>> + 'a, content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = (Point, &'a T)> + 'a { ) -> impl Iterator<Item = (Point, &'a T)> + 'a {
@ -121,23 +141,50 @@ impl<T> AnchorMap<T> {
.summaries_for_anchors(self) .summaries_for_anchors(self)
.map(move |(sum, value)| (sum.lines, value)) .map(move |(sum, value)| (sum.lines, value))
} }
pub fn version(&self) -> &clock::Global {
&self.version
}
} }
impl AnchorSet { impl AnchorSet {
pub fn to_points<'a>( pub fn version(&self) -> &clock::Global {
&self.0.version
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn offsets<'a>(
&'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = usize> + 'a {
self.0.offsets(content).map(|(offset, _)| offset)
}
pub fn points<'a>(
&'a self, &'a self,
content: impl Into<Content<'a>> + 'a, content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = Point> + 'a { ) -> impl Iterator<Item = Point> + 'a {
self.0.to_points(content).map(move |(point, _)| point) self.0.points(content).map(|(point, _)| point)
} }
} }
impl<T> AnchorRangeMap<T> { impl<T> AnchorRangeMap<T> {
pub fn to_point_ranges<'a>( pub fn version(&self) -> &clock::Global {
&self.version
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn from_raw(version: clock::Global, entries: Vec<(Range<(FullOffset, Bias)>, T)>) -> Self {
Self { version, entries }
}
pub fn raw_entries(&self) -> &[(Range<(FullOffset, Bias)>, T)] {
&self.entries
}
pub fn point_ranges<'a>(
&'a self, &'a self,
content: impl Into<Content<'a>> + 'a, content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = (Range<Point>, &'a T)> + 'a { ) -> impl Iterator<Item = (Range<Point>, &'a T)> + 'a {
@ -147,22 +194,68 @@ impl<T> AnchorRangeMap<T> {
.map(move |(range, value)| ((range.start.lines..range.end.lines), value)) .map(move |(range, value)| ((range.start.lines..range.end.lines), value))
} }
pub fn version(&self) -> &clock::Global { pub fn offset_ranges<'a>(
&self.version &'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = (Range<usize>, &'a T)> + 'a {
let content = content.into();
content
.summaries_for_anchor_ranges(self)
.map(move |(range, value)| ((range.start.bytes..range.end.bytes), value))
}
}
impl<T: PartialEq> PartialEq for AnchorRangeMap<T> {
fn eq(&self, other: &Self) -> bool {
self.version == other.version && self.entries == other.entries
}
}
impl<T: Eq> Eq for AnchorRangeMap<T> {}
impl<T: Debug> Debug for AnchorRangeMap<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
let mut f = f.debug_map();
for (range, value) in &self.entries {
f.key(range);
f.value(value);
}
f.finish()
}
}
impl Debug for AnchorRangeSet {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_set();
for (range, _) in &self.0.entries {
f.entry(range);
}
f.finish()
} }
} }
impl AnchorRangeSet { impl AnchorRangeSet {
pub fn to_point_ranges<'a>( pub fn len(&self) -> usize {
&'a self, self.0.len()
content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = Range<Point>> + 'a {
self.0.to_point_ranges(content).map(|(range, _)| range)
} }
pub fn version(&self) -> &clock::Global { pub fn version(&self) -> &clock::Global {
self.0.version() self.0.version()
} }
pub fn offset_ranges<'a>(
&'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = Range<usize>> + 'a {
self.0.offset_ranges(content).map(|(range, _)| range)
}
pub fn point_ranges<'a>(
&'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl Iterator<Item = Range<Point>> + 'a {
self.0.point_ranges(content).map(|(range, _)| range)
}
} }
impl<T: Clone> Default for AnchorRangeMultimap<T> { impl<T: Clone> Default for AnchorRangeMultimap<T> {

View File

@ -20,7 +20,7 @@ use rpc::proto;
pub use selection::*; pub use selection::*;
use std::{ use std::{
cmp::{self, Reverse}, cmp::{self, Reverse},
convert::{TryFrom, TryInto}, convert::TryFrom,
iter::Iterator, iter::Iterator,
ops::{self, Range}, ops::{self, Range},
str, str,
@ -73,20 +73,14 @@ pub struct Buffer {
lamport_clock: clock::Lamport, lamport_clock: clock::Lamport,
} }
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SelectionSet {
pub selections: Arc<[Selection]>,
pub active: bool,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Transaction { pub struct Transaction {
start: clock::Global, start: clock::Global,
end: clock::Global, end: clock::Global,
edits: Vec<clock::Local>, edits: Vec<clock::Local>,
ranges: Vec<Range<FullOffset>>, ranges: Vec<Range<FullOffset>>,
selections_before: HashMap<SelectionSetId, Arc<[Selection]>>, selections_before: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
selections_after: HashMap<SelectionSetId, Arc<[Selection]>>, selections_after: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
first_edit_at: Instant, first_edit_at: Instant,
last_edit_at: Instant, last_edit_at: Instant,
} }
@ -173,7 +167,7 @@ impl History {
fn start_transaction( fn start_transaction(
&mut self, &mut self,
start: clock::Global, start: clock::Global,
selections_before: HashMap<SelectionSetId, Arc<[Selection]>>, selections_before: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
now: Instant, now: Instant,
) { ) {
self.transaction_depth += 1; self.transaction_depth += 1;
@ -193,7 +187,7 @@ impl History {
fn end_transaction( fn end_transaction(
&mut self, &mut self,
selections_after: HashMap<SelectionSetId, Arc<[Selection]>>, selections_after: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
now: Instant, now: Instant,
) -> Option<&Transaction> { ) -> Option<&Transaction> {
assert_ne!(self.transaction_depth, 0); assert_ne!(self.transaction_depth, 0);
@ -415,7 +409,11 @@ pub enum Operation {
}, },
UpdateSelections { UpdateSelections {
set_id: SelectionSetId, set_id: SelectionSetId,
selections: Option<Arc<[Selection]>>, selections: Arc<AnchorRangeMap<SelectionState>>,
lamport_timestamp: clock::Lamport,
},
RemoveSelections {
set_id: SelectionSetId,
lamport_timestamp: clock::Lamport, lamport_timestamp: clock::Lamport,
}, },
SetActiveSelections { SetActiveSelections {
@ -489,20 +487,8 @@ impl Buffer {
.selections .selections
.into_iter() .into_iter()
.map(|set| { .map(|set| {
let set_id = clock::Lamport { let set = SelectionSet::try_from(set)?;
replica_id: set.replica_id as ReplicaId, Result::<_, anyhow::Error>::Ok((set.id, set))
value: set.local_timestamp,
};
let selections: Vec<Selection> = set
.selections
.into_iter()
.map(TryFrom::try_from)
.collect::<Result<_, _>>()?;
let set = SelectionSet {
selections: Arc::from(selections),
active: set.is_active,
};
Result::<_, anyhow::Error>::Ok((set_id, set))
}) })
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
Ok(buffer) Ok(buffer)
@ -514,16 +500,7 @@ impl Buffer {
id: self.remote_id, id: self.remote_id,
content: self.history.base_text.to_string(), content: self.history.base_text.to_string(),
history: ops, history: ops,
selections: self selections: self.selections.iter().map(|(_, set)| set.into()).collect(),
.selections
.iter()
.map(|(set_id, set)| proto::SelectionSetSnapshot {
replica_id: set_id.replica_id as u32,
local_timestamp: set_id.value,
selections: set.selections.iter().map(Into::into).collect(),
is_active: set.active,
})
.collect(),
} }
} }
@ -565,6 +542,13 @@ impl Buffer {
self.content().anchor_at(position, bias) self.content().anchor_at(position, bias)
} }
pub fn anchor_range_set<E>(&self, entries: E) -> AnchorRangeSet
where
E: IntoIterator<Item = Range<(usize, Bias)>>,
{
self.content().anchor_range_set(entries)
}
pub fn point_for_offset(&self, offset: usize) -> Result<Point> { pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
self.content().point_for_offset(offset) self.content().point_for_offset(offset)
} }
@ -858,23 +842,27 @@ impl Buffer {
selections, selections,
lamport_timestamp, lamport_timestamp,
} => { } => {
if let Some(selections) = selections { if let Some(set) = self.selections.get_mut(&set_id) {
if let Some(set) = self.selections.get_mut(&set_id) { set.selections = selections;
set.selections = selections;
} else {
self.selections.insert(
set_id,
SelectionSet {
selections,
active: false,
},
);
}
} else { } else {
self.selections.remove(&set_id); self.selections.insert(
set_id,
SelectionSet {
id: set_id,
selections,
active: false,
},
);
} }
self.lamport_clock.observe(lamport_timestamp); self.lamport_clock.observe(lamport_timestamp);
} }
Operation::RemoveSelections {
set_id,
lamport_timestamp,
} => {
self.selections.remove(&set_id);
self.lamport_clock.observe(lamport_timestamp);
}
Operation::SetActiveSelections { Operation::SetActiveSelections {
set_id, set_id,
lamport_timestamp, lamport_timestamp,
@ -1142,16 +1130,9 @@ impl Buffer {
Operation::Edit(edit) => self.version >= edit.version, Operation::Edit(edit) => self.version >= edit.version,
Operation::Undo { undo, .. } => self.version >= undo.version, Operation::Undo { undo, .. } => self.version >= undo.version,
Operation::UpdateSelections { selections, .. } => { Operation::UpdateSelections { selections, .. } => {
if let Some(selections) = selections { self.version >= *selections.version()
selections.iter().all(|selection| {
let contains_start = self.version >= selection.start.version;
let contains_end = self.version >= selection.end.version;
contains_start && contains_end
})
} else {
true
}
} }
Operation::RemoveSelections { .. } => true,
Operation::SetActiveSelections { set_id, .. } => { Operation::SetActiveSelections { set_id, .. } => {
set_id.map_or(true, |set_id| self.selections.contains_key(&set_id)) set_id.map_or(true, |set_id| self.selections.contains_key(&set_id))
} }
@ -1232,7 +1213,7 @@ impl Buffer {
let selections = transaction.selections_before.clone(); let selections = transaction.selections_before.clone();
ops.push(self.undo_or_redo(transaction).unwrap()); ops.push(self.undo_or_redo(transaction).unwrap());
for (set_id, selections) in selections { for (set_id, selections) in selections {
ops.extend(self.update_selection_set(set_id, selections)); ops.extend(self.restore_selection_set(set_id, selections));
} }
} }
ops ops
@ -1244,7 +1225,7 @@ impl Buffer {
let selections = transaction.selections_after.clone(); let selections = transaction.selections_after.clone();
ops.push(self.undo_or_redo(transaction).unwrap()); ops.push(self.undo_or_redo(transaction).unwrap());
for (set_id, selections) in selections { for (set_id, selections) in selections {
ops.extend(self.update_selection_set(set_id, selections)); ops.extend(self.restore_selection_set(set_id, selections));
} }
} }
ops ops
@ -1281,12 +1262,32 @@ impl Buffer {
self.selections.iter() self.selections.iter()
} }
pub fn update_selection_set( fn build_selection_anchor_range_map<T: ToOffset>(
&self,
selections: &[Selection<T>],
) -> Arc<AnchorRangeMap<SelectionState>> {
Arc::new(
self.content()
.anchor_range_map(selections.iter().map(|selection| {
let start = selection.start.to_offset(self);
let end = selection.end.to_offset(self);
let range = (start, Bias::Left)..(end, Bias::Left);
let state = SelectionState {
id: selection.id,
reversed: selection.reversed,
goal: selection.goal,
};
(range, state)
})),
)
}
pub fn update_selection_set<T: ToOffset>(
&mut self, &mut self,
set_id: SelectionSetId, set_id: SelectionSetId,
selections: impl Into<Arc<[Selection]>>, selections: &[Selection<T>],
) -> Result<Operation> { ) -> Result<Operation> {
let selections = selections.into(); let selections = self.build_selection_anchor_range_map(selections);
let set = self let set = self
.selections .selections
.get_mut(&set_id) .get_mut(&set_id)
@ -1294,25 +1295,43 @@ impl Buffer {
set.selections = selections.clone(); set.selections = selections.clone();
Ok(Operation::UpdateSelections { Ok(Operation::UpdateSelections {
set_id, set_id,
selections: Some(selections), selections,
lamport_timestamp: self.lamport_clock.tick(), lamport_timestamp: self.lamport_clock.tick(),
}) })
} }
pub fn add_selection_set(&mut self, selections: impl Into<Arc<[Selection]>>) -> Operation { pub fn restore_selection_set(
let selections = selections.into(); &mut self,
let lamport_timestamp = self.lamport_clock.tick(); set_id: SelectionSetId,
selections: Arc<AnchorRangeMap<SelectionState>>,
) -> Result<Operation> {
let set = self
.selections
.get_mut(&set_id)
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
set.selections = selections.clone();
Ok(Operation::UpdateSelections {
set_id,
selections,
lamport_timestamp: self.lamport_clock.tick(),
})
}
pub fn add_selection_set<T: ToOffset>(&mut self, selections: &[Selection<T>]) -> Operation {
let selections = self.build_selection_anchor_range_map(selections);
let set_id = self.lamport_clock.tick();
self.selections.insert( self.selections.insert(
lamport_timestamp, set_id,
SelectionSet { SelectionSet {
id: set_id,
selections: selections.clone(), selections: selections.clone(),
active: false, active: false,
}, },
); );
Operation::UpdateSelections { Operation::UpdateSelections {
set_id: lamport_timestamp, set_id,
selections: Some(selections), selections,
lamport_timestamp, lamport_timestamp: set_id,
} }
} }
@ -1344,9 +1363,8 @@ impl Buffer {
self.selections self.selections
.remove(&set_id) .remove(&set_id)
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
Ok(Operation::UpdateSelections { Ok(Operation::RemoveSelections {
set_id, set_id,
selections: None,
lamport_timestamp: self.lamport_clock.tick(), lamport_timestamp: self.lamport_clock.tick(),
}) })
} }
@ -1419,9 +1437,9 @@ impl Buffer {
let new_selections = self.selections_from_ranges(ranges).unwrap(); let new_selections = self.selections_from_ranges(ranges).unwrap();
let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) {
self.add_selection_set(new_selections) self.add_selection_set(&new_selections)
} else { } else {
self.update_selection_set(*set_id.unwrap(), new_selections) self.update_selection_set(*set_id.unwrap(), &new_selections)
.unwrap() .unwrap()
}; };
ops.push(op); ops.push(op);
@ -1447,7 +1465,7 @@ impl Buffer {
ops ops
} }
fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection>> fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection<usize>>>
where where
I: IntoIterator<Item = Range<usize>>, I: IntoIterator<Item = Range<usize>>,
{ {
@ -1458,25 +1476,28 @@ impl Buffer {
let mut ranges = ranges.into_iter().collect::<Vec<_>>(); let mut ranges = ranges.into_iter().collect::<Vec<_>>();
ranges.sort_unstable_by_key(|range| range.start); ranges.sort_unstable_by_key(|range| range.start);
let mut selections = Vec::with_capacity(ranges.len()); let mut selections = Vec::<Selection<usize>>::with_capacity(ranges.len());
for range in ranges { for mut range in ranges {
let mut reversed = false;
if range.start > range.end { if range.start > range.end {
selections.push(Selection { reversed = true;
id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), std::mem::swap(&mut range.start, &mut range.end);
start: self.anchor_before(range.end),
end: self.anchor_before(range.start),
reversed: true,
goal: SelectionGoal::None,
});
} else {
selections.push(Selection {
id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst),
start: self.anchor_after(range.start),
end: self.anchor_before(range.end),
reversed: false,
goal: SelectionGoal::None,
});
} }
if let Some(selection) = selections.last_mut() {
if selection.end >= range.start {
selection.end = range.end;
continue;
}
}
selections.push(Selection {
id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst),
start: range.start,
end: range.end,
reversed,
goal: SelectionGoal::None,
});
} }
Ok(selections) Ok(selections)
} }
@ -1484,15 +1505,12 @@ impl Buffer {
pub fn selection_ranges<'a>(&'a self, set_id: SelectionSetId) -> Result<Vec<Range<usize>>> { pub fn selection_ranges<'a>(&'a self, set_id: SelectionSetId) -> Result<Vec<Range<usize>>> {
Ok(self Ok(self
.selection_set(set_id)? .selection_set(set_id)?
.selections .offset_selections(self)
.iter()
.map(move |selection| { .map(move |selection| {
let start = selection.start.to_offset(self);
let end = selection.end.to_offset(self);
if selection.reversed { if selection.reversed {
end..start selection.end..selection.start
} else { } else {
start..end selection.start..selection.end
} }
}) })
.collect()) .collect())
@ -2259,6 +2277,9 @@ impl Operation {
Operation::UpdateSelections { Operation::UpdateSelections {
lamport_timestamp, .. lamport_timestamp, ..
} => *lamport_timestamp, } => *lamport_timestamp,
Operation::RemoveSelections {
lamport_timestamp, ..
} => *lamport_timestamp,
Operation::SetActiveSelections { Operation::SetActiveSelections {
lamport_timestamp, .. lamport_timestamp, ..
} => *lamport_timestamp, } => *lamport_timestamp,
@ -2315,9 +2336,27 @@ impl<'a> Into<proto::Operation> for &'a Operation {
replica_id: set_id.replica_id as u32, replica_id: set_id.replica_id as u32,
local_timestamp: set_id.value, local_timestamp: set_id.value,
lamport_timestamp: lamport_timestamp.value, lamport_timestamp: lamport_timestamp.value,
set: selections.as_ref().map(|selections| proto::SelectionSet { version: selections.version().into(),
selections: selections.iter().map(Into::into).collect(), selections: selections
}), .raw_entries()
.iter()
.map(|(range, state)| proto::Selection {
id: state.id as u64,
start: range.start.0.to_proto(),
end: range.end.0.to_proto(),
reversed: state.reversed,
})
.collect(),
},
),
Operation::RemoveSelections {
set_id,
lamport_timestamp,
} => proto::operation::Variant::RemoveSelections(
proto::operation::RemoveSelections {
replica_id: set_id.replica_id as u32,
local_timestamp: set_id.value,
lamport_timestamp: lamport_timestamp.value,
}, },
), ),
Operation::SetActiveSelections { Operation::SetActiveSelections {
@ -2358,30 +2397,6 @@ impl<'a> Into<proto::operation::Edit> for &'a EditOperation {
} }
} }
impl<'a> Into<proto::Anchor> for &'a Anchor {
fn into(self) -> proto::Anchor {
proto::Anchor {
version: (&self.version).into(),
offset: self.full_offset.to_proto(),
bias: match self.bias {
Bias::Left => proto::anchor::Bias::Left as i32,
Bias::Right => proto::anchor::Bias::Right as i32,
},
}
}
}
impl<'a> Into<proto::Selection> for &'a Selection {
fn into(self) -> proto::Selection {
proto::Selection {
id: self.id as u64,
start: Some((&self.start).into()),
end: Some((&self.end).into()),
reversed: self.reversed,
}
}
}
impl TryFrom<proto::Operation> for Operation { impl TryFrom<proto::Operation> for Operation {
type Error = anyhow::Error; type Error = anyhow::Error;
@ -2424,16 +2439,23 @@ impl TryFrom<proto::Operation> for Operation {
}, },
}, },
proto::operation::Variant::UpdateSelections(message) => { proto::operation::Variant::UpdateSelections(message) => {
let selections: Option<Vec<Selection>> = if let Some(set) = message.set { let version = message.version.into();
Some( let entries = message
set.selections .selections
.into_iter() .iter()
.map(TryFrom::try_from) .map(|selection| {
.collect::<Result<_, _>>()?, let range = (FullOffset::from_proto(selection.start), Bias::Left)
) ..(FullOffset::from_proto(selection.end), Bias::Right);
} else { let state = SelectionState {
None id: selection.id as usize,
}; reversed: selection.reversed,
goal: SelectionGoal::None,
};
(range, state)
})
.collect();
let selections = AnchorRangeMap::from_raw(version, entries);
Operation::UpdateSelections { Operation::UpdateSelections {
set_id: clock::Lamport { set_id: clock::Lamport {
replica_id: message.replica_id as ReplicaId, replica_id: message.replica_id as ReplicaId,
@ -2443,7 +2465,19 @@ impl TryFrom<proto::Operation> for Operation {
replica_id: message.replica_id as ReplicaId, replica_id: message.replica_id as ReplicaId,
value: message.lamport_timestamp, value: message.lamport_timestamp,
}, },
selections: selections.map(Arc::from), selections: Arc::from(selections),
}
}
proto::operation::Variant::RemoveSelections(message) => {
Operation::RemoveSelections {
set_id: clock::Lamport {
replica_id: message.replica_id as ReplicaId,
value: message.local_timestamp,
},
lamport_timestamp: clock::Lamport {
replica_id: message.replica_id as ReplicaId,
value: message.lamport_timestamp,
},
} }
} }
proto::operation::Variant::SetActiveSelections(message) => { proto::operation::Variant::SetActiveSelections(message) => {
@ -2483,52 +2517,6 @@ impl From<proto::operation::Edit> for EditOperation {
} }
} }
impl TryFrom<proto::Anchor> for Anchor {
type Error = anyhow::Error;
fn try_from(message: proto::Anchor) -> Result<Self, Self::Error> {
let mut version = clock::Global::new();
for entry in message.version {
version.observe(clock::Local {
replica_id: entry.replica_id as ReplicaId,
value: entry.timestamp,
});
}
Ok(Self {
full_offset: FullOffset::from_proto(message.offset),
bias: if message.bias == proto::anchor::Bias::Left as i32 {
Bias::Left
} else if message.bias == proto::anchor::Bias::Right as i32 {
Bias::Right
} else {
Err(anyhow!("invalid anchor bias {}", message.bias))?
},
version,
})
}
}
impl TryFrom<proto::Selection> for Selection {
type Error = anyhow::Error;
fn try_from(selection: proto::Selection) -> Result<Self, Self::Error> {
Ok(Selection {
id: selection.id as usize,
start: selection
.start
.ok_or_else(|| anyhow!("missing selection start"))?
.try_into()?,
end: selection
.end
.ok_or_else(|| anyhow!("missing selection end"))?
.try_into()?,
reversed: selection.reversed,
goal: SelectionGoal::None,
})
}
}
pub trait ToOffset { pub trait ToOffset {
fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize; fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize;
@ -2582,6 +2570,12 @@ impl ToPoint for usize {
} }
} }
impl ToPoint for Point {
fn to_point<'a>(&self, _: impl Into<Content<'a>>) -> Point {
*self
}
}
pub trait FromAnchor { pub trait FromAnchor {
fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self; fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self;
} }

View File

@ -1,5 +1,7 @@
use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _}; use super::{AnchorRangeMap, Buffer, Content, FullOffset, Point, ToOffset, ToPoint};
use std::{cmp::Ordering, mem, ops::Range}; use rpc::proto;
use std::{cmp::Ordering, ops::Range, sync::Arc};
use sum_tree::Bias;
pub type SelectionSetId = clock::Lamport; pub type SelectionSetId = clock::Lamport;
pub type SelectionsVersion = usize; pub type SelectionsVersion = usize;
@ -12,44 +14,62 @@ pub enum SelectionGoal {
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Selection { pub struct Selection<T> {
pub id: usize, pub id: usize,
pub start: Anchor, pub start: T,
pub end: Anchor, pub end: T,
pub reversed: bool, pub reversed: bool,
pub goal: SelectionGoal, pub goal: SelectionGoal,
} }
impl Selection { #[derive(Clone, Debug, Eq, PartialEq)]
pub fn head(&self) -> &Anchor { pub struct SelectionSet {
pub id: SelectionSetId,
pub active: bool,
pub selections: Arc<AnchorRangeMap<SelectionState>>,
}
#[derive(Debug, Eq, PartialEq)]
pub struct SelectionState {
pub id: usize,
pub reversed: bool,
pub goal: SelectionGoal,
}
impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
pub fn is_empty(&self) -> bool {
self.start == self.end
}
pub fn head(&self) -> T {
if self.reversed { if self.reversed {
&self.start self.start
} else { } else {
&self.end self.end
} }
} }
pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) { pub fn set_head(&mut self, head: T) {
if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal { if head.cmp(&self.tail()) < Ordering::Equal {
if !self.reversed { if !self.reversed {
mem::swap(&mut self.start, &mut self.end); self.end = self.start;
self.reversed = true; self.reversed = true;
} }
self.start = cursor; self.start = head;
} else { } else {
if self.reversed { if self.reversed {
mem::swap(&mut self.start, &mut self.end); self.start = self.end;
self.reversed = false; self.reversed = false;
} }
self.end = cursor; self.end = head;
} }
} }
pub fn tail(&self) -> &Anchor { pub fn tail(&self) -> T {
if self.reversed { if self.reversed {
&self.end self.end
} else { } else {
&self.start self.start
} }
} }
@ -73,3 +93,89 @@ impl Selection {
} }
} }
} }
impl SelectionSet {
pub fn len(&self) -> usize {
self.selections.len()
}
pub fn offset_selections<'a>(
&'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl 'a + Iterator<Item = Selection<usize>> {
self.selections
.offset_ranges(content)
.map(|(range, state)| Selection {
id: state.id,
start: range.start,
end: range.end,
reversed: state.reversed,
goal: state.goal,
})
}
pub fn point_selections<'a>(
&'a self,
content: impl Into<Content<'a>> + 'a,
) -> impl 'a + Iterator<Item = Selection<Point>> {
self.selections
.point_ranges(content)
.map(|(range, state)| Selection {
id: state.id,
start: range.start,
end: range.end,
reversed: state.reversed,
goal: state.goal,
})
}
}
impl<'a> Into<proto::SelectionSet> for &'a SelectionSet {
fn into(self) -> proto::SelectionSet {
let version = self.selections.version();
let entries = self.selections.raw_entries();
proto::SelectionSet {
replica_id: self.id.replica_id as u32,
lamport_timestamp: self.id.value as u32,
is_active: self.active,
version: version.into(),
selections: entries
.iter()
.map(|(range, state)| proto::Selection {
id: state.id as u64,
start: range.start.0.to_proto(),
end: range.end.0.to_proto(),
reversed: state.reversed,
})
.collect(),
}
}
}
impl From<proto::SelectionSet> for SelectionSet {
fn from(set: proto::SelectionSet) -> Self {
Self {
id: clock::Lamport {
replica_id: set.replica_id as u16,
value: set.lamport_timestamp,
},
active: set.is_active,
selections: Arc::new(AnchorRangeMap::from_raw(
set.version.into(),
set.selections
.into_iter()
.map(|selection| {
let range = (FullOffset::from_proto(selection.start), Bias::Left)
..(FullOffset::from_proto(selection.end), Bias::Right);
let state = SelectionState {
id: selection.id as usize,
reversed: selection.reversed,
goal: SelectionGoal::None,
};
(range, state)
})
.collect(),
)),
}
}
}

View File

@ -408,7 +408,7 @@ fn test_history() {
let mut buffer = Buffer::new(0, 0, History::new("123456".into())); let mut buffer = Buffer::new(0, 0, History::new("123456".into()));
let set_id = if let Operation::UpdateSelections { set_id, .. } = let set_id = if let Operation::UpdateSelections { set_id, .. } =
buffer.add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap()) buffer.add_selection_set(&buffer.selections_from_ranges(vec![4..4]).unwrap())
{ {
set_id set_id
} else { } else {
@ -422,7 +422,7 @@ fn test_history() {
buffer.start_transaction_at(Some(set_id), now).unwrap(); buffer.start_transaction_at(Some(set_id), now).unwrap();
buffer buffer
.update_selection_set(set_id, buffer.selections_from_ranges(vec![1..3]).unwrap()) .update_selection_set(set_id, &buffer.selections_from_ranges(vec![1..3]).unwrap())
.unwrap(); .unwrap();
buffer.edit(vec![4..5], "e"); buffer.edit(vec![4..5], "e");
buffer.end_transaction_at(Some(set_id), now).unwrap(); buffer.end_transaction_at(Some(set_id), now).unwrap();
@ -432,7 +432,7 @@ fn test_history() {
now += buffer.history.group_interval + Duration::from_millis(1); now += buffer.history.group_interval + Duration::from_millis(1);
buffer.start_transaction_at(Some(set_id), now).unwrap(); buffer.start_transaction_at(Some(set_id), now).unwrap();
buffer buffer
.update_selection_set(set_id, buffer.selections_from_ranges(vec![2..2]).unwrap()) .update_selection_set(set_id, &buffer.selections_from_ranges(vec![2..2]).unwrap())
.unwrap(); .unwrap();
buffer.edit(vec![0..1], "a"); buffer.edit(vec![0..1], "a");
buffer.edit(vec![1..1], "b"); buffer.edit(vec![1..1], "b");

View File

@ -86,6 +86,12 @@ impl<'a> From<&'a Global> for Vec<rpc::proto::VectorClockEntry> {
} }
} }
impl From<Global> for Vec<rpc::proto::VectorClockEntry> {
fn from(version: Global) -> Self {
(&version).into()
}
}
impl Global { impl Global {
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()

File diff suppressed because it is too large Load Diff

View File

@ -790,9 +790,9 @@ impl Buffer {
for request in autoindent_requests { for request in autoindent_requests {
let old_to_new_rows = request let old_to_new_rows = request
.edited .edited
.to_points(&request.before_edit) .points(&request.before_edit)
.map(|point| point.row) .map(|point| point.row)
.zip(request.edited.to_points(&snapshot).map(|point| point.row)) .zip(request.edited.points(&snapshot).map(|point| point.row))
.collect::<BTreeMap<u32, u32>>(); .collect::<BTreeMap<u32, u32>>();
let mut old_suggestions = HashMap::<u32, u32>::default(); let mut old_suggestions = HashMap::<u32, u32>::default();
@ -853,7 +853,7 @@ impl Buffer {
if let Some(inserted) = request.inserted.as_ref() { if let Some(inserted) = request.inserted.as_ref() {
let inserted_row_ranges = contiguous_ranges( let inserted_row_ranges = contiguous_ranges(
inserted inserted
.to_point_ranges(&snapshot) .point_ranges(&snapshot)
.flat_map(|range| range.start.row..range.end.row + 1), .flat_map(|range| range.start.row..range.end.row + 1),
max_rows_between_yields, max_rows_between_yields,
); );
@ -901,31 +901,30 @@ impl Buffer {
for selection_set_id in &selection_set_ids { for selection_set_id in &selection_set_ids {
if let Ok(set) = self.selection_set(*selection_set_id) { if let Ok(set) = self.selection_set(*selection_set_id) {
let new_selections = set let new_selections = set
.selections .point_selections(&*self)
.iter()
.map(|selection| { .map(|selection| {
let start_point = selection.start.to_point(&self.text); if selection.start.column == 0 {
if start_point.column == 0 {
let end_point = selection.end.to_point(&self.text);
let delta = Point::new( let delta = Point::new(
0, 0,
indent_columns.get(&start_point.row).copied().unwrap_or(0), indent_columns
.get(&selection.start.row)
.copied()
.unwrap_or(0),
); );
if delta.column > 0 { if delta.column > 0 {
return Selection { return Selection {
id: selection.id, id: selection.id,
goal: selection.goal, goal: selection.goal,
reversed: selection.reversed, reversed: selection.reversed,
start: self start: selection.start + delta,
.anchor_at(start_point + delta, selection.start.bias), end: selection.end + delta,
end: self.anchor_at(end_point + delta, selection.end.bias),
}; };
} }
} }
selection.clone() selection
}) })
.collect::<Arc<[_]>>(); .collect::<Vec<_>>();
self.update_selection_set(*selection_set_id, new_selections, cx) self.update_selection_set(*selection_set_id, &new_selections, cx)
.unwrap(); .unwrap();
} }
} }
@ -1239,9 +1238,9 @@ impl Buffer {
cx.notify(); cx.notify();
} }
pub fn add_selection_set( pub fn add_selection_set<T: ToOffset>(
&mut self, &mut self,
selections: impl Into<Arc<[Selection]>>, selections: &[Selection<T>],
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> SelectionSetId { ) -> SelectionSetId {
let operation = self.text.add_selection_set(selections); let operation = self.text.add_selection_set(selections);
@ -1255,10 +1254,10 @@ impl Buffer {
} }
} }
pub fn update_selection_set( pub fn update_selection_set<T: ToOffset>(
&mut self, &mut self,
set_id: SelectionSetId, set_id: SelectionSetId,
selections: impl Into<Arc<[Selection]>>, selections: &[Selection<T>],
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Result<()> { ) -> Result<()> {
let operation = self.text.update_selection_set(set_id, selections)?; let operation = self.text.update_selection_set(set_id, selections)?;

View File

@ -274,24 +274,24 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx); let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
let selection_set_id = buffer.add_selection_set(Vec::new(), cx); let selection_set_id = buffer.add_selection_set::<usize>(&[], cx);
buffer.start_transaction(Some(selection_set_id)).unwrap(); buffer.start_transaction(Some(selection_set_id)).unwrap();
buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx); buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx);
buffer buffer
.update_selection_set( .update_selection_set(
selection_set_id, selection_set_id,
vec![ &[
Selection { Selection {
id: 0, id: 0,
start: buffer.anchor_before(Point::new(1, 0)), start: Point::new(1, 0),
end: buffer.anchor_before(Point::new(1, 0)), end: Point::new(1, 0),
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}, },
Selection { Selection {
id: 1, id: 1,
start: buffer.anchor_before(Point::new(4, 0)), start: Point::new(4, 0),
end: buffer.anchor_before(Point::new(4, 0)), end: Point::new(4, 0),
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}, },
@ -308,8 +308,7 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
let selection_ranges = buffer let selection_ranges = buffer
.selection_set(selection_set_id) .selection_set(selection_set_id)
.unwrap() .unwrap()
.selections .point_selections(&buffer)
.iter()
.map(|selection| selection.point_range(&buffer)) .map(|selection| selection.point_range(&buffer))
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -3410,7 +3410,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) { async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) {
use buffer::{Point, Selection, SelectionGoal, ToPoint}; use buffer::{Point, Selection, SelectionGoal};
use std::fs; use std::fs;
let initial_contents = "aaa\nbbbbb\nc\n"; let initial_contents = "aaa\nbbbbb\nc\n";
@ -3436,20 +3436,17 @@ mod tests {
.await .await
.unwrap(); .unwrap();
// Add a cursor at the start of each row. // Add a cursor on each row.
let selection_set_id = buffer.update(&mut cx, |buffer, cx| { let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
assert!(!buffer.is_dirty()); assert!(!buffer.is_dirty());
buffer.add_selection_set( buffer.add_selection_set(
(0..3) &(0..3)
.map(|row| { .map(|row| Selection {
let anchor = buffer.anchor_at(Point::new(row, 0), Bias::Right); id: row as usize,
Selection { start: Point::new(row, 1),
id: row as usize, end: Point::new(row, 1),
start: anchor.clone(), reversed: false,
end: anchor, goal: SelectionGoal::None,
reversed: false,
goal: SelectionGoal::None,
}
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
cx, cx,
@ -3469,7 +3466,7 @@ mod tests {
// contents are edited according to the diff between the old and new // contents are edited according to the diff between the old and new
// file contents. // file contents.
buffer buffer
.condition(&cx, |buffer, _| buffer.text() != initial_contents) .condition(&cx, |buffer, _| buffer.text() == new_contents)
.await; .await;
buffer.update(&mut cx, |buffer, _| { buffer.update(&mut cx, |buffer, _| {
@ -3477,18 +3474,18 @@ mod tests {
assert!(!buffer.is_dirty()); assert!(!buffer.is_dirty());
assert!(!buffer.has_conflict()); assert!(!buffer.has_conflict());
let set = buffer.selection_set(selection_set_id).unwrap(); let cursor_positions = buffer
let cursor_positions = set .selection_set(selection_set_id)
.selections .unwrap()
.iter() .point_selections(&*buffer)
.map(|selection| { .map(|selection| {
assert_eq!(selection.start, selection.end); assert_eq!(selection.start, selection.end);
selection.start.to_point(&*buffer) selection.start
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!( assert_eq!(
cursor_positions, cursor_positions,
&[Point::new(1, 0), Point::new(3, 0), Point::new(4, 0),] [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
); );
}); });

View File

@ -227,43 +227,31 @@ message Buffer {
uint64 id = 1; uint64 id = 1;
string content = 2; string content = 2;
repeated Operation.Edit history = 3; repeated Operation.Edit history = 3;
repeated SelectionSetSnapshot selections = 4; repeated SelectionSet selections = 4;
}
message SelectionSetSnapshot {
uint32 replica_id = 1;
uint32 local_timestamp = 2;
repeated Selection selections = 3;
bool is_active = 4;
} }
message SelectionSet { message SelectionSet {
repeated Selection selections = 1; uint32 replica_id = 1;
uint32 lamport_timestamp = 2;
bool is_active = 3;
repeated VectorClockEntry version = 4;
repeated Selection selections = 5;
} }
message Selection { message Selection {
uint64 id = 1; uint64 id = 1;
Anchor start = 2; uint64 start = 2;
Anchor end = 3; uint64 end = 3;
bool reversed = 4; bool reversed = 4;
} }
message Anchor {
repeated VectorClockEntry version = 1;
uint64 offset = 2;
Bias bias = 3;
enum Bias {
LEFT = 0;
Right = 1;
}
}
message Operation { message Operation {
oneof variant { oneof variant {
Edit edit = 1; Edit edit = 1;
Undo undo = 2; Undo undo = 2;
UpdateSelections update_selections = 3; UpdateSelections update_selections = 3;
SetActiveSelections set_active_selections = 4; RemoveSelections remove_selections = 4;
SetActiveSelections set_active_selections = 5;
} }
message Edit { message Edit {
@ -294,7 +282,14 @@ message Operation {
uint32 replica_id = 1; uint32 replica_id = 1;
uint32 local_timestamp = 2; uint32 local_timestamp = 2;
uint32 lamport_timestamp = 3; uint32 lamport_timestamp = 3;
SelectionSet set = 4; repeated VectorClockEntry version = 4;
repeated Selection selections = 5;
}
message RemoveSelections {
uint32 replica_id = 1;
uint32 local_timestamp = 2;
uint32 lamport_timestamp = 3;
} }
message SetActiveSelections { message SetActiveSelections {

View File

@ -509,7 +509,7 @@ where
} }
} }
pub struct FilterCursor<'a, F: FnMut(&T::Summary) -> bool, T: Item, D> { pub struct FilterCursor<'a, F, T: Item, D> {
cursor: Cursor<'a, T, D>, cursor: Cursor<'a, T, D>,
filter_node: F, filter_node: F,
} }