1use std::{
2 cmp, fmt, iter, mem,
3 ops::{AddAssign, Deref, DerefMut, Range, Sub},
4 sync::Arc,
5};
6
7use gpui::Pixels;
8use itertools::Itertools as _;
9use language::{Bias, Point, PointUtf16, Selection, SelectionGoal};
10use multi_buffer::{MultiBufferDimension, MultiBufferOffset};
11use util::post_inc;
12
13use crate::{
14 Anchor, DisplayPoint, DisplayRow, MultiBufferSnapshot, SelectMode, ToOffset,
15 display_map::{DisplaySnapshot, ToDisplayPoint},
16 movement::TextLayoutDetails,
17};
18
19#[derive(Debug, Clone)]
20pub struct PendingSelection {
21 selection: Selection<Anchor>,
22 mode: SelectMode,
23}
24
25#[derive(Debug, Clone)]
26pub struct SelectionsCollection {
27 next_selection_id: usize,
28 line_mode: bool,
29 /// The non-pending, non-overlapping selections.
30 /// The [SelectionsCollection::pending] selection could possibly overlap these
31 disjoint: Arc<[Selection<Anchor>]>,
32 /// A pending selection, such as when the mouse is being dragged
33 pending: Option<PendingSelection>,
34 select_mode: SelectMode,
35 is_extending: bool,
36}
37
38impl SelectionsCollection {
39 pub fn new() -> Self {
40 Self {
41 next_selection_id: 1,
42 line_mode: false,
43 disjoint: Arc::default(),
44 pending: Some(PendingSelection {
45 selection: Selection {
46 id: 0,
47 start: Anchor::Min,
48 end: Anchor::Min,
49 reversed: false,
50 goal: SelectionGoal::None,
51 },
52 mode: SelectMode::Character,
53 }),
54 select_mode: SelectMode::Character,
55 is_extending: false,
56 }
57 }
58
59 pub fn clone_state(&mut self, other: &SelectionsCollection) {
60 self.next_selection_id = other.next_selection_id;
61 self.line_mode = other.line_mode;
62 self.disjoint = other.disjoint.clone();
63 self.pending.clone_from(&other.pending);
64 }
65
66 pub fn count(&self) -> usize {
67 let mut count = self.disjoint.len();
68 if self.pending.is_some() {
69 count += 1;
70 }
71 count
72 }
73
74 /// The non-pending, non-overlapping selections. There could be a pending selection that
75 /// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a
76 /// pending selection. Returned as selections over Anchors.
77 pub fn disjoint_anchors_arc(&self) -> Arc<[Selection<Anchor>]> {
78 self.disjoint.clone()
79 }
80
81 /// The non-pending, non-overlapping selections. There could be a pending selection that
82 /// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a
83 /// pending selection. Returned as selections over Anchors.
84 pub fn disjoint_anchors(&self) -> &[Selection<Anchor>] {
85 &self.disjoint
86 }
87
88 pub fn disjoint_anchor_ranges(&self) -> impl Iterator<Item = Range<Anchor>> {
89 // Mapping the Arc slice would borrow it, whereas indexing captures it.
90 let disjoint = self.disjoint_anchors_arc();
91 (0..disjoint.len()).map(move |ix| disjoint[ix].range())
92 }
93
94 /// Non-overlapping selections using anchors, including the pending selection.
95 pub fn all_anchors(&self, snapshot: &DisplaySnapshot) -> Arc<[Selection<Anchor>]> {
96 if self.pending.is_none() {
97 self.disjoint_anchors_arc()
98 } else {
99 let all_offset_selections = self.all::<MultiBufferOffset>(snapshot);
100 all_offset_selections
101 .into_iter()
102 .map(|selection| selection_to_anchor_selection(selection, snapshot))
103 .collect()
104 }
105 }
106
107 pub fn pending_anchor(&self) -> Option<&Selection<Anchor>> {
108 self.pending.as_ref().map(|pending| &pending.selection)
109 }
110
111 pub fn pending<D>(&self, snapshot: &DisplaySnapshot) -> Option<Selection<D>>
112 where
113 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
114 {
115 resolve_selections_wrapping_blocks(self.pending_anchor(), &snapshot).next()
116 }
117
118 pub(crate) fn pending_mode(&self) -> Option<SelectMode> {
119 self.pending.as_ref().map(|pending| pending.mode.clone())
120 }
121
122 pub fn all<D>(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<D>>
123 where
124 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
125 {
126 let disjoint_anchors = &self.disjoint;
127 let mut disjoint =
128 resolve_selections_wrapping_blocks::<D, _>(disjoint_anchors.iter(), &snapshot)
129 .peekable();
130 let mut pending_opt = self.pending::<D>(&snapshot);
131 iter::from_fn(move || {
132 if let Some(pending) = pending_opt.as_mut() {
133 while let Some(next_selection) = disjoint.peek() {
134 if should_merge(
135 pending.start,
136 pending.end,
137 next_selection.start,
138 next_selection.end,
139 false,
140 ) {
141 let next_selection = disjoint.next().unwrap();
142 if next_selection.start < pending.start {
143 pending.start = next_selection.start;
144 }
145 if next_selection.end > pending.end {
146 pending.end = next_selection.end;
147 }
148 } else if next_selection.end < pending.start {
149 return disjoint.next();
150 } else {
151 break;
152 }
153 }
154
155 pending_opt.take()
156 } else {
157 disjoint.next()
158 }
159 })
160 .collect()
161 }
162
163 /// Returns all of the selections, adjusted to take into account the selection line_mode
164 pub fn all_adjusted(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<Point>> {
165 let mut selections = self.all::<Point>(&snapshot);
166 if self.line_mode {
167 for selection in &mut selections {
168 let new_range = snapshot.expand_to_line(selection.range());
169 selection.start = new_range.start;
170 selection.end = new_range.end;
171 }
172 }
173 selections
174 }
175
176 /// Returns the newest selection, adjusted to take into account the selection line_mode
177 pub fn newest_adjusted(&self, snapshot: &DisplaySnapshot) -> Selection<Point> {
178 let mut selection = self.newest::<Point>(&snapshot);
179 if self.line_mode {
180 let new_range = snapshot.expand_to_line(selection.range());
181 selection.start = new_range.start;
182 selection.end = new_range.end;
183 }
184 selection
185 }
186
187 pub fn all_adjusted_display(
188 &self,
189 display_map: &DisplaySnapshot,
190 ) -> Vec<Selection<DisplayPoint>> {
191 if self.line_mode {
192 let selections = self.all::<Point>(&display_map);
193 let result = selections
194 .into_iter()
195 .map(|mut selection| {
196 let new_range = display_map.expand_to_line(selection.range());
197 selection.start = new_range.start;
198 selection.end = new_range.end;
199 selection.map(|point| point.to_display_point(&display_map))
200 })
201 .collect();
202 result
203 } else {
204 self.all_display(display_map)
205 }
206 }
207
208 pub fn disjoint_in_range<D>(
209 &self,
210 range: Range<Anchor>,
211 snapshot: &DisplaySnapshot,
212 ) -> Vec<Selection<D>>
213 where
214 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord + std::fmt::Debug,
215 {
216 let start_ix = match self
217 .disjoint
218 .binary_search_by(|probe| probe.end.cmp(&range.start, snapshot.buffer_snapshot()))
219 {
220 Ok(ix) | Err(ix) => ix,
221 };
222 let end_ix = match self
223 .disjoint
224 .binary_search_by(|probe| probe.start.cmp(&range.end, snapshot.buffer_snapshot()))
225 {
226 Ok(ix) => ix + 1,
227 Err(ix) => ix,
228 };
229 resolve_selections_wrapping_blocks(&self.disjoint[start_ix..end_ix], snapshot).collect()
230 }
231
232 pub fn all_display(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<DisplayPoint>> {
233 let disjoint_anchors = &self.disjoint;
234 let mut disjoint =
235 resolve_selections_display(disjoint_anchors.iter(), &snapshot).peekable();
236 let mut pending_opt = resolve_selections_display(self.pending_anchor(), &snapshot).next();
237 iter::from_fn(move || {
238 if let Some(pending) = pending_opt.as_mut() {
239 while let Some(next_selection) = disjoint.peek() {
240 if should_merge(
241 pending.start,
242 pending.end,
243 next_selection.start,
244 next_selection.end,
245 false,
246 ) {
247 let next_selection = disjoint.next().unwrap();
248 if next_selection.start < pending.start {
249 pending.start = next_selection.start;
250 }
251 if next_selection.end > pending.end {
252 pending.end = next_selection.end;
253 }
254 } else if next_selection.end < pending.start {
255 return disjoint.next();
256 } else {
257 break;
258 }
259 }
260
261 pending_opt.take()
262 } else {
263 disjoint.next()
264 }
265 })
266 .collect()
267 }
268
269 pub fn newest_anchor(&self) -> &Selection<Anchor> {
270 self.pending
271 .as_ref()
272 .map(|s| &s.selection)
273 .or_else(|| self.disjoint.iter().max_by_key(|s| s.id))
274 .unwrap()
275 }
276
277 pub fn newest<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
278 where
279 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
280 {
281 resolve_selections_wrapping_blocks([self.newest_anchor()], &snapshot)
282 .next()
283 .unwrap()
284 }
285
286 pub fn newest_display(&self, snapshot: &DisplaySnapshot) -> Selection<DisplayPoint> {
287 resolve_selections_display([self.newest_anchor()], &snapshot)
288 .next()
289 .unwrap()
290 }
291
292 pub fn oldest_anchor(&self) -> &Selection<Anchor> {
293 self.disjoint
294 .iter()
295 .min_by_key(|s| s.id)
296 .or_else(|| self.pending.as_ref().map(|p| &p.selection))
297 .unwrap()
298 }
299
300 pub fn oldest<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
301 where
302 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
303 {
304 resolve_selections_wrapping_blocks([self.oldest_anchor()], &snapshot)
305 .next()
306 .unwrap()
307 }
308
309 pub fn first_anchor(&self) -> Selection<Anchor> {
310 self.pending
311 .as_ref()
312 .map(|pending| pending.selection.clone())
313 .unwrap_or_else(|| self.disjoint.first().cloned().unwrap())
314 }
315
316 pub fn first<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
317 where
318 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
319 {
320 self.all(snapshot).first().unwrap().clone()
321 }
322
323 pub fn last<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>
324 where
325 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
326 {
327 self.all(snapshot).last().unwrap().clone()
328 }
329
330 /// Returns a list of (potentially backwards!) ranges representing the selections.
331 /// Useful for test assertions, but prefer `.all()` instead.
332 #[cfg(any(test, feature = "test-support"))]
333 pub fn ranges<D>(&self, snapshot: &DisplaySnapshot) -> Vec<Range<D>>
334 where
335 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
336 {
337 self.all::<D>(snapshot)
338 .iter()
339 .map(|s| {
340 if s.reversed {
341 s.end..s.start
342 } else {
343 s.start..s.end
344 }
345 })
346 .collect()
347 }
348
349 #[cfg(any(test, feature = "test-support"))]
350 pub fn display_ranges(&self, display_snapshot: &DisplaySnapshot) -> Vec<Range<DisplayPoint>> {
351 self.disjoint_anchors_arc()
352 .iter()
353 .chain(self.pending_anchor())
354 .map(|s| {
355 if s.reversed {
356 s.end.to_display_point(display_snapshot)
357 ..s.start.to_display_point(display_snapshot)
358 } else {
359 s.start.to_display_point(display_snapshot)
360 ..s.end.to_display_point(display_snapshot)
361 }
362 })
363 .collect()
364 }
365
366 /// Attempts to build a selection in the provided `DisplayRow` within the
367 /// same range as the provided range of `Pixels`.
368 /// Returns `None` if the range is not empty but it starts past the line's
369 /// length, meaning that the line isn't long enough to be contained within
370 /// part of the provided range.
371 pub fn build_columnar_selection(
372 &mut self,
373 display_map: &DisplaySnapshot,
374 row: DisplayRow,
375 positions: &Range<Pixels>,
376 reversed: bool,
377 text_layout_details: &TextLayoutDetails,
378 ) -> Option<Selection<Point>> {
379 let is_empty = positions.start == positions.end;
380 let line_len = display_map.line_len(row);
381 let line = display_map.layout_row(row, text_layout_details);
382 let start_col = line.closest_index_for_x(positions.start) as u32;
383
384 let (start, end) = if is_empty {
385 let point = DisplayPoint::new(row, std::cmp::min(start_col, line_len));
386 (point, point)
387 } else {
388 if start_col >= line_len {
389 return None;
390 }
391 let start = DisplayPoint::new(row, start_col);
392 let end_col = line.closest_index_for_x(positions.end) as u32;
393 let end = DisplayPoint::new(row, end_col);
394 (start, end)
395 };
396
397 Some(Selection {
398 id: post_inc(&mut self.next_selection_id),
399 start: start.to_point(display_map),
400 end: end.to_point(display_map),
401 reversed,
402 goal: SelectionGoal::HorizontalRange {
403 start: positions.start.into(),
404 end: positions.end.into(),
405 },
406 })
407 }
408
409 /// Attempts to build a selection in the provided buffer row using the
410 /// same UTF-16 column range as specified.
411 /// Returns `None` if the range is not empty but it starts past the line's
412 /// length, meaning that the line isn't long enough to be contained within
413 /// part of the provided range.
414 fn build_columnar_selection_from_utf16_columns(
415 &mut self,
416 display_map: &DisplaySnapshot,
417 buffer_row: u32,
418 positions: &Range<u32>,
419 reversed: bool,
420 text_layout_details: &TextLayoutDetails,
421 ) -> Option<Selection<Point>> {
422 let snapshot = display_map.buffer_snapshot();
423 let is_empty = positions.start == positions.end;
424 let line_len_utf16 = snapshot.line_len_utf16(multi_buffer::MultiBufferRow(buffer_row));
425
426 let (start, end) = if is_empty {
427 let column = std::cmp::min(positions.start, line_len_utf16);
428 let point = snapshot.point_utf16_to_point(PointUtf16::new(buffer_row, column));
429 (point, point)
430 } else {
431 if positions.start >= line_len_utf16 {
432 return None;
433 }
434
435 let start = snapshot.point_utf16_to_point(PointUtf16::new(buffer_row, positions.start));
436 let end_column = std::cmp::min(positions.end, line_len_utf16);
437 let end = snapshot.point_utf16_to_point(PointUtf16::new(buffer_row, end_column));
438 (start, end)
439 };
440
441 let start_display_point = start.to_display_point(display_map);
442 let end_display_point = end.to_display_point(display_map);
443 let start_x = display_map.x_for_display_point(start_display_point, text_layout_details);
444 let end_x = display_map.x_for_display_point(end_display_point, text_layout_details);
445
446 Some(Selection {
447 id: post_inc(&mut self.next_selection_id),
448 start,
449 end,
450 reversed,
451 goal: SelectionGoal::HorizontalRange {
452 start: start_x.min(end_x).into(),
453 end: start_x.max(end_x).into(),
454 },
455 })
456 }
457
458 /// Finds the next columnar selection by walking display rows one at a time
459 /// so that soft-wrapped lines are considered and not skipped.
460 pub fn find_next_columnar_selection_by_display_row(
461 &mut self,
462 display_map: &DisplaySnapshot,
463 start_row: DisplayRow,
464 end_row: DisplayRow,
465 above: bool,
466 positions: &Range<Pixels>,
467 reversed: bool,
468 text_layout_details: &TextLayoutDetails,
469 ) -> Option<Selection<Point>> {
470 let mut row = start_row;
471 while row != end_row {
472 if above {
473 row.0 -= 1;
474 } else {
475 row.0 += 1;
476 }
477
478 if let Some(selection) = self.build_columnar_selection(
479 display_map,
480 row,
481 positions,
482 reversed,
483 text_layout_details,
484 ) {
485 return Some(selection);
486 }
487 }
488 None
489 }
490
491 /// Finds the next columnar selection by skipping to the next buffer row,
492 /// ignoring soft-wrapped lines.
493 pub fn find_next_columnar_selection_by_buffer_row(
494 &mut self,
495 display_map: &DisplaySnapshot,
496 start_row: DisplayRow,
497 end_row: DisplayRow,
498 above: bool,
499 goal_columns: &Range<u32>,
500 reversed: bool,
501 text_layout_details: &TextLayoutDetails,
502 ) -> Option<Selection<Point>> {
503 let mut row = start_row;
504 let direction = if above { -1 } else { 1 };
505 while row != end_row {
506 let new_row =
507 display_map.start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
508 row = new_row.row();
509 let buffer_row = new_row.to_point(display_map).row;
510
511 if let Some(selection) = self.build_columnar_selection_from_utf16_columns(
512 display_map,
513 buffer_row,
514 goal_columns,
515 reversed,
516 text_layout_details,
517 ) {
518 return Some(selection);
519 }
520 }
521 None
522 }
523
524 pub fn change_with<R>(
525 &mut self,
526 snapshot: &DisplaySnapshot,
527 change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
528 ) -> (bool, R) {
529 let mut mutable_collection = MutableSelectionsCollection {
530 snapshot,
531 collection: self,
532 selections_changed: false,
533 };
534
535 let result = change(&mut mutable_collection);
536 assert!(
537 !mutable_collection.disjoint.is_empty() || mutable_collection.pending.is_some(),
538 "There must be at least one selection"
539 );
540 if cfg!(debug_assertions) {
541 mutable_collection.disjoint.iter().for_each(|selection| {
542 assert!(
543 selection.start.cmp(&selection.end, &snapshot).is_le(),
544 "disjoint selection has start > end: {:?}",
545 mutable_collection.disjoint
546 );
547 assert!(
548 snapshot.can_resolve(&selection.start),
549 "disjoint selection start is not resolvable for the given snapshot:\n{selection:?}",
550 );
551 assert!(
552 snapshot.can_resolve(&selection.end),
553 "disjoint selection start is not resolvable for the given snapshot:\n{selection:?}",
554 );
555 });
556 assert!(
557 mutable_collection
558 .disjoint
559 .is_sorted_by(|first, second| first.end.cmp(&second.start, &snapshot).is_le()),
560 "disjoint selections are not sorted: {:?}",
561 mutable_collection.disjoint
562 );
563 if let Some(pending) = &mutable_collection.pending {
564 let selection = &pending.selection;
565 assert!(
566 selection.start.cmp(&selection.end, &snapshot).is_le(),
567 "pending selection has start > end: {:?}",
568 selection
569 );
570 assert!(
571 snapshot.can_resolve(&selection.start),
572 "pending selection start is not resolvable for the given snapshot: {pending:?}",
573 );
574 assert!(
575 snapshot.can_resolve(&selection.end),
576 "pending selection end is not resolvable for the given snapshot: {pending:?}",
577 );
578 }
579 }
580 (mutable_collection.selections_changed, result)
581 }
582
583 pub fn next_selection_id(&self) -> usize {
584 self.next_selection_id
585 }
586
587 pub fn line_mode(&self) -> bool {
588 self.line_mode
589 }
590
591 pub fn set_line_mode(&mut self, line_mode: bool) {
592 self.line_mode = line_mode;
593 }
594
595 pub fn select_mode(&self) -> &SelectMode {
596 &self.select_mode
597 }
598
599 pub fn set_select_mode(&mut self, select_mode: SelectMode) {
600 self.select_mode = select_mode;
601 }
602
603 pub fn is_extending(&self) -> bool {
604 self.is_extending
605 }
606
607 pub fn set_is_extending(&mut self, is_extending: bool) {
608 self.is_extending = is_extending;
609 }
610}
611
612pub struct MutableSelectionsCollection<'snap, 'a> {
613 collection: &'a mut SelectionsCollection,
614 snapshot: &'snap DisplaySnapshot,
615 selections_changed: bool,
616}
617
618impl<'snap, 'a> fmt::Debug for MutableSelectionsCollection<'snap, 'a> {
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 f.debug_struct("MutableSelectionsCollection")
621 .field("collection", &self.collection)
622 .field("selections_changed", &self.selections_changed)
623 .finish()
624 }
625}
626
627impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
628 pub fn display_snapshot(&self) -> DisplaySnapshot {
629 self.snapshot.clone()
630 }
631
632 pub fn clear_disjoint(&mut self) {
633 self.collection.disjoint = Arc::default();
634 }
635
636 pub fn delete(&mut self, selection_id: usize) {
637 let mut changed = false;
638 self.collection.disjoint = self
639 .disjoint
640 .iter()
641 .filter(|selection| {
642 let found = selection.id == selection_id;
643 changed |= found;
644 !found
645 })
646 .cloned()
647 .collect();
648
649 self.selections_changed |= changed;
650 }
651
652 pub fn remove_selections_from_buffer(&mut self, buffer_id: language::BufferId) {
653 let mut changed = false;
654
655 let filtered_selections: Arc<[Selection<Anchor>]> = {
656 self.disjoint
657 .iter()
658 .filter(|selection| {
659 if let Some((selection_buffer_anchor, _)) =
660 self.snapshot.anchor_to_buffer_anchor(selection.start)
661 {
662 let should_remove = selection_buffer_anchor.buffer_id == buffer_id;
663 changed |= should_remove;
664 !should_remove
665 } else {
666 true
667 }
668 })
669 .cloned()
670 .collect()
671 };
672
673 if filtered_selections.is_empty() {
674 let buffer_snapshot = self.snapshot.buffer_snapshot();
675 let anchor = buffer_snapshot
676 .excerpts()
677 .find(|excerpt| excerpt.context.start.buffer_id == buffer_id)
678 .and_then(|excerpt| buffer_snapshot.anchor_in_excerpt(excerpt.context.start))
679 .unwrap_or_else(|| self.snapshot.anchor_before(MultiBufferOffset(0)));
680 self.collection.disjoint = Arc::from([Selection {
681 id: post_inc(&mut self.collection.next_selection_id),
682 start: anchor,
683 end: anchor,
684 reversed: false,
685 goal: SelectionGoal::None,
686 }]);
687 } else {
688 self.collection.disjoint = filtered_selections;
689 }
690
691 self.selections_changed |= changed;
692 }
693
694 pub fn clear_pending(&mut self) {
695 if self.collection.pending.is_some() {
696 self.collection.pending = None;
697 self.selections_changed = true;
698 }
699 }
700
701 pub(crate) fn set_pending_anchor_range(&mut self, range: Range<Anchor>, mode: SelectMode) {
702 self.collection.pending = Some(PendingSelection {
703 selection: {
704 let mut start = range.start;
705 let mut end = range.end;
706 let reversed = if start.cmp(&end, self.snapshot).is_gt() {
707 mem::swap(&mut start, &mut end);
708 true
709 } else {
710 false
711 };
712 Selection {
713 id: post_inc(&mut self.collection.next_selection_id),
714 start,
715 end,
716 reversed,
717 goal: SelectionGoal::None,
718 }
719 },
720 mode,
721 });
722 self.selections_changed = true;
723 }
724
725 pub(crate) fn set_pending(&mut self, selection: Selection<Anchor>, mode: SelectMode) {
726 self.collection.pending = Some(PendingSelection { selection, mode });
727 self.selections_changed = true;
728 }
729
730 pub fn try_cancel(&mut self) -> bool {
731 if let Some(pending) = self.collection.pending.take() {
732 if self.disjoint.is_empty() {
733 self.collection.disjoint = Arc::from([pending.selection]);
734 }
735 self.selections_changed = true;
736 return true;
737 }
738
739 let mut oldest = self.oldest_anchor().clone();
740 if self.count() > 1 {
741 self.collection.disjoint = Arc::from([oldest]);
742 self.selections_changed = true;
743 return true;
744 }
745
746 if !oldest.start.cmp(&oldest.end, self.snapshot).is_eq() {
747 let head = oldest.head();
748 oldest.start = head;
749 oldest.end = head;
750 self.collection.disjoint = Arc::from([oldest]);
751 self.selections_changed = true;
752 return true;
753 }
754
755 false
756 }
757
758 pub fn insert_range<T>(&mut self, range: Range<T>)
759 where
760 T: ToOffset,
761 {
762 let display_map = self.display_snapshot();
763 let mut selections = self.collection.all(&display_map);
764 let mut start = range.start.to_offset(self.snapshot);
765 let mut end = range.end.to_offset(self.snapshot);
766 let reversed = if start > end {
767 mem::swap(&mut start, &mut end);
768 true
769 } else {
770 false
771 };
772 selections.push(Selection {
773 id: post_inc(&mut self.collection.next_selection_id),
774 start,
775 end,
776 reversed,
777 goal: SelectionGoal::None,
778 });
779 self.select(selections);
780 }
781
782 pub fn select<T>(&mut self, selections: Vec<Selection<T>>)
783 where
784 T: ToOffset + std::marker::Copy + std::fmt::Debug,
785 {
786 let mut selections = selections
787 .into_iter()
788 .map(|selection| selection.map(|it| it.to_offset(self.snapshot)))
789 .map(|mut selection| {
790 if selection.start > selection.end {
791 mem::swap(&mut selection.start, &mut selection.end);
792 selection.reversed = true
793 }
794 selection
795 })
796 .collect::<Vec<_>>();
797 selections.sort_unstable_by_key(|s| s.start);
798
799 let mut i = 1;
800 while i < selections.len() {
801 let prev = &selections[i - 1];
802 let current = &selections[i];
803
804 if should_merge(prev.start, prev.end, current.start, current.end, true) {
805 let removed = selections.remove(i);
806 if removed.start < selections[i - 1].start {
807 selections[i - 1].start = removed.start;
808 }
809 if selections[i - 1].end < removed.end {
810 selections[i - 1].end = removed.end;
811 }
812 } else {
813 i += 1;
814 }
815 }
816
817 self.collection.disjoint = Arc::from_iter(
818 selections
819 .into_iter()
820 .map(|selection| selection_to_anchor_selection(selection, self.snapshot)),
821 );
822 self.collection.pending = None;
823 self.selections_changed = true;
824 }
825
826 pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
827 let map = self.display_snapshot();
828 let resolved_selections =
829 resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(&selections, &map)
830 .collect::<Vec<_>>();
831 self.select(resolved_selections);
832 }
833
834 pub fn select_ranges<I, T>(&mut self, ranges: I)
835 where
836 I: IntoIterator<Item = Range<T>>,
837 T: ToOffset,
838 {
839 let ranges = ranges
840 .into_iter()
841 .map(|range| range.start.to_offset(self.snapshot)..range.end.to_offset(self.snapshot));
842 self.select_offset_ranges(ranges);
843 }
844
845 fn select_offset_ranges<I>(&mut self, ranges: I)
846 where
847 I: IntoIterator<Item = Range<MultiBufferOffset>>,
848 {
849 let selections = ranges
850 .into_iter()
851 .map(|range| {
852 let mut start = range.start;
853 let mut end = range.end;
854 let reversed = if start > end {
855 mem::swap(&mut start, &mut end);
856 true
857 } else {
858 false
859 };
860 Selection {
861 id: post_inc(&mut self.collection.next_selection_id),
862 start,
863 end,
864 reversed,
865 goal: SelectionGoal::None,
866 }
867 })
868 .collect::<Vec<_>>();
869
870 self.select(selections)
871 }
872
873 pub fn select_anchor_ranges<I>(&mut self, ranges: I)
874 where
875 I: IntoIterator<Item = Range<Anchor>>,
876 {
877 let selections = ranges
878 .into_iter()
879 .map(|range| {
880 let mut start = range.start;
881 let mut end = range.end;
882 let reversed = if start.cmp(&end, self.snapshot).is_gt() {
883 mem::swap(&mut start, &mut end);
884 true
885 } else {
886 false
887 };
888 Selection {
889 id: post_inc(&mut self.collection.next_selection_id),
890 start,
891 end,
892 reversed,
893 goal: SelectionGoal::None,
894 }
895 })
896 .collect::<Vec<_>>();
897 self.select_anchors(selections)
898 }
899
900 pub fn new_selection_id(&mut self) -> usize {
901 post_inc(&mut self.next_selection_id)
902 }
903
904 pub fn select_display_ranges<T>(&mut self, ranges: T)
905 where
906 T: IntoIterator<Item = Range<DisplayPoint>>,
907 {
908 let selections = ranges
909 .into_iter()
910 .map(|range| {
911 let mut start = range.start;
912 let mut end = range.end;
913 let reversed = if start > end {
914 mem::swap(&mut start, &mut end);
915 true
916 } else {
917 false
918 };
919 Selection {
920 id: post_inc(&mut self.collection.next_selection_id),
921 start: start.to_point(self.snapshot),
922 end: end.to_point(self.snapshot),
923 reversed,
924 goal: SelectionGoal::None,
925 }
926 })
927 .collect();
928 self.select(selections);
929 }
930
931 pub fn reverse_selections(&mut self) {
932 let mut new_selections: Vec<Selection<Point>> = Vec::new();
933 let disjoint = self.disjoint.clone();
934 for selection in disjoint
935 .iter()
936 .sorted_by(|first, second| Ord::cmp(&second.id, &first.id))
937 {
938 new_selections.push(Selection {
939 id: self.new_selection_id(),
940 start: selection
941 .start
942 .to_display_point(self.snapshot)
943 .to_point(self.snapshot),
944 end: selection
945 .end
946 .to_display_point(self.snapshot)
947 .to_point(self.snapshot),
948 reversed: selection.reversed,
949 goal: selection.goal,
950 });
951 }
952 self.select(new_selections);
953 }
954
955 pub fn move_with(
956 &mut self,
957 move_selection: &mut dyn FnMut(&DisplaySnapshot, &mut Selection<DisplayPoint>),
958 ) {
959 let mut changed = false;
960 let display_map = self.display_snapshot();
961 let selections = self.collection.all_display(&display_map);
962 let selections = selections
963 .into_iter()
964 .map(|selection| {
965 let mut moved_selection = selection.clone();
966 move_selection(&display_map, &mut moved_selection);
967 if selection != moved_selection {
968 changed = true;
969 }
970 moved_selection.map(|display_point| display_point.to_point(&display_map))
971 })
972 .collect();
973
974 if changed {
975 self.select(selections)
976 }
977 }
978
979 pub fn move_offsets_with(
980 &mut self,
981 move_selection: &mut dyn FnMut(&MultiBufferSnapshot, &mut Selection<MultiBufferOffset>),
982 ) {
983 let mut changed = false;
984 let display_map = self.display_snapshot();
985 let selections = self
986 .collection
987 .all::<MultiBufferOffset>(&display_map)
988 .into_iter()
989 .map(|selection| {
990 let mut moved_selection = selection.clone();
991 move_selection(self.snapshot, &mut moved_selection);
992 if selection != moved_selection {
993 changed = true;
994 }
995 moved_selection
996 })
997 .collect();
998
999 if changed {
1000 self.select(selections)
1001 }
1002 }
1003
1004 pub fn move_heads_with(
1005 &mut self,
1006 update_head: &mut dyn FnMut(
1007 &DisplaySnapshot,
1008 DisplayPoint,
1009 SelectionGoal,
1010 ) -> (DisplayPoint, SelectionGoal),
1011 ) {
1012 self.move_with(&mut |map, selection| {
1013 let (new_head, new_goal) = update_head(map, selection.head(), selection.goal);
1014 selection.set_head(new_head, new_goal);
1015 });
1016 }
1017
1018 pub fn move_cursors_with(
1019 &mut self,
1020 update_cursor_position: &mut dyn FnMut(
1021 &DisplaySnapshot,
1022 DisplayPoint,
1023 SelectionGoal,
1024 ) -> (DisplayPoint, SelectionGoal),
1025 ) {
1026 self.move_with(&mut |map, selection| {
1027 let (cursor, new_goal) = update_cursor_position(map, selection.head(), selection.goal);
1028 selection.collapse_to(cursor, new_goal)
1029 });
1030 }
1031
1032 pub fn maybe_move_cursors_with(
1033 &mut self,
1034 update_cursor_position: &mut dyn FnMut(
1035 &DisplaySnapshot,
1036 DisplayPoint,
1037 SelectionGoal,
1038 ) -> Option<(DisplayPoint, SelectionGoal)>,
1039 ) {
1040 self.move_cursors_with(&mut |map, point, goal| {
1041 update_cursor_position(map, point, goal).unwrap_or((point, goal))
1042 })
1043 }
1044
1045 pub fn replace_cursors_with(
1046 &mut self,
1047 find_replacement_cursors: impl FnOnce(&DisplaySnapshot) -> Vec<DisplayPoint>,
1048 ) {
1049 let new_selections = find_replacement_cursors(self.snapshot)
1050 .into_iter()
1051 .map(|cursor| {
1052 let cursor_point = cursor.to_point(self.snapshot);
1053 Selection {
1054 id: post_inc(&mut self.collection.next_selection_id),
1055 start: cursor_point,
1056 end: cursor_point,
1057 reversed: false,
1058 goal: SelectionGoal::None,
1059 }
1060 })
1061 .collect();
1062 self.select(new_selections);
1063 }
1064
1065 pub fn pending_anchor_mut(&mut self) -> Option<&mut Selection<Anchor>> {
1066 self.selections_changed = true;
1067 self.pending.as_mut().map(|pending| &mut pending.selection)
1068 }
1069}
1070
1071impl Deref for MutableSelectionsCollection<'_, '_> {
1072 type Target = SelectionsCollection;
1073 fn deref(&self) -> &Self::Target {
1074 self.collection
1075 }
1076}
1077
1078impl DerefMut for MutableSelectionsCollection<'_, '_> {
1079 fn deref_mut(&mut self) -> &mut Self::Target {
1080 self.collection
1081 }
1082}
1083
1084fn selection_to_anchor_selection(
1085 selection: Selection<MultiBufferOffset>,
1086 buffer: &MultiBufferSnapshot,
1087) -> Selection<Anchor> {
1088 let end_bias = if selection.start == selection.end {
1089 Bias::Right
1090 } else {
1091 Bias::Left
1092 };
1093 Selection {
1094 id: selection.id,
1095 start: buffer.anchor_after(selection.start),
1096 end: buffer.anchor_at(selection.end, end_bias),
1097 reversed: selection.reversed,
1098 goal: selection.goal,
1099 }
1100}
1101
1102fn resolve_selections_point<'a>(
1103 selections: impl 'a + IntoIterator<Item = &'a Selection<Anchor>>,
1104 map: &'a DisplaySnapshot,
1105) -> impl 'a + Iterator<Item = Selection<Point>> {
1106 let (to_summarize, selections) = selections.into_iter().tee();
1107 let mut summaries = map
1108 .buffer_snapshot()
1109 .summaries_for_anchors::<Point, _>(to_summarize.flat_map(|s| [&s.start, &s.end]))
1110 .into_iter();
1111 selections.map(move |s| {
1112 let start = summaries.next().unwrap();
1113 let end = summaries.next().unwrap();
1114 assert!(
1115 start <= end,
1116 "anchors: start: {:?}, end: {:?}; resolved to: start: {:?}, end: {:?}",
1117 s.start,
1118 s.end,
1119 start,
1120 end
1121 );
1122 Selection {
1123 id: s.id,
1124 start,
1125 end,
1126 reversed: s.reversed,
1127 goal: s.goal,
1128 }
1129 })
1130}
1131
1132/// Panics if passed selections are not in order
1133/// Resolves the anchors to display positions
1134fn resolve_selections_display<'a>(
1135 selections: impl 'a + IntoIterator<Item = &'a Selection<Anchor>>,
1136 map: &'a DisplaySnapshot,
1137) -> impl 'a + Iterator<Item = Selection<DisplayPoint>> {
1138 let selections = resolve_selections_point(selections, map).map(move |s| {
1139 let display_start = map.point_to_display_point(s.start, Bias::Left);
1140 let display_end = map.point_to_display_point(
1141 s.end,
1142 if s.start == s.end {
1143 Bias::Right
1144 } else {
1145 Bias::Left
1146 },
1147 );
1148 assert!(
1149 display_start <= display_end,
1150 "display_start: {:?}, display_end: {:?}",
1151 display_start,
1152 display_end
1153 );
1154 Selection {
1155 id: s.id,
1156 start: display_start,
1157 end: display_end,
1158 reversed: s.reversed,
1159 goal: s.goal,
1160 }
1161 });
1162 coalesce_selections(selections)
1163}
1164
1165/// Resolves the passed in anchors to [`MultiBufferDimension`]s `D`
1166/// wrapping around blocks inbetween.
1167///
1168/// # Panics
1169///
1170/// Panics if passed selections are not in order
1171pub(crate) fn resolve_selections_wrapping_blocks<'a, D, I>(
1172 selections: I,
1173 map: &'a DisplaySnapshot,
1174) -> impl 'a + Iterator<Item = Selection<D>>
1175where
1176 D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,
1177 I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
1178{
1179 // Transforms `Anchor -> DisplayPoint -> Point -> DisplayPoint -> D`
1180 // todo(lw): We should be able to short circuit the `Anchor -> DisplayPoint -> Point` to `Anchor -> Point`
1181 let (to_convert, selections) = resolve_selections_display(selections, map).tee();
1182 let mut converted_endpoints =
1183 map.buffer_snapshot()
1184 .dimensions_from_points::<D>(to_convert.flat_map(|s| {
1185 let start = map.display_point_to_point(s.start, Bias::Left);
1186 let end = map.display_point_to_point(s.end, Bias::Right);
1187 assert!(start <= end, "start: {:?}, end: {:?}", start, end);
1188 [start, end]
1189 }));
1190 selections.map(move |s| {
1191 let start = converted_endpoints.next().unwrap();
1192 let end = converted_endpoints.next().unwrap();
1193 assert!(start <= end, "start: {:?}, end: {:?}", start, end);
1194 Selection {
1195 id: s.id,
1196 start,
1197 end,
1198 reversed: s.reversed,
1199 goal: s.goal,
1200 }
1201 })
1202}
1203
1204fn coalesce_selections<D: Ord + fmt::Debug + Copy>(
1205 selections: impl Iterator<Item = Selection<D>>,
1206) -> impl Iterator<Item = Selection<D>> {
1207 let mut selections = selections.peekable();
1208 iter::from_fn(move || {
1209 let mut selection = selections.next()?;
1210 while let Some(next_selection) = selections.peek() {
1211 if should_merge(
1212 selection.start,
1213 selection.end,
1214 next_selection.start,
1215 next_selection.end,
1216 true,
1217 ) {
1218 if selection.reversed == next_selection.reversed {
1219 selection.end = cmp::max(selection.end, next_selection.end);
1220 selections.next();
1221 } else {
1222 selection.end = cmp::max(selection.start, next_selection.start);
1223 break;
1224 }
1225 } else {
1226 break;
1227 }
1228 }
1229 assert!(
1230 selection.start <= selection.end,
1231 "selection.start: {:?}, selection.end: {:?}, selection.reversed: {:?}",
1232 selection.start,
1233 selection.end,
1234 selection.reversed
1235 );
1236 Some(selection)
1237 })
1238}
1239
1240/// Determines whether two selections should be merged into one.
1241///
1242/// Two selections should be merged when:
1243/// 1. They overlap: the selections share at least one position
1244/// 2. They have the same start position: one contains or equals the other
1245/// 3. A cursor touches a selection boundary: a zero-width selection (cursor) at the
1246/// start or end of another selection should be absorbed into it
1247///
1248/// Note: two selections that merely touch (one ends exactly where the other begins)
1249/// but don't share any positions remain separate, see: https://github.com/zed-industries/zed/issues/24748
1250fn should_merge<T: Ord + Copy>(a_start: T, a_end: T, b_start: T, b_end: T, sorted: bool) -> bool {
1251 let is_overlapping = if sorted {
1252 // When sorted, `a` starts before or at `b`, so overlap means `b` starts before `a` ends
1253 b_start < a_end
1254 } else {
1255 a_start < b_end && b_start < a_end
1256 };
1257
1258 // Selections starting at the same position should always merge (one contains the other)
1259 let same_start = a_start == b_start;
1260
1261 // A cursor (zero-width selection) touching another selection's boundary should merge.
1262 // This handles cases like a cursor at position X merging with a selection that
1263 // starts or ends at X.
1264 let is_cursor_a = a_start == a_end;
1265 let is_cursor_b = b_start == b_end;
1266 let cursor_at_boundary = (is_cursor_a && (a_start == b_start || a_end == b_end))
1267 || (is_cursor_b && (b_start == a_start || b_end == a_end));
1268
1269 is_overlapping || same_start || cursor_at_boundary
1270}