selection.rs

  1use crate::{Anchor, BufferSnapshot, TextDimension};
  2use std::cmp::Ordering;
  3use std::ops::Range;
  4
  5#[derive(Copy, Clone, Debug, PartialEq)]
  6pub enum SelectionGoal {
  7    None,
  8    HorizontalPosition(f32),
  9    HorizontalRange { start: f32, end: f32 },
 10    WrappedHorizontalPosition((u32, f32)),
 11    WrappedHorizontalRange { start: (u32, f32), end: (u32, f32) },
 12}
 13
 14#[derive(Clone, Debug, PartialEq)]
 15pub struct Selection<T> {
 16    pub id: usize,
 17    pub start: T,
 18    pub end: T,
 19    pub reversed: bool,
 20    pub goal: SelectionGoal,
 21}
 22
 23impl Default for SelectionGoal {
 24    fn default() -> Self {
 25        Self::None
 26    }
 27}
 28
 29impl<T: Clone> Selection<T> {
 30    pub fn head(&self) -> T {
 31        if self.reversed {
 32            self.start.clone()
 33        } else {
 34            self.end.clone()
 35        }
 36    }
 37
 38    pub fn tail(&self) -> T {
 39        if self.reversed {
 40            self.end.clone()
 41        } else {
 42            self.start.clone()
 43        }
 44    }
 45
 46    pub fn map<F, S>(&self, f: F) -> Selection<S>
 47    where
 48        F: Fn(T) -> S,
 49    {
 50        Selection::<S> {
 51            id: self.id,
 52            start: f(self.start.clone()),
 53            end: f(self.end.clone()),
 54            reversed: self.reversed,
 55            goal: self.goal,
 56        }
 57    }
 58
 59    pub fn collapse_to(&mut self, point: T, new_goal: SelectionGoal) {
 60        self.start = point.clone();
 61        self.end = point;
 62        self.goal = new_goal;
 63        self.reversed = false;
 64    }
 65}
 66
 67impl<T: Copy + Ord> Selection<T> {
 68    pub fn is_empty(&self) -> bool {
 69        self.start == self.end
 70    }
 71
 72    pub fn set_head(&mut self, head: T, new_goal: SelectionGoal) {
 73        if head.cmp(&self.tail()) < Ordering::Equal {
 74            if !self.reversed {
 75                self.end = self.start;
 76                self.reversed = true;
 77            }
 78            self.start = head;
 79        } else {
 80            if self.reversed {
 81                self.start = self.end;
 82                self.reversed = false;
 83            }
 84            self.end = head;
 85        }
 86        self.goal = new_goal;
 87    }
 88
 89    pub fn range(&self) -> Range<T> {
 90        self.start..self.end
 91    }
 92}
 93
 94impl Selection<usize> {
 95    #[cfg(feature = "test-support")]
 96    pub fn from_offset(offset: usize) -> Self {
 97        Selection {
 98            id: 0,
 99            start: offset,
100            end: offset,
101            goal: SelectionGoal::None,
102            reversed: false,
103        }
104    }
105
106    pub fn equals(&self, offset_range: &Range<usize>) -> bool {
107        self.start == offset_range.start && self.end == offset_range.end
108    }
109}
110
111impl Selection<Anchor> {
112    pub fn resolve<'a, D: 'a + TextDimension>(
113        &'a self,
114        snapshot: &'a BufferSnapshot,
115    ) -> Selection<D> {
116        Selection {
117            id: self.id,
118            start: snapshot.summary_for_anchor(&self.start),
119            end: snapshot.summary_for_anchor(&self.end),
120            reversed: self.reversed,
121            goal: self.goal,
122        }
123    }
124}