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 offset_selections<'a>(
 95        &'a self,
 96        content: impl Into<Content<'a>> + 'a,
 97    ) -> impl 'a + Iterator<Item = Selection<usize>> {
 98        self.selections
 99            .offset_ranges(content)
100            .map(|(range, state)| Selection {
101                id: state.id,
102                start: range.start,
103                end: range.end,
104                reversed: state.reversed,
105                goal: state.goal,
106            })
107    }
108
109    pub fn point_selections<'a>(
110        &'a self,
111        content: impl Into<Content<'a>> + 'a,
112    ) -> impl 'a + Iterator<Item = Selection<Point>> {
113        self.selections
114            .point_ranges(content)
115            .map(|(range, state)| Selection {
116                id: state.id,
117                start: range.start,
118                end: range.end,
119                reversed: state.reversed,
120                goal: state.goal,
121            })
122    }
123}
124
125impl<'a> Into<proto::SelectionSet> for &'a SelectionSet {
126    fn into(self) -> proto::SelectionSet {
127        let version = self.selections.version();
128        let entries = self.selections.raw_entries();
129        proto::SelectionSet {
130            replica_id: self.id.replica_id as u32,
131            lamport_timestamp: self.id.value as u32,
132            is_active: self.active,
133            version: version.into(),
134            selections: entries
135                .iter()
136                .map(|(range, state)| proto::Selection {
137                    id: state.id as u64,
138                    start: range.start.0 as u64,
139                    end: range.end.0 as u64,
140                    reversed: state.reversed,
141                })
142                .collect(),
143        }
144    }
145}
146
147impl From<proto::SelectionSet> for SelectionSet {
148    fn from(set: proto::SelectionSet) -> Self {
149        Self {
150            id: clock::Lamport {
151                replica_id: set.replica_id as u16,
152                value: set.lamport_timestamp,
153            },
154            active: set.is_active,
155            selections: Arc::new(AnchorRangeMap::from_raw(
156                set.version.into(),
157                set.selections
158                    .into_iter()
159                    .map(|selection| {
160                        let range = (selection.start as usize, Bias::Left)
161                            ..(selection.end as usize, Bias::Right);
162                        let state = SelectionState {
163                            id: selection.id as usize,
164                            reversed: selection.reversed,
165                            goal: SelectionGoal::None,
166                        };
167                        (range, state)
168                    })
169                    .collect(),
170            )),
171        }
172    }
173}