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