selection.rs

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