1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::id::CaretId;
5use crate::position::Position;
6use crate::range::Range;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)]
11pub struct Cursor {
12 pub id: CaretId,
13 pub anchor: Position,
14 pub head: Position,
15}
16
17impl Cursor {
18 #[must_use]
19 pub const fn new(id: CaretId, anchor: Position, head: Position) -> Self {
20 Self { id, anchor, head }
21 }
22
23 #[must_use]
24 pub fn at(id: CaretId, p: Position) -> Self {
25 Self {
26 id,
27 anchor: p,
28 head: p,
29 }
30 }
31
32 #[must_use]
34 pub fn range(self) -> Range {
35 Range::new(self.anchor, self.head).normalized()
36 }
37
38 #[must_use]
39 pub const fn is_caret(self) -> bool {
40 self.anchor.line == self.head.line && self.anchor.column == self.head.column
43 }
44
45 #[must_use]
47 pub const fn extend_to(self, p: Position) -> Self {
48 Self {
49 id: self.id,
50 anchor: self.anchor,
51 head: p,
52 }
53 }
54
55 #[must_use]
57 pub const fn collapse(self) -> Self {
58 Self {
59 id: self.id,
60 anchor: self.head,
61 head: self.head,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
83pub struct Cursors {
84 primary: Position,
85}
86
87impl Cursors {
88 #[must_use]
90 pub const fn single(p: Position) -> Self {
91 Self { primary: p }
92 }
93
94 #[must_use]
97 pub const fn primary(&self) -> Position {
98 self.primary
99 }
100
101 pub const fn set_primary(&mut self, p: Position) {
105 self.primary = p;
106 }
107
108 pub fn map_primary(&mut self, f: impl FnOnce(Position) -> Position) {
110 self.primary = f(self.primary);
111 }
112
113 #[must_use]
116 pub const fn count(&self) -> usize {
117 1
118 }
119}
120
121impl From<Position> for Cursors {
122 fn from(p: Position) -> Self {
123 Self::single(p)
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
130pub struct Selection {
131 carets: Vec<Cursor>,
132 primary: usize,
133}
134
135impl Selection {
136 #[must_use]
137 pub fn single(cursor: Cursor) -> Self {
138 Self {
139 carets: vec![cursor],
140 primary: 0,
141 }
142 }
143
144 #[must_use]
145 pub fn carets(&self) -> &[Cursor] {
146 &self.carets
147 }
148
149 #[must_use]
150 pub fn primary(&self) -> &Cursor {
151 &self.carets[self.primary]
152 }
153
154 pub fn add(&mut self, c: Cursor) {
155 self.carets.push(c);
156 }
157
158 pub fn map_primary(&mut self, f: impl FnOnce(Cursor) -> Cursor) {
159 let idx = self.primary;
160 self.carets[idx] = f(self.carets[idx]);
161 }
162
163 pub fn map_all(&mut self, mut f: impl FnMut(Cursor) -> Cursor) {
164 for c in &mut self.carets {
165 *c = f(*c);
166 }
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn caret_is_empty_range() {
176 let c = Cursor::at(CaretId(0), Position::new(1, 3));
177 assert!(c.is_caret());
178 assert!(c.range().is_empty());
179 }
180
181 #[test]
182 fn extend_grows_but_anchor_stays() {
183 let c = Cursor::at(CaretId(0), Position::new(0, 0));
184 let grown = c.extend_to(Position::new(0, 5));
185 assert_eq!(grown.anchor, Position::new(0, 0));
186 assert_eq!(grown.head, Position::new(0, 5));
187 }
188
189 #[test]
190 fn collapse_makes_caret() {
191 let c = Cursor::new(CaretId(0), Position::new(0, 0), Position::new(0, 5));
192 let collapsed = c.collapse();
193 assert!(collapsed.is_caret());
194 assert_eq!(collapsed.head, Position::new(0, 5));
195 }
196
197 #[test]
198 fn primary_is_first_by_default() {
199 let s = Selection::single(Cursor::at(CaretId(0), Position::new(3, 2)));
200 assert_eq!(s.primary().head, Position::new(3, 2));
201 }
202
203 #[test]
206 fn cursors_single_round_trips_position() {
207 let c = Cursors::single(Position::new(2, 5));
208 assert_eq!(c.primary(), Position::new(2, 5));
209 assert_eq!(c.count(), 1);
210 }
211
212 #[test]
213 fn cursors_set_primary_is_the_write_path() {
214 let mut c = Cursors::default();
215 assert_eq!(c.primary(), Position::ZERO);
216 c.set_primary(Position::new(4, 1));
217 assert_eq!(c.primary(), Position::new(4, 1));
218 }
219
220 #[test]
221 fn cursors_map_primary_transforms_in_place() {
222 let mut c = Cursors::single(Position::new(1, 1));
223 c.map_primary(|p| Position::new(p.line + 1, p.column + 2));
224 assert_eq!(c.primary(), Position::new(2, 3));
225 }
226
227 #[test]
228 fn cursors_from_position() {
229 let c: Cursors = Position::new(7, 7).into();
230 assert_eq!(c.primary(), Position::new(7, 7));
231 }
232}