2021-10-04 14:50:12 +00:00
|
|
|
use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _};
|
2021-10-22 18:46:02 +00:00
|
|
|
use anyhow::anyhow;
|
|
|
|
use rpc::proto;
|
|
|
|
use std::{
|
|
|
|
cmp::Ordering,
|
|
|
|
convert::{TryFrom, TryInto},
|
|
|
|
mem,
|
|
|
|
ops::Range,
|
|
|
|
sync::Arc,
|
|
|
|
};
|
2021-04-09 16:45:13 +00:00
|
|
|
|
2021-10-04 12:34:02 +00:00
|
|
|
pub type SelectionSetId = clock::Lamport;
|
2021-04-09 16:45:13 +00:00
|
|
|
pub type SelectionsVersion = usize;
|
|
|
|
|
2021-05-10 13:06:07 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
|
|
pub enum SelectionGoal {
|
|
|
|
None,
|
|
|
|
Column(u32),
|
|
|
|
ColumnRange { start: u32, end: u32 },
|
|
|
|
}
|
|
|
|
|
2021-04-09 16:45:13 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
pub struct Selection {
|
2021-05-10 14:10:41 +00:00
|
|
|
pub id: usize,
|
2021-04-09 16:45:13 +00:00
|
|
|
pub start: Anchor,
|
|
|
|
pub end: Anchor,
|
|
|
|
pub reversed: bool,
|
2021-05-10 13:06:07 +00:00
|
|
|
pub goal: SelectionGoal,
|
2021-04-09 16:45:13 +00:00
|
|
|
}
|
|
|
|
|
2021-10-22 07:56:47 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
pub struct SelectionSet {
|
2021-10-22 18:46:02 +00:00
|
|
|
pub id: SelectionSetId,
|
2021-10-22 07:56:47 +00:00
|
|
|
pub active: bool,
|
2021-10-22 18:46:02 +00:00
|
|
|
pub selections: Arc<[Selection]>,
|
2021-10-22 07:56:47 +00:00
|
|
|
}
|
|
|
|
|
2021-04-09 16:45:13 +00:00
|
|
|
impl Selection {
|
|
|
|
pub fn head(&self) -> &Anchor {
|
|
|
|
if self.reversed {
|
|
|
|
&self.start
|
|
|
|
} else {
|
|
|
|
&self.end
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
|
|
|
|
if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
|
|
|
|
if !self.reversed {
|
|
|
|
mem::swap(&mut self.start, &mut self.end);
|
|
|
|
self.reversed = true;
|
|
|
|
}
|
|
|
|
self.start = cursor;
|
|
|
|
} else {
|
|
|
|
if self.reversed {
|
|
|
|
mem::swap(&mut self.start, &mut self.end);
|
|
|
|
self.reversed = false;
|
|
|
|
}
|
|
|
|
self.end = cursor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn tail(&self) -> &Anchor {
|
|
|
|
if self.reversed {
|
|
|
|
&self.end
|
|
|
|
} else {
|
|
|
|
&self.start
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-28 18:07:30 +00:00
|
|
|
pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
|
2021-05-17 20:21:49 +00:00
|
|
|
let start = self.start.to_point(buffer);
|
|
|
|
let end = self.end.to_point(buffer);
|
2021-04-09 16:45:13 +00:00
|
|
|
if self.reversed {
|
|
|
|
end..start
|
|
|
|
} else {
|
|
|
|
start..end
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-28 18:07:30 +00:00
|
|
|
pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
|
|
|
|
let start = self.start.to_offset(buffer);
|
|
|
|
let end = self.end.to_offset(buffer);
|
|
|
|
if self.reversed {
|
|
|
|
end..start
|
|
|
|
} else {
|
|
|
|
start..end
|
|
|
|
}
|
|
|
|
}
|
2021-04-09 16:45:13 +00:00
|
|
|
}
|
2021-10-22 07:56:47 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-22 18:46:02 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<proto::SelectionSet> for SelectionSet {
|
|
|
|
type Error = anyhow::Error;
|
|
|
|
|
|
|
|
fn try_from(set: proto::SelectionSet) -> Result<Self, Self::Error> {
|
|
|
|
Ok(Self {
|
|
|
|
id: clock::Lamport {
|
|
|
|
replica_id: set.replica_id as u16,
|
|
|
|
value: set.lamport_timestamp,
|
|
|
|
},
|
|
|
|
active: set.is_active,
|
|
|
|
selections: Arc::from(
|
|
|
|
set.selections
|
|
|
|
.into_iter()
|
|
|
|
.map(TryInto::try_into)
|
|
|
|
.collect::<Result<Vec<Selection>, _>>()?,
|
|
|
|
),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|