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