1use {
2 crate::{
3 layout::Layout,
4 str::StrExt,
5 text::{Edit, Length, Position},
6 },
7 std::{ops, ops::Deref, slice::Iter},
8};
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Hash, Eq)]
11pub struct Selection {
12 pub cursor: Cursor,
13 pub anchor: Position,
14}
15
16impl Selection {
17 pub fn is_empty(self) -> bool {
18 self.anchor == self.cursor.position
19 }
20
21 pub fn overlaps_with(self, other: Self) -> bool {
22 if self.is_empty() || other.is_empty() {
23 self.end() >= other.start()
24 } else {
25 self.end() > other.start()
26 }
27 }
28
29 pub fn start(self) -> Position {
30 self.cursor.position.min(self.anchor)
31 }
32
33 pub fn start_affinity(self) -> Affinity {
34 if self.anchor < self.cursor.position {
35 Affinity::After
36 } else {
37 self.cursor.affinity
38 }
39 }
40
41 pub fn end(self) -> Position {
42 self.cursor.position.max(self.anchor)
43 }
44
45 pub fn end_affinity(self) -> Affinity {
46 if self.cursor.position < self.anchor {
47 Affinity::Before
48 } else {
49 self.cursor.affinity
50 }
51 }
52
53 pub fn length(self) -> Length {
54 self.end() - self.start()
55 }
56
57 pub fn line_range(self) -> ops::Range<usize> {
58 if self.anchor <= self.cursor.position {
59 self.anchor.line_index..self.cursor.position.line_index + 1
60 } else {
61 self.cursor.position.line_index..if self.anchor.byte_index == 0 {
62 self.anchor.line_index
63 } else {
64 self.anchor.line_index + 1
65 }
66 }
67 }
68
69 pub fn update_cursor(self, f: impl FnOnce(Cursor) -> Cursor) -> Self {
70 Self {
71 cursor: f(self.cursor),
72 ..self
73 }
74 }
75
76 pub fn reset_anchor(self) -> Self {
77 Self {
78 anchor: self.cursor.position,
79 ..self
80 }
81 }
82
83 pub fn merge_with(self, other: Self) -> Option<Self> {
84 if self.overlaps_with(other) {
85 Some(if self.anchor <= self.cursor.position {
86 Selection {
87 anchor: self.anchor,
88 cursor: other.cursor,
89 }
90 } else {
91 Selection {
92 anchor: other.anchor,
93 cursor: self.cursor,
94 }
95 })
96 } else {
97 None
98 }
99 }
100
101 pub fn apply_edit(self, edit: &Edit) -> Self {
102 Self {
103 anchor: self.anchor.apply_edit(edit),
104 cursor: self.cursor.apply_edit(edit),
105 ..self
106 }
107 }
108}
109
110impl From<Cursor> for Selection {
111 fn from(cursor: Cursor) -> Self {
112 Self {
113 cursor,
114 anchor: cursor.position,
115 }
116 }
117}
118
119#[derive(Clone, Debug, Eq, Hash, PartialEq)]
120pub struct SelectionSet {
121 selections: Vec<Selection>,
122}
123
124impl SelectionSet {
125 pub fn new() -> Self {
126 Self::default()
127 }
128
129 pub fn as_selections(&self) -> &[Selection] {
130 &self.selections
131 }
132
133 pub fn update_selection(
134 &mut self,
135 index: usize,
136 f: impl FnOnce(Selection) -> Selection,
137 ) -> usize {
138 self.selections[index] = f(self.selections[index]);
139 self.normalize_selection(index)
140 }
141
142 pub fn update_all_selections(
143 &mut self,
144 retained_index: Option<usize>,
145 mut f: impl FnMut(Selection) -> Selection,
146 ) -> Option<usize> {
147 for selection in &mut self.selections {
148 *selection = f(*selection);
149 }
150 self.normalize_all_selections(retained_index)
151 }
152
153 pub fn apply_edit(&mut self, edit: &Edit, retained_index: Option<usize>) -> Option<usize> {
154 self.update_all_selections(retained_index, |selection| selection.apply_edit(edit))
155 }
156
157 pub fn add_selection(&mut self, selection: Selection) -> usize {
158 let index = match self
159 .selections
160 .binary_search_by_key(&selection.start(), |selection| selection.start())
161 {
162 Ok(index) => {
163 self.selections[index] = selection;
164 index
165 }
166 Err(index) => {
167 self.selections.insert(index, selection);
168 index
169 }
170 };
171 self.normalize_selection(index)
172 }
173
174 pub fn set_selection(&mut self, selection: Selection) {
175 self.selections.clear();
176 self.selections.push(selection);
177 }
178
179 fn normalize_selection(&mut self, index: usize) -> usize {
180 let mut index = index;
181 while index > 0 {
182 let prev_index = index - 1;
183 if !self.selections[prev_index].overlaps_with(self.selections[index]) {
184 break;
185 }
186 self.selections.remove(prev_index);
187 index -= 1;
188 }
189 while index + 1 < self.selections.len() {
190 let next_index = index + 1;
191 if !self.selections[index].overlaps_with(self.selections[next_index]) {
192 break;
193 }
194 self.selections.remove(next_index);
195 }
196 index
197 }
198
199 fn normalize_all_selections(&mut self, retained_index: Option<usize>) -> Option<usize> {
200 let mut retained_index = retained_index;
201 let mut current_index = 0;
202 while current_index + 1 < self.selections.len() {
203 let next_index = current_index + 1;
204 let current_selection = self.selections[current_index];
205 let next_selection = self.selections[next_index];
206 assert!(current_selection.start() <= next_selection.start());
207 if let Some(merged_selection) = current_selection.merge_with(next_selection) {
208 self.selections[current_index] = merged_selection;
209 self.selections.remove(next_index);
210 if let Some(retained_index) = &mut retained_index {
211 if next_index <= *retained_index {
212 *retained_index -= 1;
213 }
214 }
215 } else {
216 current_index += 1;
217 }
218 }
219 retained_index
220 }
221}
222
223impl Default for SelectionSet {
224 fn default() -> Self {
225 Self {
226 selections: vec![Selection::default()],
227 }
228 }
229}
230
231impl Deref for SelectionSet {
232 type Target = [Selection];
233
234 fn deref(&self) -> &Self::Target {
235 &self.selections
236 }
237}
238
239impl<'a> IntoIterator for &'a SelectionSet {
240 type Item = &'a Selection;
241 type IntoIter = Iter<'a, Selection>;
242
243 fn into_iter(self) -> Self::IntoIter {
244 self.iter()
245 }
246}
247
248#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
249pub struct Cursor {
250 pub position: Position,
251 pub affinity: Affinity,
252 pub preferred_column_index: Option<usize>,
253}
254
255impl Cursor {
256 pub fn is_at_first_line(self) -> bool {
257 self.position.line_index == 0
258 }
259
260 pub fn is_at_last_line(self, line_count: usize) -> bool {
261 self.position.line_index == line_count - 1
262 }
263
264 pub fn is_at_start_of_line(self) -> bool {
265 self.position.byte_index == 0
266 }
267
268 pub fn is_at_end_of_line(self, lines: &[String]) -> bool {
269 self.position.byte_index == lines[self.position.line_index].len()
270 }
271
272 pub fn is_at_first_row_of_line(self, layout: &Layout<'_>) -> bool {
273 let (row, _) = layout
274 .line(self.position.line_index)
275 .logical_to_grid_position(self.position.byte_index, self.affinity);
276 row == 0
277 }
278
279 pub fn is_at_last_row_of_line(self, layout: &Layout<'_>) -> bool {
280 let line = layout.line(self.position.line_index);
281 let (row, _) = line.logical_to_grid_position(self.position.byte_index, self.affinity);
282 row == line.row_count() - 1
283 }
284
285 pub fn move_left(self, lines: &[String]) -> Self {
286 if !self.is_at_start_of_line() {
287 return self.move_to_prev_grapheme(lines);
288 }
289 if !self.is_at_first_line() {
290 return self.move_to_end_of_prev_line(lines);
291 }
292 self
293 }
294
295 pub fn move_right(self, lines: &[String]) -> Self {
296 if !self.is_at_end_of_line(lines) {
297 return self.move_to_next_grapheme(lines);
298 }
299 if !self.is_at_last_line(lines.len()) {
300 return self.move_to_start_of_next_line();
301 }
302 self
303 }
304
305 pub fn move_up(self, layout: &Layout<'_>) -> Self {
306 if !self.is_at_first_row_of_line(layout) {
307 return self.move_to_prev_row_of_line(layout);
308 }
309 if !self.is_at_first_line() {
310 return self.move_to_last_row_of_prev_line(layout);
311 }
312 self.move_to_start_of_line()
313 }
314
315 pub fn move_down(self, layout: &Layout<'_>) -> Self {
316 if !self.is_at_last_row_of_line(layout) {
317 return self.move_to_next_row_of_line(layout);
318 }
319 if !self.is_at_last_line(layout.as_text().as_lines().len()) {
320 return self.move_to_first_row_of_next_line(layout);
321 }
322 self.move_to_end_of_line(layout.as_text().as_lines())
323 }
324
325 pub fn home(self, lines: &[String]) -> Self {
326 if !self.is_at_start_of_line() {
327 let indent_len = lines[self.position.line_index].indent().unwrap_or("").len();
328 if self.position.byte_index <= indent_len {
329 return self.move_to_start_of_line();
330 } else {
331 return Self {
332 position: Position {
333 line_index: self.position.line_index,
334 byte_index: indent_len,
335 },
336 affinity: Affinity::Before,
337 preferred_column_index: None,
338 };
339 }
340 }
341 self
342 }
343
344 pub fn end(self, lines: &[String]) -> Self {
345 if !self.is_at_end_of_line(lines) {
346 let indent_len = lines[self.position.line_index].indent().unwrap_or("").len();
347 if self.position.byte_index >= indent_len {
348 return self.move_to_end_of_line(lines);
349 } else {
350 return Self {
351 position: Position {
352 line_index: self.position.line_index,
353 byte_index: indent_len,
354 },
355 affinity: Affinity::After,
356 preferred_column_index: None,
357 };
358 }
359 }
360 self
361 }
362
363 pub fn move_to_end_of_line(self, lines: &[String]) -> Self {
364 let mut me = self.clone();
365 while !me.is_at_end_of_line(lines) {
366 me = me.move_to_next_grapheme(lines);
367 }
368 me
369 }
370
371 pub fn move_to_start_of_line(self) -> Self {
372 Self {
373 position: Position {
374 line_index: self.position.line_index,
375 byte_index: 0,
376 },
377 affinity: Affinity::Before,
378 preferred_column_index: None,
379 }
380 }
381
382 pub fn move_to_file_start(self) -> Self {
383 Self {
384 position: Position {
385 line_index: 0,
386 byte_index: 0,
387 },
388 affinity: Affinity::Before,
389 preferred_column_index: None,
390 }
391 }
392
393 pub fn move_to_file_end(self, lines: &[String]) -> Self {
394 Self {
395 position: Position {
396 line_index: lines.len() - 1,
397 byte_index: lines[lines.len() - 1].len(),
398 },
399 affinity: Affinity::After,
400 preferred_column_index: None,
401 }
402 }
403
404 pub fn move_to_prev_grapheme(self, lines: &[String]) -> Self {
405 Self {
406 position: Position {
407 line_index: self.position.line_index,
408 byte_index: lines[self.position.line_index][..self.position.byte_index]
409 .grapheme_indices()
410 .next_back()
411 .map(|(index, _)| index)
412 .unwrap(),
413 },
414 affinity: Affinity::After,
415 preferred_column_index: None,
416 }
417 }
418
419 pub fn move_to_next_grapheme(self, lines: &[String]) -> Self {
420 let line = &lines[self.position.line_index];
421 Self {
422 position: Position {
423 line_index: self.position.line_index,
424 byte_index: line[self.position.byte_index..]
425 .grapheme_indices()
426 .nth(1)
427 .map(|(index, _)| self.position.byte_index + index)
428 .unwrap_or(line.len()),
429 },
430 affinity: Affinity::Before,
431 preferred_column_index: None,
432 }
433 }
434
435 pub fn move_to_end_of_prev_line(self, lines: &[String]) -> Self {
436 let prev_line_index = self.position.line_index - 1;
437 Self {
438 position: Position {
439 line_index: prev_line_index,
440 byte_index: lines[prev_line_index].len(),
441 },
442 affinity: Affinity::After,
443 preferred_column_index: None,
444 }
445 }
446
447 pub fn move_to_start_of_next_line(self) -> Self {
448 Self {
449 position: Position {
450 line_index: self.position.line_index + 1,
451 byte_index: 0,
452 },
453 affinity: Affinity::Before,
454 preferred_column_index: None,
455 }
456 }
457
458 pub fn move_to_prev_row_of_line(self, layout: &Layout<'_>) -> Self {
459 let line = layout.line(self.position.line_index);
460 let (row_index, mut column_index) =
461 line.logical_to_grid_position(self.position.byte_index, self.affinity);
462 if let Some(preferred_column_index) = self.preferred_column_index {
463 column_index = preferred_column_index;
464 }
465 let (byte_index, affinity) = line.grid_to_logical_position(row_index - 1, column_index);
466 Self {
467 position: Position {
468 line_index: self.position.line_index,
469 byte_index,
470 },
471 affinity,
472 preferred_column_index: Some(column_index),
473 }
474 }
475
476 pub fn move_to_next_row_of_line(self, layout: &Layout<'_>) -> Self {
477 let line = layout.line(self.position.line_index);
478 let (row_index, mut column_index) =
479 line.logical_to_grid_position(self.position.byte_index, self.affinity);
480 if let Some(preferred_column_index) = self.preferred_column_index {
481 column_index = preferred_column_index;
482 }
483 let (byte, affinity) = line.grid_to_logical_position(row_index + 1, column_index);
484 Self {
485 position: Position {
486 line_index: self.position.line_index,
487 byte_index: byte,
488 },
489 affinity,
490 preferred_column_index: Some(column_index),
491 }
492 }
493
494 pub fn move_to_last_row_of_prev_line(self, layout: &Layout<'_>) -> Self {
495 let line = layout.line(self.position.line_index);
496 let (_, mut column_index) =
497 line.logical_to_grid_position(self.position.byte_index, self.affinity);
498 if let Some(preferred_column_index) = self.preferred_column_index {
499 column_index = preferred_column_index;
500 }
501 let prev_line = layout.line(self.position.line_index - 1);
502 let (byte_index, affinity) =
503 prev_line.grid_to_logical_position(prev_line.row_count() - 1, column_index);
504 Self {
505 position: Position {
506 line_index: self.position.line_index - 1,
507 byte_index,
508 },
509 affinity,
510 preferred_column_index: Some(column_index),
511 }
512 }
513
514 pub fn move_to_first_row_of_next_line(self, layout: &Layout<'_>) -> Self {
515 let line = layout.line(self.position.line_index);
516 let (_, mut column_index) =
517 line.logical_to_grid_position(self.position.byte_index, self.affinity);
518 if let Some(preferred_column_index) = self.preferred_column_index {
519 column_index = preferred_column_index;
520 }
521 let next_line = layout.line(self.position.line_index + 1);
522 let (byte_index, affinity) = next_line.grid_to_logical_position(0, column_index);
523 Self {
524 position: Position {
525 line_index: self.position.line_index + 1,
526 byte_index,
527 },
528 affinity,
529 preferred_column_index: Some(column_index),
530 }
531 }
532
533
534 pub fn apply_edit(self, edit: &Edit) -> Self {
535 Self {
536 position: self.position.apply_edit(edit),
537 ..self
538 }
539 }
540}
541
542impl From<Position> for Cursor {
543 fn from(position: Position) -> Self {
544 Self {
545 position,
546 affinity: Affinity::Before,
547 preferred_column_index: None,
548 }
549 }
550}
551
552#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
553pub enum Affinity {
554 Before,
555 After,
556}
557
558impl Default for Affinity {
559 fn default() -> Self {
560 Self::Before
561 }
562}