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: ToOffset + ToPoint + Copy + Ord> Selection<T> {
40 pub fn is_empty(&self) -> bool {
41 self.start == self.end
42 }
43
44 pub fn head(&self) -> T {
45 if self.reversed {
46 self.start
47 } else {
48 self.end
49 }
50 }
51
52 pub fn set_head(&mut self, head: T) {
53 if head.cmp(&self.tail()) < Ordering::Equal {
54 if !self.reversed {
55 self.end = self.start;
56 self.reversed = true;
57 }
58 self.start = head;
59 } else {
60 if self.reversed {
61 self.start = self.end;
62 self.reversed = false;
63 }
64 self.end = head;
65 }
66 }
67
68 pub fn tail(&self) -> T {
69 if self.reversed {
70 self.end
71 } else {
72 self.start
73 }
74 }
75
76 pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
77 let start = self.start.to_point(buffer);
78 let end = self.end.to_point(buffer);
79 if self.reversed {
80 end..start
81 } else {
82 start..end
83 }
84 }
85
86 pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
87 let start = self.start.to_offset(buffer);
88 let end = self.end.to_offset(buffer);
89 if self.reversed {
90 end..start
91 } else {
92 start..end
93 }
94 }
95}
96
97impl SelectionSet {
98 pub fn len(&self) -> usize {
99 self.selections.len()
100 }
101
102 pub fn selections<'a, D, C>(&'a self, content: C) -> impl 'a + Iterator<Item = Selection<D>>
103 where
104 D: 'a + TextDimension<'a>,
105 C: 'a + Into<Content<'a>>,
106 {
107 self.selections
108 .ranges(content)
109 .map(|(range, state)| Selection {
110 id: state.id,
111 start: range.start,
112 end: range.end,
113 reversed: state.reversed,
114 goal: state.goal,
115 })
116 }
117}