selections_collection.rs

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