selection.rs

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