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.rs86
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> {