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