1use super::{AnchorRangeMap, Buffer, Content, Point, ToOffset, ToPoint};
2use std::{cmp::Ordering, ops::Range, sync::Arc};
3
4pub type SelectionSetId = clock::Lamport;
5pub type SelectionsVersion = usize;
6
7#[derive(Copy, Clone, Debug, Eq, PartialEq)]
8pub enum SelectionGoal {
9 None,
10 Column(u32),
11 ColumnRange { start: u32, end: u32 },
12}
13
14#[derive(Clone, Debug, Eq, 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
23#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct SelectionSet {
25 pub id: SelectionSetId,
26 pub active: bool,
27 pub selections: Arc<AnchorRangeMap<SelectionState>>,
28}
29
30#[derive(Debug, Eq, PartialEq)]
31pub struct SelectionState {
32 pub id: usize,
33 pub reversed: bool,
34 pub goal: SelectionGoal,
35}
36
37impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
38 pub fn is_empty(&self) -> bool {
39 self.start == self.end
40 }
41
42 pub fn head(&self) -> T {
43 if self.reversed {
44 self.start
45 } else {
46 self.end
47 }
48 }
49
50 pub fn set_head(&mut self, head: T) {
51 if head.cmp(&self.tail()) < Ordering::Equal {
52 if !self.reversed {
53 self.end = self.start;
54 self.reversed = true;
55 }
56 self.start = head;
57 } else {
58 if self.reversed {
59 self.start = self.end;
60 self.reversed = false;
61 }
62 self.end = head;
63 }
64 }
65
66 pub fn tail(&self) -> T {
67 if self.reversed {
68 self.end
69 } else {
70 self.start
71 }
72 }
73
74 pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
75 let start = self.start.to_point(buffer);
76 let end = self.end.to_point(buffer);
77 if self.reversed {
78 end..start
79 } else {
80 start..end
81 }
82 }
83
84 pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
85 let start = self.start.to_offset(buffer);
86 let end = self.end.to_offset(buffer);
87 if self.reversed {
88 end..start
89 } else {
90 start..end
91 }
92 }
93}
94
95impl SelectionSet {
96 pub fn len(&self) -> usize {
97 self.selections.len()
98 }
99
100 pub fn offset_selections<'a>(
101 &'a self,
102 content: impl Into<Content<'a>> + 'a,
103 ) -> impl 'a + Iterator<Item = Selection<usize>> {
104 self.selections
105 .offset_ranges(content)
106 .map(|(range, state)| Selection {
107 id: state.id,
108 start: range.start,
109 end: range.end,
110 reversed: state.reversed,
111 goal: state.goal,
112 })
113 }
114
115 pub fn point_selections<'a>(
116 &'a self,
117 content: impl Into<Content<'a>> + 'a,
118 ) -> impl 'a + Iterator<Item = Selection<Point>> {
119 self.selections
120 .point_ranges(content)
121 .map(|(range, state)| Selection {
122 id: state.id,
123 start: range.start,
124 end: range.end,
125 reversed: state.reversed,
126 goal: state.goal,
127 })
128 }
129}