selection.rs

  1use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _};
  2use anyhow::anyhow;
  3use rpc::proto;
  4use std::{
  5    cmp::Ordering,
  6    convert::{TryFrom, TryInto},
  7    mem,
  8    ops::Range,
  9    sync::Arc,
 10};
 11
 12pub type SelectionSetId = clock::Lamport;
 13pub type SelectionsVersion = usize;
 14
 15#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 16pub enum SelectionGoal {
 17    None,
 18    Column(u32),
 19    ColumnRange { start: u32, end: u32 },
 20}
 21
 22#[derive(Clone, Debug, Eq, PartialEq)]
 23pub struct Selection {
 24    pub id: usize,
 25    pub start: Anchor,
 26    pub end: Anchor,
 27    pub reversed: bool,
 28    pub goal: SelectionGoal,
 29}
 30
 31#[derive(Clone, Debug, Eq, PartialEq)]
 32pub struct SelectionSet {
 33    pub id: SelectionSetId,
 34    pub active: bool,
 35    pub selections: Arc<[Selection]>,
 36}
 37
 38impl Selection {
 39    pub fn head(&self) -> &Anchor {
 40        if self.reversed {
 41            &self.start
 42        } else {
 43            &self.end
 44        }
 45    }
 46
 47    pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
 48        if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
 49            if !self.reversed {
 50                mem::swap(&mut self.start, &mut self.end);
 51                self.reversed = true;
 52            }
 53            self.start = cursor;
 54        } else {
 55            if self.reversed {
 56                mem::swap(&mut self.start, &mut self.end);
 57                self.reversed = false;
 58            }
 59            self.end = cursor;
 60        }
 61    }
 62
 63    pub fn tail(&self) -> &Anchor {
 64        if self.reversed {
 65            &self.end
 66        } else {
 67            &self.start
 68        }
 69    }
 70
 71    pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
 72        let start = self.start.to_point(buffer);
 73        let end = self.end.to_point(buffer);
 74        if self.reversed {
 75            end..start
 76        } else {
 77            start..end
 78        }
 79    }
 80
 81    pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
 82        let start = self.start.to_offset(buffer);
 83        let end = self.end.to_offset(buffer);
 84        if self.reversed {
 85            end..start
 86        } else {
 87            start..end
 88        }
 89    }
 90}
 91
 92impl<'a> Into<proto::Selection> for &'a Selection {
 93    fn into(self) -> proto::Selection {
 94        proto::Selection {
 95            id: self.id as u64,
 96            start: Some((&self.start).into()),
 97            end: Some((&self.end).into()),
 98            reversed: self.reversed,
 99        }
100    }
101}
102
103impl TryFrom<proto::Selection> for Selection {
104    type Error = anyhow::Error;
105
106    fn try_from(selection: proto::Selection) -> Result<Self, Self::Error> {
107        Ok(Selection {
108            id: selection.id as usize,
109            start: selection
110                .start
111                .ok_or_else(|| anyhow!("missing selection start"))?
112                .try_into()?,
113            end: selection
114                .end
115                .ok_or_else(|| anyhow!("missing selection end"))?
116                .try_into()?,
117            reversed: selection.reversed,
118            goal: SelectionGoal::None,
119        })
120    }
121}
122
123impl TryFrom<proto::SelectionSet> for SelectionSet {
124    type Error = anyhow::Error;
125
126    fn try_from(set: proto::SelectionSet) -> Result<Self, Self::Error> {
127        Ok(Self {
128            id: clock::Lamport {
129                replica_id: set.replica_id as u16,
130                value: set.lamport_timestamp,
131            },
132            active: set.is_active,
133            selections: Arc::from(
134                set.selections
135                    .into_iter()
136                    .map(TryInto::try_into)
137                    .collect::<Result<Vec<Selection>, _>>()?,
138            ),
139        })
140    }
141}