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