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