selection.rs

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