selection.rs

  1use crate::{AnchorRangeMap, Buffer, Content, Point, ToOffset, ToPoint};
  2use rpc::proto;
  3use std::{cmp::Ordering, 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<T> {
 18    pub id: usize,
 19    pub start: T,
 20    pub end: T,
 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<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
 40    pub fn head(&self) -> T {
 41        if self.reversed {
 42            self.start
 43        } else {
 44            self.end
 45        }
 46    }
 47
 48    pub fn set_head(&mut self, head: T) {
 49        if head.cmp(&self.tail()) < Ordering::Equal {
 50            if !self.reversed {
 51                self.end = self.start;
 52                self.reversed = true;
 53            }
 54            self.start = head;
 55        } else {
 56            if self.reversed {
 57                self.start = self.end;
 58                self.reversed = false;
 59            }
 60            self.end = head;
 61        }
 62    }
 63
 64    pub fn tail(&self) -> T {
 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 SelectionSet {
 94    pub fn len(&self) -> usize {
 95        self.selections.len()
 96    }
 97
 98    pub fn offset_selections<'a>(
 99        &'a self,
100        content: impl Into<Content<'a>> + 'a,
101    ) -> impl 'a + Iterator<Item = Selection<usize>> {
102        self.selections
103            .offset_ranges(content)
104            .map(|(range, state)| Selection {
105                id: state.id,
106                start: range.start,
107                end: range.end,
108                reversed: state.reversed,
109                goal: state.goal,
110            })
111    }
112
113    pub fn point_selections<'a>(
114        &'a self,
115        content: impl Into<Content<'a>> + 'a,
116    ) -> impl 'a + Iterator<Item = Selection<Point>> {
117        self.selections
118            .point_ranges(content)
119            .map(|(range, state)| Selection {
120                id: state.id,
121                start: range.start,
122                end: range.end,
123                reversed: state.reversed,
124                goal: state.goal,
125            })
126    }
127}
128
129impl<'a> Into<proto::SelectionSet> for &'a SelectionSet {
130    fn into(self) -> proto::SelectionSet {
131        let version = self.selections.version();
132        let entries = self.selections.raw_entries();
133        proto::SelectionSet {
134            replica_id: self.id.replica_id as u32,
135            lamport_timestamp: self.id.value as u32,
136            is_active: self.active,
137            version: version.into(),
138            selections: entries
139                .iter()
140                .map(|(range, state)| proto::Selection {
141                    id: state.id as u64,
142                    start: range.start.0 as u64,
143                    end: range.end.0 as u64,
144                    reversed: state.reversed,
145                })
146                .collect(),
147        }
148    }
149}
150
151impl From<proto::SelectionSet> for SelectionSet {
152    fn from(set: proto::SelectionSet) -> Self {
153        Self {
154            id: clock::Lamport {
155                replica_id: set.replica_id as u16,
156                value: set.lamport_timestamp,
157            },
158            active: set.is_active,
159            selections: Arc::new(AnchorRangeMap::from_raw(
160                set.version.into(),
161                set.selections
162                    .into_iter()
163                    .map(|selection| {
164                        let range = (selection.start as usize, Bias::Left)
165                            ..(selection.end as usize, Bias::Right);
166                        let state = SelectionState {
167                            id: selection.id as usize,
168                            reversed: selection.reversed,
169                            goal: SelectionGoal::None,
170                        };
171                        (range, state)
172                    })
173                    .collect(),
174            )),
175        }
176    }
177}