1use std::{
2 cell::Ref,
3 cmp, iter, mem,
4 ops::{Deref, Range, Sub},
5 sync::Arc,
6};
7
8use collections::HashMap;
9use gpui::{AppContext, ModelHandle, MutableAppContext};
10use itertools::Itertools;
11use language::{rope::TextDimension, Bias, Point, Selection, SelectionGoal, ToPoint};
12use util::post_inc;
13
14use crate::{
15 display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
16 Anchor, DisplayPoint, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, ToOffset,
17};
18
19#[derive(Clone)]
20pub struct PendingSelection {
21 pub selection: Selection<Anchor>,
22 pub mode: SelectMode,
23}
24
25#[derive(Clone)]
26pub struct SelectionsCollection {
27 display_map: ModelHandle<DisplayMap>,
28 buffer: ModelHandle<MultiBuffer>,
29 pub next_selection_id: usize,
30 pub line_mode: bool,
31 disjoint: Arc<[Selection<Anchor>]>,
32 pending: Option<PendingSelection>,
33}
34
35impl SelectionsCollection {
36 pub fn new(display_map: ModelHandle<DisplayMap>, buffer: ModelHandle<MultiBuffer>) -> Self {
37 Self {
38 display_map,
39 buffer,
40 next_selection_id: 1,
41 line_mode: false,
42 disjoint: Arc::from([]),
43 pending: Some(PendingSelection {
44 selection: Selection {
45 id: 0,
46 start: Anchor::min(),
47 end: Anchor::min(),
48 reversed: false,
49 goal: SelectionGoal::None,
50 },
51 mode: SelectMode::Character,
52 }),
53 }
54 }
55
56 fn display_map(&self, cx: &mut MutableAppContext) -> DisplaySnapshot {
57 self.display_map.update(cx, |map, cx| map.snapshot(cx))
58 }
59
60 fn buffer<'a>(&self, cx: &'a AppContext) -> Ref<'a, MultiBufferSnapshot> {
61 self.buffer.read(cx).read(cx)
62 }
63
64 pub fn set_state(&mut self, other: &SelectionsCollection) {
65 self.next_selection_id = other.next_selection_id;
66 self.line_mode = other.line_mode;
67 self.disjoint = other.disjoint.clone();
68 self.pending = other.pending.clone();
69 }
70
71 pub fn count<'a>(&self) -> usize {
72 let mut count = self.disjoint.len();
73 if self.pending.is_some() {
74 count += 1;
75 }
76 count
77 }
78
79 pub fn disjoint_anchors(&self) -> Arc<[Selection<Anchor>]> {
80 self.disjoint.clone()
81 }
82
83 pub fn pending_anchor(&self) -> Option<Selection<Anchor>> {
84 self.pending
85 .as_ref()
86 .map(|pending| pending.selection.clone())
87 }
88
89 pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
90 &self,
91 cx: &AppContext,
92 ) -> Option<Selection<D>> {
93 self.pending_anchor()
94 .as_ref()
95 .map(|pending| pending.map(|p| p.summary::<D>(&self.buffer(cx))))
96 }
97
98 pub fn pending_mode(&self) -> Option<SelectMode> {
99 self.pending.as_ref().map(|pending| pending.mode.clone())
100 }
101
102 pub fn all<'a, D>(&self, cx: &AppContext) -> Vec<Selection<D>>
103 where
104 D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
105 {
106 let disjoint_anchors = &self.disjoint;
107 let mut disjoint =
108 resolve_multiple::<D, _>(disjoint_anchors.iter(), &self.buffer(cx)).peekable();
109
110 let mut pending_opt = self.pending::<D>(cx);
111
112 iter::from_fn(move || {
113 if let Some(pending) = pending_opt.as_mut() {
114 while let Some(next_selection) = disjoint.peek() {
115 if pending.start <= next_selection.end && pending.end >= next_selection.start {
116 let next_selection = disjoint.next().unwrap();
117 if next_selection.start < pending.start {
118 pending.start = next_selection.start;
119 }
120 if next_selection.end > pending.end {
121 pending.end = next_selection.end;
122 }
123 } else if next_selection.end < pending.start {
124 return disjoint.next();
125 } else {
126 break;
127 }
128 }
129
130 pending_opt.take()
131 } else {
132 disjoint.next()
133 }
134 })
135 .collect()
136 }
137
138 // Returns all of the selections, adjusted to take into account the selection line_mode
139 pub fn all_adjusted(&self, cx: &mut MutableAppContext) -> Vec<Selection<Point>> {
140 let mut selections = self.all::<Point>(cx);
141 if self.line_mode {
142 let map = self.display_map(cx);
143 for selection in &mut selections {
144 let new_range = map.expand_to_line(selection.range());
145 selection.start = new_range.start;
146 selection.end = new_range.end;
147 }
148 }
149 selections
150 }
151
152 pub fn disjoint_in_range<'a, D>(
153 &self,
154 range: Range<Anchor>,
155 cx: &AppContext,
156 ) -> Vec<Selection<D>>
157 where
158 D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
159 {
160 let buffer = self.buffer(cx);
161 let start_ix = match self
162 .disjoint
163 .binary_search_by(|probe| probe.end.cmp(&range.start, &buffer))
164 {
165 Ok(ix) | Err(ix) => ix,
166 };
167 let end_ix = match self
168 .disjoint
169 .binary_search_by(|probe| probe.start.cmp(&range.end, &buffer))
170 {
171 Ok(ix) => ix + 1,
172 Err(ix) => ix,
173 };
174 resolve_multiple(&self.disjoint[start_ix..end_ix], &buffer).collect()
175 }
176
177 pub fn all_display(
178 &mut self,
179 cx: &mut MutableAppContext,
180 ) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
181 let display_map = self.display_map(cx);
182 let selections = self
183 .all::<Point>(cx)
184 .into_iter()
185 .map(|selection| selection.map(|point| point.to_display_point(&display_map)))
186 .collect();
187 (display_map, selections)
188 }
189
190 pub fn newest_anchor(&self) -> &Selection<Anchor> {
191 self.pending
192 .as_ref()
193 .map(|s| &s.selection)
194 .or_else(|| self.disjoint.iter().max_by_key(|s| s.id))
195 .unwrap()
196 }
197
198 pub fn newest<D: TextDimension + Ord + Sub<D, Output = D>>(
199 &self,
200 cx: &AppContext,
201 ) -> Selection<D> {
202 resolve(self.newest_anchor(), &self.buffer(cx))
203 }
204
205 pub fn newest_display(&self, cx: &mut MutableAppContext) -> Selection<DisplayPoint> {
206 let display_map = self.display_map(cx);
207 let selection = self
208 .newest_anchor()
209 .map(|point| point.to_display_point(&display_map));
210 selection
211 }
212
213 pub fn oldest_anchor(&self) -> &Selection<Anchor> {
214 self.disjoint
215 .iter()
216 .min_by_key(|s| s.id)
217 .or_else(|| self.pending.as_ref().map(|p| &p.selection))
218 .unwrap()
219 }
220
221 pub fn oldest<D: TextDimension + Ord + Sub<D, Output = D>>(
222 &self,
223 cx: &AppContext,
224 ) -> Selection<D> {
225 resolve(self.oldest_anchor(), &self.buffer(cx))
226 }
227
228 pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
229 &self,
230 cx: &AppContext,
231 ) -> Selection<D> {
232 self.all(cx).first().unwrap().clone()
233 }
234
235 pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
236 &self,
237 cx: &AppContext,
238 ) -> Selection<D> {
239 self.all(cx).last().unwrap().clone()
240 }
241
242 #[cfg(any(test, feature = "test-support"))]
243 pub fn ranges<D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug>(
244 &self,
245 cx: &AppContext,
246 ) -> Vec<Range<D>> {
247 self.all::<D>(cx)
248 .iter()
249 .map(|s| {
250 if s.reversed {
251 s.end.clone()..s.start.clone()
252 } else {
253 s.start.clone()..s.end.clone()
254 }
255 })
256 .collect()
257 }
258
259 #[cfg(any(test, feature = "test-support"))]
260 pub fn display_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
261 let display_map = self.display_map(cx);
262 self.disjoint_anchors()
263 .iter()
264 .chain(self.pending_anchor().as_ref())
265 .map(|s| {
266 if s.reversed {
267 s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
268 } else {
269 s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map)
270 }
271 })
272 .collect()
273 }
274
275 pub fn build_columnar_selection(
276 &mut self,
277 display_map: &DisplaySnapshot,
278 row: u32,
279 columns: &Range<u32>,
280 reversed: bool,
281 ) -> Option<Selection<Point>> {
282 let is_empty = columns.start == columns.end;
283 let line_len = display_map.line_len(row);
284 if columns.start < line_len || (is_empty && columns.start == line_len) {
285 let start = DisplayPoint::new(row, columns.start);
286 let end = DisplayPoint::new(row, cmp::min(columns.end, line_len));
287
288 Some(Selection {
289 id: post_inc(&mut self.next_selection_id),
290 start: start.to_point(display_map),
291 end: end.to_point(display_map),
292 reversed,
293 goal: SelectionGoal::ColumnRange {
294 start: columns.start,
295 end: columns.end,
296 },
297 })
298 } else {
299 None
300 }
301 }
302
303 pub(crate) fn change_with<R>(
304 &mut self,
305 cx: &mut MutableAppContext,
306 change: impl FnOnce(&mut MutableSelectionsCollection) -> R,
307 ) -> (bool, R) {
308 let mut mutable_collection = MutableSelectionsCollection {
309 collection: self,
310 selections_changed: false,
311 cx,
312 };
313
314 let result = change(&mut mutable_collection);
315 assert!(
316 !mutable_collection.disjoint.is_empty() || mutable_collection.pending.is_some(),
317 "There must be at least one selection"
318 );
319 (mutable_collection.selections_changed, result)
320 }
321}
322
323pub struct MutableSelectionsCollection<'a> {
324 collection: &'a mut SelectionsCollection,
325 selections_changed: bool,
326 cx: &'a mut MutableAppContext,
327}
328
329impl<'a> MutableSelectionsCollection<'a> {
330 fn display_map(&mut self) -> DisplaySnapshot {
331 self.collection.display_map(self.cx)
332 }
333
334 fn buffer(&self) -> Ref<MultiBufferSnapshot> {
335 self.collection.buffer(self.cx)
336 }
337
338 pub fn clear_disjoint(&mut self) {
339 self.collection.disjoint = Arc::from([]);
340 }
341
342 pub fn delete(&mut self, selection_id: usize) {
343 let mut changed = false;
344 self.collection.disjoint = self
345 .disjoint
346 .into_iter()
347 .filter(|selection| {
348 let found = selection.id == selection_id;
349 changed |= found;
350 !found
351 })
352 .cloned()
353 .collect();
354
355 self.selections_changed |= changed;
356 }
357
358 pub fn clear_pending(&mut self) {
359 if self.collection.pending.is_some() {
360 self.collection.pending = None;
361 self.selections_changed = true;
362 }
363 }
364
365 pub fn set_pending_range(&mut self, range: Range<Anchor>, mode: SelectMode) {
366 self.collection.pending = Some(PendingSelection {
367 selection: Selection {
368 id: post_inc(&mut self.collection.next_selection_id),
369 start: range.start,
370 end: range.end,
371 reversed: false,
372 goal: SelectionGoal::None,
373 },
374 mode,
375 });
376 self.selections_changed = true;
377 }
378
379 pub fn set_pending(&mut self, selection: Selection<Anchor>, mode: SelectMode) {
380 self.collection.pending = Some(PendingSelection { selection, mode });
381 self.selections_changed = true;
382 }
383
384 pub fn try_cancel(&mut self) -> bool {
385 if let Some(pending) = self.collection.pending.take() {
386 if self.disjoint.is_empty() {
387 self.collection.disjoint = Arc::from([pending.selection]);
388 }
389 self.selections_changed = true;
390 return true;
391 }
392
393 let mut oldest = self.oldest_anchor().clone();
394 if self.count() > 1 {
395 self.collection.disjoint = Arc::from([oldest]);
396 self.selections_changed = true;
397 return true;
398 }
399
400 if !oldest.start.cmp(&oldest.end, &self.buffer()).is_eq() {
401 let head = oldest.head();
402 oldest.start = head.clone();
403 oldest.end = head;
404 self.collection.disjoint = Arc::from([oldest]);
405 self.selections_changed = true;
406 return true;
407 }
408
409 return false;
410 }
411
412 pub fn insert_range<T>(&mut self, range: Range<T>)
413 where
414 T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
415 {
416 let mut selections = self.all(self.cx);
417 let mut start = range.start.to_offset(&self.buffer());
418 let mut end = range.end.to_offset(&self.buffer());
419 let reversed = if start > end {
420 mem::swap(&mut start, &mut end);
421 true
422 } else {
423 false
424 };
425 selections.push(Selection {
426 id: post_inc(&mut self.collection.next_selection_id),
427 start,
428 end,
429 reversed,
430 goal: SelectionGoal::None,
431 });
432 self.select(selections);
433 }
434
435 pub fn select<T>(&mut self, mut selections: Vec<Selection<T>>)
436 where
437 T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug,
438 {
439 let buffer = self.buffer.read(self.cx).snapshot(self.cx);
440 selections.sort_unstable_by_key(|s| s.start);
441 // Merge overlapping selections.
442 let mut i = 1;
443 while i < selections.len() {
444 if selections[i - 1].end >= selections[i].start {
445 let removed = selections.remove(i);
446 if removed.start < selections[i - 1].start {
447 selections[i - 1].start = removed.start;
448 }
449 if removed.end > selections[i - 1].end {
450 selections[i - 1].end = removed.end;
451 }
452 } else {
453 i += 1;
454 }
455 }
456
457 self.collection.disjoint = Arc::from_iter(selections.into_iter().map(|selection| {
458 let end_bias = if selection.end > selection.start {
459 Bias::Left
460 } else {
461 Bias::Right
462 };
463 Selection {
464 id: selection.id,
465 start: buffer.anchor_after(selection.start),
466 end: buffer.anchor_at(selection.end, end_bias),
467 reversed: selection.reversed,
468 goal: selection.goal,
469 }
470 }));
471
472 self.collection.pending = None;
473 self.selections_changed = true;
474 }
475
476 pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
477 let buffer = self.buffer.read(self.cx).snapshot(self.cx);
478 let resolved_selections =
479 resolve_multiple::<usize, _>(&selections, &buffer).collect::<Vec<_>>();
480 self.select(resolved_selections);
481 }
482
483 pub fn select_ranges<I, T>(&mut self, ranges: I)
484 where
485 I: IntoIterator<Item = Range<T>>,
486 T: ToOffset,
487 {
488 let buffer = self.buffer.read(self.cx).snapshot(self.cx);
489 let selections = ranges
490 .into_iter()
491 .map(|range| {
492 let mut start = range.start.to_offset(&buffer);
493 let mut end = range.end.to_offset(&buffer);
494 let reversed = if start > end {
495 mem::swap(&mut start, &mut end);
496 true
497 } else {
498 false
499 };
500 Selection {
501 id: post_inc(&mut self.collection.next_selection_id),
502 start,
503 end,
504 reversed,
505 goal: SelectionGoal::None,
506 }
507 })
508 .collect::<Vec<_>>();
509
510 self.select(selections)
511 }
512
513 pub fn select_anchor_ranges<I: IntoIterator<Item = Range<Anchor>>>(&mut self, ranges: I) {
514 let buffer = self.buffer.read(self.cx).snapshot(self.cx);
515 let selections = ranges
516 .into_iter()
517 .map(|range| {
518 let mut start = range.start;
519 let mut end = range.end;
520 let reversed = if start.cmp(&end, &buffer).is_gt() {
521 mem::swap(&mut start, &mut end);
522 true
523 } else {
524 false
525 };
526 Selection {
527 id: post_inc(&mut self.collection.next_selection_id),
528 start,
529 end,
530 reversed,
531 goal: SelectionGoal::None,
532 }
533 })
534 .collect::<Vec<_>>();
535
536 self.select_anchors(selections)
537 }
538
539 #[cfg(any(test, feature = "test-support"))]
540 pub fn select_display_ranges<T>(&mut self, ranges: T)
541 where
542 T: IntoIterator<Item = Range<DisplayPoint>>,
543 {
544 let display_map = self.display_map();
545 let selections = ranges
546 .into_iter()
547 .map(|range| {
548 let mut start = range.start;
549 let mut end = range.end;
550 let reversed = if start > end {
551 mem::swap(&mut start, &mut end);
552 true
553 } else {
554 false
555 };
556 Selection {
557 id: post_inc(&mut self.collection.next_selection_id),
558 start: start.to_point(&display_map),
559 end: end.to_point(&display_map),
560 reversed,
561 goal: SelectionGoal::None,
562 }
563 })
564 .collect();
565 self.select(selections);
566 }
567
568 pub fn move_with(
569 &mut self,
570 mut move_selection: impl FnMut(&DisplaySnapshot, &mut Selection<DisplayPoint>),
571 ) {
572 let mut changed = false;
573 let display_map = self.display_map();
574 let selections = self
575 .all::<Point>(self.cx)
576 .into_iter()
577 .map(|selection| {
578 let mut moved_selection =
579 selection.map(|point| point.to_display_point(&display_map));
580 move_selection(&display_map, &mut moved_selection);
581 let moved_selection =
582 moved_selection.map(|display_point| display_point.to_point(&display_map));
583 if selection != moved_selection {
584 changed = true;
585 }
586 moved_selection
587 })
588 .collect();
589
590 if changed {
591 self.select(selections)
592 }
593 }
594
595 pub fn move_heads_with(
596 &mut self,
597 mut update_head: impl FnMut(
598 &DisplaySnapshot,
599 DisplayPoint,
600 SelectionGoal,
601 ) -> (DisplayPoint, SelectionGoal),
602 ) {
603 self.move_with(|map, selection| {
604 let (new_head, new_goal) = update_head(map, selection.head(), selection.goal);
605 selection.set_head(new_head, new_goal);
606 });
607 }
608
609 pub fn move_cursors_with(
610 &mut self,
611 mut update_cursor_position: impl FnMut(
612 &DisplaySnapshot,
613 DisplayPoint,
614 SelectionGoal,
615 ) -> (DisplayPoint, SelectionGoal),
616 ) {
617 self.move_with(|map, selection| {
618 let (cursor, new_goal) = update_cursor_position(map, selection.head(), selection.goal);
619 selection.collapse_to(cursor, new_goal)
620 });
621 }
622
623 pub fn replace_cursors_with(
624 &mut self,
625 mut find_replacement_cursors: impl FnMut(&DisplaySnapshot) -> Vec<DisplayPoint>,
626 ) {
627 let display_map = self.display_map();
628 let new_selections = find_replacement_cursors(&display_map)
629 .into_iter()
630 .map(|cursor| {
631 let cursor_point = cursor.to_point(&display_map);
632 Selection {
633 id: post_inc(&mut self.collection.next_selection_id),
634 start: cursor_point,
635 end: cursor_point,
636 reversed: false,
637 goal: SelectionGoal::None,
638 }
639 })
640 .collect();
641 self.select(new_selections);
642 }
643
644 /// Compute new ranges for any selections that were located in excerpts that have
645 /// since been removed.
646 ///
647 /// Returns a `HashMap` indicating which selections whose former head position
648 /// was no longer present. The keys of the map are selection ids. The values are
649 /// the id of the new excerpt where the head of the selection has been moved.
650 pub fn refresh(&mut self) -> HashMap<usize, ExcerptId> {
651 let mut pending = self.collection.pending.take();
652 let mut selections_with_lost_position = HashMap::default();
653
654 let anchors_with_status = {
655 let buffer = self.buffer();
656 let disjoint_anchors = self
657 .disjoint
658 .iter()
659 .flat_map(|selection| [&selection.start, &selection.end]);
660 buffer.refresh_anchors(disjoint_anchors)
661 };
662 let adjusted_disjoint: Vec<_> = anchors_with_status
663 .chunks(2)
664 .map(|selection_anchors| {
665 let (anchor_ix, start, kept_start) = selection_anchors[0].clone();
666 let (_, end, kept_end) = selection_anchors[1].clone();
667 let selection = &self.disjoint[anchor_ix / 2];
668 let kept_head = if selection.reversed {
669 kept_start
670 } else {
671 kept_end
672 };
673 if !kept_head {
674 selections_with_lost_position
675 .insert(selection.id, selection.head().excerpt_id.clone());
676 }
677
678 Selection {
679 id: selection.id,
680 start,
681 end,
682 reversed: selection.reversed,
683 goal: selection.goal,
684 }
685 })
686 .collect();
687
688 if !adjusted_disjoint.is_empty() {
689 let resolved_selections =
690 resolve_multiple(adjusted_disjoint.iter(), &self.buffer()).collect();
691 self.select::<usize>(resolved_selections);
692 }
693
694 if let Some(pending) = pending.as_mut() {
695 let buffer = self.buffer();
696 let anchors =
697 buffer.refresh_anchors([&pending.selection.start, &pending.selection.end]);
698 let (_, start, kept_start) = anchors[0].clone();
699 let (_, end, kept_end) = anchors[1].clone();
700 let kept_head = if pending.selection.reversed {
701 kept_start
702 } else {
703 kept_end
704 };
705 if !kept_head {
706 selections_with_lost_position.insert(
707 pending.selection.id,
708 pending.selection.head().excerpt_id.clone(),
709 );
710 }
711
712 pending.selection.start = start;
713 pending.selection.end = end;
714 }
715 self.collection.pending = pending;
716 self.selections_changed = true;
717
718 selections_with_lost_position
719 }
720}
721
722impl<'a> Deref for MutableSelectionsCollection<'a> {
723 type Target = SelectionsCollection;
724 fn deref(&self) -> &Self::Target {
725 self.collection
726 }
727}
728
729// Panics if passed selections are not in order
730pub fn resolve_multiple<'a, D, I>(
731 selections: I,
732 snapshot: &MultiBufferSnapshot,
733) -> impl 'a + Iterator<Item = Selection<D>>
734where
735 D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
736 I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
737{
738 let (to_summarize, selections) = selections.into_iter().tee();
739 let mut summaries = snapshot
740 .summaries_for_anchors::<D, _>(
741 to_summarize
742 .flat_map(|s| [&s.start, &s.end])
743 .collect::<Vec<_>>(),
744 )
745 .into_iter();
746 selections.map(move |s| Selection {
747 id: s.id,
748 start: summaries.next().unwrap(),
749 end: summaries.next().unwrap(),
750 reversed: s.reversed,
751 goal: s.goal,
752 })
753}
754
755fn resolve<D: TextDimension + Ord + Sub<D, Output = D>>(
756 selection: &Selection<Anchor>,
757 buffer: &MultiBufferSnapshot,
758) -> Selection<D> {
759 selection.map(|p| p.summary::<D>(&buffer))
760}