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