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}