use crate::position::Position;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Selection {
pub anchor: Position,
pub head: Position,
}
impl Selection {
pub fn caret(at: Position) -> Self {
Self {
anchor: at,
head: at,
}
}
pub fn is_empty(&self) -> bool {
self.anchor == self.head
}
pub fn range(&self) -> (Position, Position) {
if self.anchor <= self.head {
(self.anchor, self.head)
} else {
(self.head, self.anchor)
}
}
pub fn contains(&self, pos: Position) -> bool {
let (start, end) = self.range();
pos >= start && pos < end
}
}
impl Default for Selection {
fn default() -> Self {
Self::caret(Position::default())
}
}
#[derive(Debug, Clone)]
pub struct Selections {
list: Vec<Selection>,
primary: usize,
}
impl Default for Selections {
fn default() -> Self {
Self {
list: vec![Selection::default()],
primary: 0,
}
}
}
impl Selections {
pub fn single(selection: Selection) -> Self {
Self {
list: vec![selection],
primary: 0,
}
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.list.len()
}
pub fn primary(&self) -> Selection {
self.list[self.primary]
}
pub fn iter(&self) -> impl Iterator<Item = &Selection> {
self.list.iter()
}
pub fn set_single(&mut self, selection: Selection) {
self.list = vec![selection];
self.primary = 0;
}
pub fn push(&mut self, selection: Selection) {
self.list.push(selection);
self.primary = self.list.len() - 1;
self.normalize();
}
pub fn map_in_place(&mut self, mut f: impl FnMut(Selection) -> Selection) {
for selection in &mut self.list {
*selection = f(*selection);
}
self.normalize();
}
pub fn collapse_to_heads(&mut self) {
let head = self.primary().head;
self.set_single(Selection::caret(head));
}
fn normalize(&mut self) {
let primary = self.list[self.primary];
self.list.sort_by_key(|s| s.range());
let mut merged: Vec<Selection> = Vec::with_capacity(self.list.len());
for selection in self.list.drain(..) {
match merged.last_mut() {
Some(previous) if overlaps(*previous, selection) => {
*previous = union(*previous, selection);
}
_ => merged.push(selection),
}
}
self.list = merged;
self.primary = self
.list
.iter()
.position(|s| *s == primary || covers(*s, primary))
.unwrap_or(0);
}
}
fn overlaps(a: Selection, b: Selection) -> bool {
let (_, a_end) = a.range();
let (b_start, _) = b.range();
if a_end > b_start {
return true;
}
a.is_empty() && b.is_empty() && a_end == b_start
}
fn union(a: Selection, b: Selection) -> Selection {
let (a_start, a_end) = a.range();
let (b_start, b_end) = b.range();
Selection {
anchor: a_start.min(b_start),
head: a_end.max(b_end),
}
}
fn covers(outer: Selection, inner: Selection) -> bool {
let (o_start, o_end) = outer.range();
let (i_start, i_end) = inner.range();
o_start <= i_start && i_end <= o_end
}