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