selection.rs

  1use crate::{
  2    rope::TextDimension, AnchorRangeMap, Buffer, BufferSnapshot, Point, ToOffset, ToPoint,
  3};
  4use std::{cmp::Ordering, ops::Range, sync::Arc};
  5use sum_tree::Bias;
  6
  7pub type SelectionSetId = clock::Lamport;
  8pub type SelectionsVersion = usize;
  9
 10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 11pub enum SelectionGoal {
 12    None,
 13    Column(u32),
 14    ColumnRange { start: u32, end: u32 },
 15}
 16
 17#[derive(Clone, Debug, Eq, PartialEq)]
 18pub struct Selection<T> {
 19    pub id: usize,
 20    pub start: T,
 21    pub end: T,
 22    pub reversed: bool,
 23    pub goal: SelectionGoal,
 24}
 25
 26#[derive(Clone, Debug, Eq, PartialEq)]
 27pub struct SelectionSet {
 28    pub id: SelectionSetId,
 29    pub active: bool,
 30    pub selections: Arc<AnchorRangeMap<SelectionState>>,
 31}
 32
 33#[derive(Debug, Eq, PartialEq)]
 34pub struct SelectionState {
 35    pub id: usize,
 36    pub reversed: bool,
 37    pub goal: SelectionGoal,
 38}
 39
 40impl<T: Clone> Selection<T> {
 41    pub fn head(&self) -> T {
 42        if self.reversed {
 43            self.start.clone()
 44        } else {
 45            self.end.clone()
 46        }
 47    }
 48
 49    pub fn tail(&self) -> T {
 50        if self.reversed {
 51            self.end.clone()
 52        } else {
 53            self.start.clone()
 54        }
 55    }
 56}
 57
 58impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
 59    pub fn is_empty(&self) -> bool {
 60        self.start == self.end
 61    }
 62
 63    pub fn set_head(&mut self, head: T) {
 64        if head.cmp(&self.tail()) < Ordering::Equal {
 65            if !self.reversed {
 66                self.end = self.start;
 67                self.reversed = true;
 68            }
 69            self.start = head;
 70        } else {
 71            if self.reversed {
 72                self.start = self.end;
 73                self.reversed = false;
 74            }
 75            self.end = head;
 76        }
 77    }
 78
 79    pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
 80        let start = self.start.to_point(buffer);
 81        let end = self.end.to_point(buffer);
 82        if self.reversed {
 83            end..start
 84        } else {
 85            start..end
 86        }
 87    }
 88
 89    pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
 90        let start = self.start.to_offset(buffer);
 91        let end = self.end.to_offset(buffer);
 92        if self.reversed {
 93            end..start
 94        } else {
 95            start..end
 96        }
 97    }
 98}
 99
100impl SelectionSet {
101    pub fn len(&self) -> usize {
102        self.selections.len()
103    }
104
105    pub fn selections<'a, D>(
106        &'a self,
107        content: &'a BufferSnapshot,
108    ) -> impl 'a + Iterator<Item = Selection<D>>
109    where
110        D: TextDimension,
111    {
112        self.selections
113            .ranges(content)
114            .map(|(range, state)| Selection {
115                id: state.id,
116                start: range.start,
117                end: range.end,
118                reversed: state.reversed,
119                goal: state.goal,
120            })
121    }
122
123    pub fn intersecting_selections<'a, D, I>(
124        &'a self,
125        range: Range<(I, Bias)>,
126        content: &'a BufferSnapshot,
127    ) -> impl 'a + Iterator<Item = Selection<D>>
128    where
129        D: TextDimension,
130        I: 'a + ToOffset,
131    {
132        self.selections
133            .intersecting_ranges(range, content)
134            .map(|(range, state)| Selection {
135                id: state.id,
136                start: range.start,
137                end: range.end,
138                reversed: state.reversed,
139                goal: state.goal,
140            })
141    }
142
143    pub fn oldest_selection<'a, D>(&'a self, content: &'a BufferSnapshot) -> Option<Selection<D>>
144    where
145        D: TextDimension,
146    {
147        self.selections
148            .min_by_key(content, |selection| selection.id)
149            .map(|(range, state)| Selection {
150                id: state.id,
151                start: range.start,
152                end: range.end,
153                reversed: state.reversed,
154                goal: state.goal,
155            })
156    }
157
158    pub fn newest_selection<'a, D>(&'a self, content: &'a BufferSnapshot) -> Option<Selection<D>>
159    where
160        D: TextDimension,
161    {
162        self.selections
163            .max_by_key(content, |selection| selection.id)
164            .map(|(range, state)| Selection {
165                id: state.id,
166                start: range.start,
167                end: range.end,
168                reversed: state.reversed,
169                goal: state.goal,
170            })
171    }
172}