use crate::Anchor; use crate::{rope::TextDimension, BufferSnapshot}; use std::cmp::Ordering; use std::ops::Range; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SelectionGoal { None, Column(u32), ColumnRange { start: u32, end: u32 }, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Selection { pub id: usize, pub start: T, pub end: T, pub reversed: bool, pub goal: SelectionGoal, } impl Default for SelectionGoal { fn default() -> Self { Self::None } } impl Selection { pub fn head(&self) -> T { if self.reversed { self.start.clone() } else { self.end.clone() } } pub fn tail(&self) -> T { if self.reversed { self.end.clone() } else { self.start.clone() } } pub fn map(&self, f: F) -> Selection where F: Fn(T) -> S, { Selection:: { id: self.id, start: f(self.start.clone()), end: f(self.end.clone()), reversed: self.reversed, goal: self.goal, } } pub fn collapse_to(&mut self, point: T, new_goal: SelectionGoal) { self.start = point.clone(); self.end = point; self.goal = new_goal; self.reversed = false; } } impl Selection { pub fn is_empty(&self) -> bool { self.start == self.end } pub fn set_head(&mut self, head: T, new_goal: SelectionGoal) { if head.cmp(&self.tail()) < Ordering::Equal { if !self.reversed { self.end = self.start; self.reversed = true; } self.start = head; } else { if self.reversed { self.start = self.end; self.reversed = false; } self.end = head; } self.goal = new_goal; } pub fn range(&self) -> Range { self.start..self.end } } impl Selection { #[cfg(feature = "test-support")] pub fn from_offset(offset: usize) -> Self { Selection { id: 0, start: offset, end: offset, goal: SelectionGoal::None, reversed: false, } } } impl Selection { pub fn resolve<'a, D: 'a + TextDimension>( &'a self, snapshot: &'a BufferSnapshot, ) -> Selection { Selection { id: self.id, start: snapshot.summary_for_anchor(&self.start), end: snapshot.summary_for_anchor(&self.end), reversed: self.reversed, goal: self.goal, } } }