selection.rs

  1use crate::rope::TextDimension;
  2
  3use super::{AnchorRangeMap, Buffer, Content, Point, ToOffset, ToPoint};
  4use std::{cmp::Ordering, ops::Range, sync::Arc};
  5
  6pub type SelectionSetId = clock::Lamport;
  7pub type SelectionsVersion = usize;
  8
  9#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 10pub enum SelectionGoal {
 11    None,
 12    Column(u32),
 13    ColumnRange { start: u32, end: u32 },
 14}
 15
 16#[derive(Clone, Debug, Eq, PartialEq)]
 17pub struct Selection<T> {
 18    pub id: usize,
 19    pub start: T,
 20    pub end: T,
 21    pub reversed: bool,
 22    pub goal: SelectionGoal,
 23}
 24
 25#[derive(Clone, Debug, Eq, PartialEq)]
 26pub struct SelectionSet {
 27    pub id: SelectionSetId,
 28    pub active: bool,
 29    pub selections: Arc<AnchorRangeMap<SelectionState>>,
 30}
 31
 32#[derive(Debug, Eq, PartialEq)]
 33pub struct SelectionState {
 34    pub id: usize,
 35    pub reversed: bool,
 36    pub goal: SelectionGoal,
 37}
 38
 39impl<T: Clone> Selection<T> {
 40    pub fn head(&self) -> T {
 41        if self.reversed {
 42            self.start.clone()
 43        } else {
 44            self.end.clone()
 45        }
 46    }
 47
 48    pub fn tail(&self) -> T {
 49        if self.reversed {
 50            self.end.clone()
 51        } else {
 52            self.start.clone()
 53        }
 54    }
 55}
 56
 57impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
 58    pub fn is_empty(&self) -> bool {
 59        self.start == self.end
 60    }
 61
 62    pub fn set_head(&mut self, head: T) {
 63        if head.cmp(&self.tail()) < Ordering::Equal {
 64            if !self.reversed {
 65                self.end = self.start;
 66                self.reversed = true;
 67            }
 68            self.start = head;
 69        } else {
 70            if self.reversed {
 71                self.start = self.end;
 72                self.reversed = false;
 73            }
 74            self.end = head;
 75        }
 76    }
 77
 78    pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
 79        let start = self.start.to_point(buffer);
 80        let end = self.end.to_point(buffer);
 81        if self.reversed {
 82            end..start
 83        } else {
 84            start..end
 85        }
 86    }
 87
 88    pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
 89        let start = self.start.to_offset(buffer);
 90        let end = self.end.to_offset(buffer);
 91        if self.reversed {
 92            end..start
 93        } else {
 94            start..end
 95        }
 96    }
 97}
 98
 99impl SelectionSet {
100    pub fn len(&self) -> usize {
101        self.selections.len()
102    }
103
104    pub fn selections<'a, D, C>(&'a self, content: C) -> impl 'a + Iterator<Item = Selection<D>>
105    where
106        D: 'a + TextDimension<'a>,
107        C: 'a + Into<Content<'a>>,
108    {
109        self.selections
110            .ranges(content)
111            .map(|(range, state)| Selection {
112                id: state.id,
113                start: range.start,
114                end: range.end,
115                reversed: state.reversed,
116                goal: state.goal,
117            })
118    }
119}