selection.rs

  1use crate::Anchor;
  2use crate::{rope::TextDimension, BufferSnapshot, ToOffset, ToPoint};
  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<[Selection<Anchor>]>,
 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: Clone> Selection<T> {
 40    pub fn head(&self) -> T {
 41        if self.reversed {
 42            self.start.clone()
 43        } else {
 44            self.end.clone()
 45        }
 46    }
 47
 48    pub fn tail(&self) -> T {
 49        if self.reversed {
 50            self.end.clone()
 51        } else {
 52            self.start.clone()
 53        }
 54    }
 55}
 56
 57impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
 58    pub fn is_empty(&self) -> bool {
 59        self.start == self.end
 60    }
 61
 62    pub fn set_head(&mut self, head: T) {
 63        if head.cmp(&self.tail()) < Ordering::Equal {
 64            if !self.reversed {
 65                self.end = self.start;
 66                self.reversed = true;
 67            }
 68            self.start = head;
 69        } else {
 70            if self.reversed {
 71                self.start = self.end;
 72                self.reversed = false;
 73            }
 74            self.end = head;
 75        }
 76    }
 77}
 78
 79impl Selection<Anchor> {
 80    pub fn resolve<'a, D: 'a + TextDimension>(
 81        &'a self,
 82        snapshot: &'a BufferSnapshot,
 83    ) -> Selection<D> {
 84        Selection {
 85            id: self.id,
 86            start: snapshot.summary_for_anchor(&self.start),
 87            end: snapshot.summary_for_anchor(&self.end),
 88            reversed: self.reversed,
 89            goal: self.goal,
 90        }
 91    }
 92}
 93
 94impl SelectionSet {
 95    pub fn len(&self) -> usize {
 96        self.selections.len()
 97    }
 98
 99    pub fn selections<'a, D>(
100        &'a self,
101        snapshot: &'a BufferSnapshot,
102    ) -> impl 'a + Iterator<Item = Selection<D>>
103    where
104        D: TextDimension,
105    {
106        let anchors = self
107            .selections
108            .iter()
109            .flat_map(|selection| [&selection.start, &selection.end].into_iter());
110        let mut positions = snapshot.summaries_for_anchors::<D, _>(anchors);
111        self.selections.iter().map(move |selection| Selection {
112            start: positions.next().unwrap(),
113            end: positions.next().unwrap(),
114            goal: selection.goal,
115            reversed: selection.reversed,
116            id: selection.id,
117        })
118    }
119
120    pub fn intersecting_selections<'a, D, I>(
121        &'a self,
122        range: Range<(I, Bias)>,
123        snapshot: &'a BufferSnapshot,
124    ) -> impl 'a + Iterator<Item = Selection<D>>
125    where
126        D: TextDimension,
127        I: 'a + ToOffset,
128    {
129        let start = snapshot.anchor_at(range.start.0, range.start.1);
130        let end = snapshot.anchor_at(range.end.0, range.end.1);
131        let start_ix = match self
132            .selections
133            .binary_search_by(|probe| probe.end.cmp(&start, snapshot).unwrap())
134        {
135            Ok(ix) | Err(ix) => ix,
136        };
137        let end_ix = match self
138            .selections
139            .binary_search_by(|probe| probe.start.cmp(&end, snapshot).unwrap())
140        {
141            Ok(ix) | Err(ix) => ix,
142        };
143        self.selections[start_ix..end_ix]
144            .iter()
145            .map(|s| s.resolve(snapshot))
146    }
147
148    pub fn oldest_selection<'a, D>(&'a self, snapshot: &'a BufferSnapshot) -> Option<Selection<D>>
149    where
150        D: TextDimension,
151    {
152        self.selections
153            .iter()
154            .min_by_key(|s| s.id)
155            .map(|s| s.resolve(snapshot))
156    }
157
158    pub fn newest_selection<'a, D>(&'a self, snapshot: &'a BufferSnapshot) -> Option<Selection<D>>
159    where
160        D: TextDimension,
161    {
162        self.selections
163            .iter()
164            .max_by_key(|s| s.id)
165            .map(|s| s.resolve(snapshot))
166    }
167}