selection.rs

  1use crate::{rope::TextDimension, AnchorRangeMap, BufferSnapshot, ToOffset, ToPoint};
  2use std::{cmp::Ordering, ops::Range, sync::Arc};
  3use sum_tree::Bias;
  4
  5pub type SelectionSetId = clock::Lamport;
  6pub type SelectionsVersion = usize;
  7
  8#[derive(Copy, Clone, Debug, Eq, PartialEq)]
  9pub enum SelectionGoal {
 10    None,
 11    Column(u32),
 12    ColumnRange { start: u32, end: u32 },
 13}
 14
 15#[derive(Clone, Debug, Eq, PartialEq)]
 16pub struct Selection<T> {
 17    pub id: usize,
 18    pub start: T,
 19    pub end: T,
 20    pub reversed: bool,
 21    pub goal: SelectionGoal,
 22}
 23
 24#[derive(Clone, Debug, Eq, PartialEq)]
 25pub struct SelectionSet {
 26    pub id: SelectionSetId,
 27    pub active: bool,
 28    pub selections: Arc<AnchorRangeMap<SelectionState>>,
 29}
 30
 31#[derive(Debug, Eq, PartialEq)]
 32pub struct SelectionState {
 33    pub id: usize,
 34    pub reversed: bool,
 35    pub goal: SelectionGoal,
 36}
 37
 38impl<T: Clone> Selection<T> {
 39    pub fn head(&self) -> T {
 40        if self.reversed {
 41            self.start.clone()
 42        } else {
 43            self.end.clone()
 44        }
 45    }
 46
 47    pub fn tail(&self) -> T {
 48        if self.reversed {
 49            self.end.clone()
 50        } else {
 51            self.start.clone()
 52        }
 53    }
 54}
 55
 56impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
 57    pub fn is_empty(&self) -> bool {
 58        self.start == self.end
 59    }
 60
 61    pub fn set_head(&mut self, head: T) {
 62        if head.cmp(&self.tail()) < Ordering::Equal {
 63            if !self.reversed {
 64                self.end = self.start;
 65                self.reversed = true;
 66            }
 67            self.start = head;
 68        } else {
 69            if self.reversed {
 70                self.start = self.end;
 71                self.reversed = false;
 72            }
 73            self.end = head;
 74        }
 75    }
 76}
 77
 78impl SelectionSet {
 79    pub fn len(&self) -> usize {
 80        self.selections.len()
 81    }
 82
 83    pub fn selections<'a, D>(
 84        &'a self,
 85        content: &'a BufferSnapshot,
 86    ) -> impl 'a + Iterator<Item = Selection<D>>
 87    where
 88        D: TextDimension,
 89    {
 90        self.selections
 91            .ranges(content)
 92            .map(|(range, state)| Selection {
 93                id: state.id,
 94                start: range.start,
 95                end: range.end,
 96                reversed: state.reversed,
 97                goal: state.goal,
 98            })
 99    }
100
101    pub fn intersecting_selections<'a, D, I>(
102        &'a self,
103        range: Range<(I, Bias)>,
104        content: &'a BufferSnapshot,
105    ) -> impl 'a + Iterator<Item = Selection<D>>
106    where
107        D: TextDimension,
108        I: 'a + ToOffset,
109    {
110        self.selections
111            .intersecting_ranges(range, content)
112            .map(|(range, state)| Selection {
113                id: state.id,
114                start: range.start,
115                end: range.end,
116                reversed: state.reversed,
117                goal: state.goal,
118            })
119    }
120
121    pub fn oldest_selection<'a, D>(&'a self, content: &'a BufferSnapshot) -> Option<Selection<D>>
122    where
123        D: TextDimension,
124    {
125        self.selections
126            .min_by_key(content, |selection| selection.id)
127            .map(|(range, state)| Selection {
128                id: state.id,
129                start: range.start,
130                end: range.end,
131                reversed: state.reversed,
132                goal: state.goal,
133            })
134    }
135
136    pub fn newest_selection<'a, D>(&'a self, content: &'a BufferSnapshot) -> Option<Selection<D>>
137    where
138        D: TextDimension,
139    {
140        self.selections
141            .max_by_key(content, |selection| selection.id)
142            .map(|(range, state)| Selection {
143                id: state.id,
144                start: range.start,
145                end: range.end,
146                reversed: state.reversed,
147                goal: state.goal,
148            })
149    }
150}