selection.rs

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