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