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