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    #[cfg(any(test, feature = "test-support"))]
540    pub fn select_display_ranges<T>(&mut self, ranges: T)
541    where
542        T: IntoIterator<Item = Range<DisplayPoint>>,
543    {
544        let display_map = self.display_map();
545        let selections = ranges
546            .into_iter()
547            .map(|range| {
548                let mut start = range.start;
549                let mut end = range.end;
550                let reversed = if start > end {
551                    mem::swap(&mut start, &mut end);
552                    true
553                } else {
554                    false
555                };
556                Selection {
557                    id: post_inc(&mut self.collection.next_selection_id),
558                    start: start.to_point(&display_map),
559                    end: end.to_point(&display_map),
560                    reversed,
561                    goal: SelectionGoal::None,
562                }
563            })
564            .collect();
565        self.select(selections);
566    }
567
568    pub fn move_with(
569        &mut self,
570        mut move_selection: impl FnMut(&DisplaySnapshot, &mut Selection<DisplayPoint>),
571    ) {
572        let mut changed = false;
573        let display_map = self.display_map();
574        let selections = self
575            .all::<Point>(self.cx)
576            .into_iter()
577            .map(|selection| {
578                let mut moved_selection =
579                    selection.map(|point| point.to_display_point(&display_map));
580                move_selection(&display_map, &mut moved_selection);
581                let moved_selection =
582                    moved_selection.map(|display_point| display_point.to_point(&display_map));
583                if selection != moved_selection {
584                    changed = true;
585                }
586                moved_selection
587            })
588            .collect();
589
590        if changed {
591            self.select(selections)
592        }
593    }
594
595    pub fn move_heads_with(
596        &mut self,
597        mut update_head: impl FnMut(
598            &DisplaySnapshot,
599            DisplayPoint,
600            SelectionGoal,
601        ) -> (DisplayPoint, SelectionGoal),
602    ) {
603        self.move_with(|map, selection| {
604            let (new_head, new_goal) = update_head(map, selection.head(), selection.goal);
605            selection.set_head(new_head, new_goal);
606        });
607    }
608
609    pub fn move_cursors_with(
610        &mut self,
611        mut update_cursor_position: impl FnMut(
612            &DisplaySnapshot,
613            DisplayPoint,
614            SelectionGoal,
615        ) -> (DisplayPoint, SelectionGoal),
616    ) {
617        self.move_with(|map, selection| {
618            let (cursor, new_goal) = update_cursor_position(map, selection.head(), selection.goal);
619            selection.collapse_to(cursor, new_goal)
620        });
621    }
622
623    pub fn replace_cursors_with(
624        &mut self,
625        mut find_replacement_cursors: impl FnMut(&DisplaySnapshot) -> Vec<DisplayPoint>,
626    ) {
627        let display_map = self.display_map();
628        let new_selections = find_replacement_cursors(&display_map)
629            .into_iter()
630            .map(|cursor| {
631                let cursor_point = cursor.to_point(&display_map);
632                Selection {
633                    id: post_inc(&mut self.collection.next_selection_id),
634                    start: cursor_point,
635                    end: cursor_point,
636                    reversed: false,
637                    goal: SelectionGoal::None,
638                }
639            })
640            .collect();
641        self.select(new_selections);
642    }
643
644    /// Compute new ranges for any selections that were located in excerpts that have
645    /// since been removed.
646    ///
647    /// Returns a `HashMap` indicating which selections whose former head position
648    /// was no longer present. The keys of the map are selection ids. The values are
649    /// the id of the new excerpt where the head of the selection has been moved.
650    pub fn refresh(&mut self) -> HashMap<usize, ExcerptId> {
651        let mut pending = self.collection.pending.take();
652        let mut selections_with_lost_position = HashMap::default();
653
654        let anchors_with_status = {
655            let buffer = self.buffer();
656            let disjoint_anchors = self
657                .disjoint
658                .iter()
659                .flat_map(|selection| [&selection.start, &selection.end]);
660            buffer.refresh_anchors(disjoint_anchors)
661        };
662        let adjusted_disjoint: Vec<_> = anchors_with_status
663            .chunks(2)
664            .map(|selection_anchors| {
665                let (anchor_ix, start, kept_start) = selection_anchors[0].clone();
666                let (_, end, kept_end) = selection_anchors[1].clone();
667                let selection = &self.disjoint[anchor_ix / 2];
668                let kept_head = if selection.reversed {
669                    kept_start
670                } else {
671                    kept_end
672                };
673                if !kept_head {
674                    selections_with_lost_position
675                        .insert(selection.id, selection.head().excerpt_id.clone());
676                }
677
678                Selection {
679                    id: selection.id,
680                    start,
681                    end,
682                    reversed: selection.reversed,
683                    goal: selection.goal,
684                }
685            })
686            .collect();
687
688        if !adjusted_disjoint.is_empty() {
689            let resolved_selections =
690                resolve_multiple(adjusted_disjoint.iter(), &self.buffer()).collect();
691            self.select::<usize>(resolved_selections);
692        }
693
694        if let Some(pending) = pending.as_mut() {
695            let buffer = self.buffer();
696            let anchors =
697                buffer.refresh_anchors([&pending.selection.start, &pending.selection.end]);
698            let (_, start, kept_start) = anchors[0].clone();
699            let (_, end, kept_end) = anchors[1].clone();
700            let kept_head = if pending.selection.reversed {
701                kept_start
702            } else {
703                kept_end
704            };
705            if !kept_head {
706                selections_with_lost_position.insert(
707                    pending.selection.id,
708                    pending.selection.head().excerpt_id.clone(),
709                );
710            }
711
712            pending.selection.start = start;
713            pending.selection.end = end;
714        }
715        self.collection.pending = pending;
716        self.selections_changed = true;
717
718        selections_with_lost_position
719    }
720}
721
722impl<'a> Deref for MutableSelectionsCollection<'a> {
723    type Target = SelectionsCollection;
724    fn deref(&self) -> &Self::Target {
725        self.collection
726    }
727}
728
729// Panics if passed selections are not in order
730pub fn resolve_multiple<'a, D, I>(
731    selections: I,
732    snapshot: &MultiBufferSnapshot,
733) -> impl 'a + Iterator<Item = Selection<D>>
734where
735    D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
736    I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
737{
738    let (to_summarize, selections) = selections.into_iter().tee();
739    let mut summaries = snapshot
740        .summaries_for_anchors::<D, _>(
741            to_summarize
742                .flat_map(|s| [&s.start, &s.end])
743                .collect::<Vec<_>>(),
744        )
745        .into_iter();
746    selections.map(move |s| Selection {
747        id: s.id,
748        start: summaries.next().unwrap(),
749        end: summaries.next().unwrap(),
750        reversed: s.reversed,
751        goal: s.goal,
752    })
753}
754
755fn resolve<D: TextDimension + Ord + Sub<D, Output = D>>(
756    selection: &Selection<Anchor>,
757    buffer: &MultiBufferSnapshot,
758) -> Selection<D> {
759    selection.map(|p| p.summary::<D>(&buffer))
760}