Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/selection.rs')
| -rw-r--r-- | helix-core/src/selection.rs | 86 |
1 files changed, 45 insertions, 41 deletions
diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 5bde08e3..eff1fcd7 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -9,13 +9,12 @@ use crate::{ }, line_ending::get_line_ending, movement::Direction, - tree_sitter::Node, - Assoc, ChangeSet, RopeSlice, + Assoc, ChangeSet, RopeGraphemes, RopeSlice, }; -use helix_stdx::range::is_subset; use helix_stdx::rope::{self, RopeSliceExt}; use smallvec::{smallvec, SmallVec}; use std::{borrow::Cow, iter, slice}; +use tree_sitter::Node; /// A single selection range. /// @@ -76,8 +75,8 @@ impl Range { } pub fn from_node(node: Node, text: RopeSlice, direction: Direction) -> Self { - let from = text.byte_to_char(node.start_byte() as usize); - let to = text.byte_to_char(node.end_byte() as usize); + let from = text.byte_to_char(node.start_byte()); + let to = text.byte_to_char(node.end_byte()); Range::new(from, to).with_direction(direction) } @@ -185,16 +184,16 @@ impl Range { let positions_to_map = match self.anchor.cmp(&self.head) { Ordering::Equal => [ - (&mut self.anchor, Assoc::AfterSticky), - (&mut self.head, Assoc::AfterSticky), + (&mut self.anchor, Assoc::After), + (&mut self.head, Assoc::After), ], Ordering::Less => [ - (&mut self.anchor, Assoc::AfterSticky), - (&mut self.head, Assoc::BeforeSticky), + (&mut self.anchor, Assoc::After), + (&mut self.head, Assoc::Before), ], Ordering::Greater => [ - (&mut self.head, Assoc::AfterSticky), - (&mut self.anchor, Assoc::BeforeSticky), + (&mut self.head, Assoc::After), + (&mut self.anchor, Assoc::Before), ], }; changes.update_positions(positions_to_map.into_iter()); @@ -379,7 +378,7 @@ impl Range { /// Returns true if this Range covers a single grapheme in the given text pub fn is_single_grapheme(&self, doc: RopeSlice) -> bool { - let mut graphemes = doc.slice(self.from()..self.to()).graphemes(); + let mut graphemes = RopeGraphemes::new(doc.slice(self.from()..self.to())); let first = graphemes.next(); let second = graphemes.next(); first.is_some() && second.is_none() @@ -402,15 +401,6 @@ impl From<(usize, usize)> for Range { } } -impl From<Range> for helix_stdx::Range { - fn from(range: Range) -> Self { - Self { - start: range.from(), - end: range.to(), - } - } -} - /// A selection consists of one or more selection ranges. /// invariant: A selection can never be empty (always contains at least primary range). #[derive(Debug, Clone, PartialEq, Eq)] @@ -492,16 +482,16 @@ impl Selection { range.old_visual_position = None; match range.anchor.cmp(&range.head) { Ordering::Equal => [ - (&mut range.anchor, Assoc::AfterSticky), - (&mut range.head, Assoc::AfterSticky), + (&mut range.anchor, Assoc::After), + (&mut range.head, Assoc::After), ], Ordering::Less => [ - (&mut range.anchor, Assoc::AfterSticky), - (&mut range.head, Assoc::BeforeSticky), + (&mut range.anchor, Assoc::After), + (&mut range.head, Assoc::Before), ], Ordering::Greater => [ - (&mut range.head, Assoc::AfterSticky), - (&mut range.anchor, Assoc::BeforeSticky), + (&mut range.head, Assoc::After), + (&mut range.anchor, Assoc::Before), ], } }); @@ -523,10 +513,6 @@ impl Selection { } } - pub fn range_bounds(&self) -> impl Iterator<Item = helix_stdx::Range> + '_ { - self.ranges.iter().map(|&range| range.into()) - } - pub fn primary_index(&self) -> usize { self.primary_index } @@ -619,6 +605,7 @@ impl Selection { self } + // TODO: consume an iterator or a vec to reduce allocations? #[must_use] pub fn new(ranges: SmallVec<[Range; 1]>, primary_index: usize) -> Self { assert!(!ranges.is_empty()); @@ -673,7 +660,7 @@ impl Selection { pub fn fragments<'a>( &'a self, text: RopeSlice<'a>, - ) -> impl DoubleEndedIterator<Item = Cow<'a, str>> + ExactSizeIterator<Item = Cow<'a, str>> + ) -> impl DoubleEndedIterator<Item = Cow<'a, str>> + ExactSizeIterator<Item = Cow<str>> + 'a { self.ranges.iter().map(move |range| range.fragment(text)) } @@ -696,9 +683,32 @@ impl Selection { self.ranges.len() } - /// returns true if self ⊇ other + // returns true if self ⊇ other pub fn contains(&self, other: &Selection) -> bool { - is_subset::<true>(self.range_bounds(), other.range_bounds()) + let (mut iter_self, mut iter_other) = (self.iter(), other.iter()); + let (mut ele_self, mut ele_other) = (iter_self.next(), iter_other.next()); + + loop { + match (ele_self, ele_other) { + (Some(ra), Some(rb)) => { + if !ra.contains_range(rb) { + // `self` doesn't contain next element from `other`, advance `self`, we need to match all from `other` + ele_self = iter_self.next(); + } else { + // matched element from `other`, advance `other` + ele_other = iter_other.next(); + }; + } + (None, Some(_)) => { + // exhausted `self`, we can't match the reminder of `other` + return false; + } + (_, None) => { + // no elements from `other` left to match, `self` contains `other` + return true; + } + } + } } } @@ -720,12 +730,6 @@ impl IntoIterator for Selection { } } -impl FromIterator<Range> for Selection { - fn from_iter<T: IntoIterator<Item = Range>>(ranges: T) -> Self { - Self::new(ranges.into_iter().collect(), 0) - } -} - impl From<Range> for Selection { fn from(range: Range) -> Self { Self { @@ -740,7 +744,7 @@ pub struct LineRangeIter<'a> { text: RopeSlice<'a>, } -impl Iterator for LineRangeIter<'_> { +impl<'a> Iterator for LineRangeIter<'a> { type Item = (usize, usize); fn next(&mut self) -> Option<Self::Item> { |