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}