mirror of https://github.com/helix-editor/helix
Add Selection::{overlaps,without} and fix contains
Adds two helper functions to `Selection`: * `overlaps`: tests whether two `Selection`s contain any ranges which overlap with each other * `without`: Computes a new `Selection` that is the set difference of two `Selection`s, i.e. everything in the first `Selection` with everything that overlaps in the second `Selection` removed, potentially leaving holes in the original ranges. It also fixes a bug with `Selection::contains`: it assumes that if the second `Selection` has a greater number of ranges than the first, then the first cannot contain the second; but this is false, since one range from the first could contain multiple smaller ranges in the second.pull/6198/head
parent
8fbb9566fb
commit
4b3aad7830
|
@ -703,22 +703,161 @@ impl Selection {
|
|||
pub fn contains(&self, other: &Selection) -> bool {
|
||||
is_subset::<true>(self.range_bounds(), other.range_bounds())
|
||||
}
|
||||
|
||||
/// returns true if self has at least one range that overlaps with at least one range from other
|
||||
pub fn overlaps(&self, other: &Selection) -> bool {
|
||||
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.overlaps(rb) {
|
||||
return true;
|
||||
} else if ra.from() > rb.from() {
|
||||
ele_self = iter_self.next();
|
||||
} else {
|
||||
ele_other = iter_other.next();
|
||||
}
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the given selection with the overlapping portions of `other`
|
||||
/// cut out. If one range from this selection is equal to one from `other`,
|
||||
/// this range is removed. If this results in an entirely empty selection,
|
||||
/// `None` is returned.
|
||||
pub fn without(self, other: &Selection) -> Option<Self> {
|
||||
if other.contains(&self) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut primary_index = self.primary_index;
|
||||
let mut ranges = smallvec!();
|
||||
let (mut iter_self, mut iter_other) = (self.into_iter(), other.iter());
|
||||
let (mut ele_self, mut ele_other) = (iter_self.next(), iter_other.next());
|
||||
let mut cur_index = 0;
|
||||
|
||||
loop {
|
||||
match (ele_self, ele_other) {
|
||||
(Some(ra), Some(rb)) => {
|
||||
if !ra.overlaps(rb) {
|
||||
// there's no overlap and it's on the left of rb
|
||||
if ra.to() <= rb.from() {
|
||||
ranges.push(ra);
|
||||
ele_self = iter_self.next();
|
||||
cur_index += 1;
|
||||
|
||||
// otherwise it must be on the right, so move rb forward
|
||||
} else {
|
||||
ele_other = iter_other.next();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise there is overlap, so truncate or split
|
||||
if rb.contains_range(&ra) {
|
||||
ele_self = iter_self.next();
|
||||
cur_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [ ra ]
|
||||
// [ rb ]
|
||||
if ra.from() <= rb.from() && ra.to() <= rb.to() && ra.to() >= rb.from() {
|
||||
let new = if ra.direction() == Direction::Backward {
|
||||
Range::new(rb.from(), ra.head)
|
||||
} else {
|
||||
Range::new(ra.anchor, rb.from())
|
||||
};
|
||||
|
||||
ranges.push(new);
|
||||
ele_self = iter_self.next();
|
||||
cur_index += 1;
|
||||
|
||||
// [ ra ]
|
||||
// [ rb ]
|
||||
} else if ra.from() >= rb.from() && ra.to() >= rb.to() && ra.from() <= rb.to() {
|
||||
let new = if ra.direction() == Direction::Backward {
|
||||
Range::new(ra.anchor, rb.to() + 1)
|
||||
} else {
|
||||
Range::new(rb.to(), ra.head)
|
||||
};
|
||||
|
||||
// don't settle on the new range yet because the next
|
||||
// rb could chop off the other end of ra
|
||||
ele_self = Some(new);
|
||||
ele_other = iter_other.next();
|
||||
|
||||
// [ ra ]
|
||||
// [ rb ]
|
||||
} else if ra.from() < rb.from() && ra.to() > rb.to() {
|
||||
// we must split the range into two
|
||||
let left = if ra.direction() == Direction::Backward {
|
||||
Range::new(rb.from(), ra.head)
|
||||
} else {
|
||||
Range::new(ra.anchor, rb.from())
|
||||
};
|
||||
|
||||
let right = if ra.direction() == Direction::Backward {
|
||||
Range::new(ra.anchor, rb.to())
|
||||
} else {
|
||||
Range::new(rb.to(), ra.head)
|
||||
};
|
||||
|
||||
// We do NOT push right onto the results right away.
|
||||
// We must put it back into the iterator and check it
|
||||
// again in case a further range splits it again.
|
||||
ranges.push(left);
|
||||
ele_other = iter_other.next();
|
||||
|
||||
// offset the primary index whenever we split
|
||||
if cur_index < primary_index {
|
||||
primary_index += 1;
|
||||
}
|
||||
|
||||
cur_index += 1;
|
||||
ele_self = Some(right);
|
||||
}
|
||||
}
|
||||
// the rest just get included as is
|
||||
(Some(range), None) => {
|
||||
ranges.push(range);
|
||||
ele_self = iter_self.next();
|
||||
cur_index += 1;
|
||||
}
|
||||
// exhausted `self`, nothing left to do
|
||||
(None, _) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ranges.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Selection::new(ranges, primary_index))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Selection {
|
||||
type Item = &'a Range;
|
||||
type IntoIter = std::slice::Iter<'a, Range>;
|
||||
|
||||
fn into_iter(self) -> std::slice::Iter<'a, Range> {
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.ranges().iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Selection {
|
||||
type Item = Range;
|
||||
type IntoIter = smallvec::IntoIter<[Range; 1]>;
|
||||
type IntoIter = smallvec::IntoIter<[Self::Item; 1]>;
|
||||
|
||||
fn into_iter(self) -> smallvec::IntoIter<[Range; 1]> {
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.ranges.into_iter()
|
||||
}
|
||||
}
|
||||
|
@ -885,6 +1024,7 @@ pub fn split_on_matches(text: RopeSlice, selection: &Selection, regex: &rope::Re
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::test;
|
||||
use crate::Rope;
|
||||
|
||||
#[test]
|
||||
|
@ -975,7 +1115,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_overlaps() {
|
||||
fn test_range_overlaps() {
|
||||
fn overlaps(a: (usize, usize), b: (usize, usize)) -> bool {
|
||||
Range::new(a.0, a.1).overlaps(&Range::new(b.0, b.1))
|
||||
}
|
||||
|
@ -1025,6 +1165,160 @@ mod test {
|
|||
assert!(overlaps((1, 1), (1, 1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_selection_overlaps() {
|
||||
fn overlaps(a: &[(usize, usize)], b: &[(usize, usize)]) -> bool {
|
||||
let a = Selection::new(
|
||||
a.iter()
|
||||
.map(|(anchor, head)| Range::new(*anchor, *head))
|
||||
.collect(),
|
||||
0,
|
||||
);
|
||||
let b = Selection::new(
|
||||
b.iter()
|
||||
.map(|(anchor, head)| Range::new(*anchor, *head))
|
||||
.collect(),
|
||||
0,
|
||||
);
|
||||
a.overlaps(&b)
|
||||
}
|
||||
|
||||
// Two non-zero-width ranges, no overlap.
|
||||
assert!(!overlaps(&[(0, 3)], &[(3, 6)]));
|
||||
assert!(!overlaps(&[(0, 3)], &[(6, 3)]));
|
||||
assert!(!overlaps(&[(3, 0)], &[(3, 6)]));
|
||||
assert!(!overlaps(&[(3, 0)], &[(6, 3)]));
|
||||
assert!(!overlaps(&[(3, 6)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(3, 6)], &[(3, 0)]));
|
||||
assert!(!overlaps(&[(6, 3)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(6, 3)], &[(3, 0)]));
|
||||
|
||||
// more ranges in one or the other, no overlap
|
||||
assert!(!overlaps(&[(6, 3), (9, 6)], &[(3, 0)]));
|
||||
assert!(!overlaps(&[(6, 3), (6, 9)], &[(3, 0)]));
|
||||
assert!(!overlaps(&[(3, 6), (9, 6)], &[(3, 0)]));
|
||||
assert!(!overlaps(&[(3, 6), (6, 9)], &[(3, 0)]));
|
||||
assert!(!overlaps(&[(6, 3), (9, 6)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(6, 3), (6, 9)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(3, 6), (9, 6)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(3, 6), (6, 9)], &[(0, 3)]));
|
||||
|
||||
assert!(!overlaps(&[(6, 3)], &[(3, 0), (9, 6)]));
|
||||
assert!(!overlaps(&[(6, 3)], &[(3, 0), (6, 9)]));
|
||||
assert!(!overlaps(&[(3, 6)], &[(3, 0), (9, 6)]));
|
||||
assert!(!overlaps(&[(3, 6)], &[(3, 0), (6, 9)]));
|
||||
assert!(!overlaps(&[(6, 3)], &[(0, 3), (9, 6)]));
|
||||
assert!(!overlaps(&[(6, 3)], &[(0, 3), (6, 9)]));
|
||||
assert!(!overlaps(&[(3, 6)], &[(0, 3), (9, 6)]));
|
||||
assert!(!overlaps(&[(3, 6)], &[(0, 3), (6, 9)]));
|
||||
|
||||
// Two non-zero-width ranges, overlap.
|
||||
assert!(overlaps(&[(0, 4)], &[(3, 6)]));
|
||||
assert!(overlaps(&[(0, 4)], &[(6, 3)]));
|
||||
assert!(overlaps(&[(4, 0)], &[(3, 6)]));
|
||||
assert!(overlaps(&[(4, 0)], &[(6, 3)]));
|
||||
assert!(overlaps(&[(3, 6)], &[(0, 4)]));
|
||||
assert!(overlaps(&[(3, 6)], &[(4, 0)]));
|
||||
assert!(overlaps(&[(6, 3)], &[(0, 4)]));
|
||||
assert!(overlaps(&[(6, 3)], &[(4, 0)]));
|
||||
|
||||
// Two non-zero-width ranges, overlap, extra from one or the other
|
||||
assert!(overlaps(&[(0, 4), (7, 10)], &[(3, 6)]));
|
||||
assert!(overlaps(&[(0, 4), (7, 10)], &[(6, 3)]));
|
||||
assert!(overlaps(&[(4, 0), (7, 10)], &[(3, 6)]));
|
||||
assert!(overlaps(&[(4, 0), (7, 10)], &[(6, 3)]));
|
||||
assert!(overlaps(&[(3, 6), (7, 10)], &[(0, 4)]));
|
||||
assert!(overlaps(&[(3, 6), (7, 10)], &[(4, 0)]));
|
||||
assert!(overlaps(&[(6, 3), (7, 10)], &[(0, 4)]));
|
||||
assert!(overlaps(&[(6, 3), (7, 10)], &[(4, 0)]));
|
||||
assert!(overlaps(&[(0, 4), (10, 7)], &[(3, 6)]));
|
||||
assert!(overlaps(&[(0, 4), (10, 7)], &[(6, 3)]));
|
||||
assert!(overlaps(&[(4, 0), (10, 7)], &[(3, 6)]));
|
||||
assert!(overlaps(&[(4, 0), (10, 7)], &[(6, 3)]));
|
||||
assert!(overlaps(&[(3, 6), (10, 7)], &[(0, 4)]));
|
||||
assert!(overlaps(&[(3, 6), (10, 7)], &[(4, 0)]));
|
||||
assert!(overlaps(&[(6, 3), (10, 7)], &[(0, 4)]));
|
||||
assert!(overlaps(&[(6, 3), (10, 7)], &[(4, 0)]));
|
||||
|
||||
assert!(overlaps(&[(0, 4)], &[(3, 6), (7, 10)]));
|
||||
assert!(overlaps(&[(0, 4)], &[(6, 3), (7, 10)]));
|
||||
assert!(overlaps(&[(4, 0)], &[(3, 6), (7, 10)]));
|
||||
assert!(overlaps(&[(4, 0)], &[(6, 3), (7, 10)]));
|
||||
assert!(overlaps(&[(3, 6)], &[(0, 4), (7, 10)]));
|
||||
assert!(overlaps(&[(3, 6)], &[(4, 0), (7, 10)]));
|
||||
assert!(overlaps(&[(6, 3)], &[(0, 4), (7, 10)]));
|
||||
assert!(overlaps(&[(6, 3)], &[(4, 0), (7, 10)]));
|
||||
assert!(overlaps(&[(0, 4)], &[(3, 6), (10, 7)]));
|
||||
assert!(overlaps(&[(0, 4)], &[(6, 3), (10, 7)]));
|
||||
assert!(overlaps(&[(4, 0)], &[(3, 6), (10, 7)]));
|
||||
assert!(overlaps(&[(4, 0)], &[(6, 3), (10, 7)]));
|
||||
assert!(overlaps(&[(3, 6)], &[(0, 4), (10, 7)]));
|
||||
assert!(overlaps(&[(3, 6)], &[(4, 0), (10, 7)]));
|
||||
assert!(overlaps(&[(6, 3)], &[(0, 4), (10, 7)]));
|
||||
assert!(overlaps(&[(6, 3)], &[(4, 0), (10, 7)]));
|
||||
|
||||
// Zero-width and non-zero-width range, no overlap.
|
||||
assert!(!overlaps(&[(0, 3)], &[(3, 3)]));
|
||||
assert!(!overlaps(&[(3, 0)], &[(3, 3)]));
|
||||
assert!(!overlaps(&[(3, 3)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(3, 3)], &[(3, 0)]));
|
||||
|
||||
assert!(!overlaps(&[(0, 3), (7, 10)], &[(3, 3)]));
|
||||
assert!(!overlaps(&[(3, 0), (7, 10)], &[(3, 3)]));
|
||||
assert!(!overlaps(&[(3, 3), (7, 10)], &[(0, 3)]));
|
||||
assert!(!overlaps(&[(3, 3), (7, 10)], &[(3, 0)]));
|
||||
|
||||
assert!(!overlaps(&[(0, 3)], &[(3, 3), (7, 10)]));
|
||||
assert!(!overlaps(&[(3, 0)], &[(3, 3), (7, 10)]));
|
||||
assert!(!overlaps(&[(3, 3)], &[(0, 3), (7, 10)]));
|
||||
assert!(!overlaps(&[(3, 3)], &[(3, 0), (7, 10)]));
|
||||
|
||||
// Zero-width and non-zero-width range, overlap.
|
||||
assert!(overlaps(&[(1, 4)], &[(1, 1)]));
|
||||
assert!(overlaps(&[(4, 1)], &[(1, 1)]));
|
||||
assert!(overlaps(&[(1, 1)], &[(1, 4)]));
|
||||
assert!(overlaps(&[(1, 1)], &[(4, 1)]));
|
||||
|
||||
assert!(overlaps(&[(1, 4)], &[(3, 3)]));
|
||||
assert!(overlaps(&[(4, 1)], &[(3, 3)]));
|
||||
assert!(overlaps(&[(3, 3)], &[(1, 4)]));
|
||||
assert!(overlaps(&[(3, 3)], &[(4, 1)]));
|
||||
|
||||
assert!(overlaps(&[(1, 4), (7, 10)], &[(1, 1)]));
|
||||
assert!(overlaps(&[(4, 1), (7, 10)], &[(1, 1)]));
|
||||
assert!(overlaps(&[(1, 1), (7, 10)], &[(1, 4)]));
|
||||
assert!(overlaps(&[(1, 1), (7, 10)], &[(4, 1)]));
|
||||
|
||||
assert!(overlaps(&[(1, 4), (7, 10)], &[(3, 3)]));
|
||||
assert!(overlaps(&[(4, 1), (7, 10)], &[(3, 3)]));
|
||||
assert!(overlaps(&[(3, 3), (7, 10)], &[(1, 4)]));
|
||||
assert!(overlaps(&[(3, 3), (7, 10)], &[(4, 1)]));
|
||||
|
||||
assert!(overlaps(&[(1, 4)], &[(1, 1), (7, 10)]));
|
||||
assert!(overlaps(&[(4, 1)], &[(1, 1), (7, 10)]));
|
||||
assert!(overlaps(&[(1, 1)], &[(1, 4), (7, 10)]));
|
||||
assert!(overlaps(&[(1, 1)], &[(4, 1), (7, 10)]));
|
||||
|
||||
assert!(overlaps(&[(1, 4)], &[(3, 3), (7, 10)]));
|
||||
assert!(overlaps(&[(4, 1)], &[(3, 3), (7, 10)]));
|
||||
assert!(overlaps(&[(3, 3)], &[(1, 4), (7, 10)]));
|
||||
assert!(overlaps(&[(3, 3)], &[(4, 1), (7, 10)]));
|
||||
|
||||
// Two zero-width ranges, no overlap.
|
||||
assert!(!overlaps(&[(0, 0)], &[(1, 1)]));
|
||||
assert!(!overlaps(&[(1, 1)], &[(0, 0)]));
|
||||
|
||||
assert!(!overlaps(&[(0, 0), (2, 2)], &[(1, 1)]));
|
||||
assert!(!overlaps(&[(0, 0), (2, 2)], &[(1, 1)]));
|
||||
assert!(!overlaps(&[(1, 1)], &[(0, 0), (2, 2)]));
|
||||
assert!(!overlaps(&[(1, 1)], &[(0, 0), (2, 2)]));
|
||||
|
||||
// Two zero-width ranges, overlap.
|
||||
assert!(overlaps(&[(1, 1)], &[(1, 1)]));
|
||||
assert!(overlaps(&[(1, 1), (2, 2)], &[(1, 1)]));
|
||||
assert!(overlaps(&[(1, 1)], &[(1, 1), (2, 2)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_grapheme_aligned() {
|
||||
let r = Rope::from_str("\r\nHi\r\n");
|
||||
|
@ -1381,9 +1675,15 @@ mod test {
|
|||
// multiple matches
|
||||
assert!(contains(vec!((1, 1), (2, 2)), vec!((1, 1), (2, 2))));
|
||||
|
||||
// smaller set can't contain bigger
|
||||
// extra items out of range
|
||||
assert!(!contains(vec!((1, 1)), vec!((1, 1), (2, 2))));
|
||||
|
||||
// one big range can contain multiple smaller ranges
|
||||
assert!(contains(
|
||||
vec!((1, 10)),
|
||||
vec!((1, 1), (2, 2), (3, 3), (3, 5), (7, 10))
|
||||
));
|
||||
|
||||
assert!(contains(
|
||||
vec!((1, 1), (2, 4), (5, 6), (7, 9), (10, 13)),
|
||||
vec!((3, 4), (7, 9))
|
||||
|
@ -1396,4 +1696,143 @@ mod test {
|
|||
vec!((1, 2), (3, 4), (7, 9))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_selection_without() {
|
||||
let without = |one, two, expected: Option<_>| {
|
||||
println!("one: {:?}", one);
|
||||
println!("two: {:?}", two);
|
||||
println!("expected: {:?}", expected);
|
||||
|
||||
let (one_text, one_sel) = test::print(one);
|
||||
let (two_text, two_sel) = test::print(two);
|
||||
assert_eq!(one_text, two_text); // sanity
|
||||
let actual_sel = one_sel.without(&two_sel);
|
||||
|
||||
let expected_sel = expected.map(|exp| {
|
||||
let (expected_text, expected_sel) = test::print(exp);
|
||||
assert_eq!(two_text, expected_text);
|
||||
expected_sel
|
||||
});
|
||||
let actual = actual_sel
|
||||
.as_ref()
|
||||
.map(|sel| test::plain(two_text.to_string(), sel));
|
||||
|
||||
println!("actual: {:?}\n\n", actual);
|
||||
|
||||
assert_eq!(
|
||||
expected_sel,
|
||||
actual_sel,
|
||||
"expected: {:?}, got: {:?}",
|
||||
expected_sel
|
||||
.as_ref()
|
||||
.map(|sel| test::plain(two_text.to_string(), sel)),
|
||||
actual,
|
||||
);
|
||||
};
|
||||
|
||||
without(
|
||||
"#[foo bar baz|]#",
|
||||
"foo #[bar|]# baz",
|
||||
Some("#[foo |]#bar#( baz|)#"),
|
||||
);
|
||||
|
||||
without("#[foo bar baz|]#", "#[foo bar baz|]#", None);
|
||||
without("#[foo bar|]# baz", "#[foo bar baz|]#", None);
|
||||
without("foo #[bar|]# baz", "#[foo bar baz|]#", None);
|
||||
|
||||
// direction is preserved
|
||||
without(
|
||||
"#[|foo bar baz]#",
|
||||
"foo #[|bar]# baz",
|
||||
Some("#[|foo ]#bar#(| baz)#"),
|
||||
);
|
||||
|
||||
// preference for direction is given to the left
|
||||
without(
|
||||
"#[|foo bar baz]#",
|
||||
"foo #[bar|]# baz",
|
||||
Some("#[|foo ]#bar#(| baz)#"),
|
||||
);
|
||||
|
||||
// disjoint ranges on the right are ignored
|
||||
without(
|
||||
"#[foo bar|]# baz",
|
||||
"foo bar #[baz|]#",
|
||||
Some("#[foo bar|]# baz"),
|
||||
);
|
||||
without(
|
||||
"#[foo bar|]# baz",
|
||||
"foo bar#[ baz|]#",
|
||||
Some("#[foo bar|]# baz"),
|
||||
);
|
||||
without(
|
||||
"#(foo|)# #[bar|]# baz",
|
||||
"foo#[ b|]#ar ba#(z|)#",
|
||||
Some("#(foo|)# b#[ar|]# baz"),
|
||||
);
|
||||
|
||||
// ranges contained by those one on the right are removed
|
||||
without(
|
||||
"#[foo bar|]# #(b|)#az",
|
||||
"foo bar#[ b|]#a#(z|)#",
|
||||
Some("#[foo bar|]# baz"),
|
||||
);
|
||||
without(
|
||||
"#[foo|]# bar #(baz|)#",
|
||||
"foo bar#[ b|]#a#(z|)#",
|
||||
Some("#[foo|]# bar b#(a|)#z"),
|
||||
);
|
||||
without(
|
||||
"#[foo bar|]# #(b|)#az",
|
||||
"foo bar #[b|]#a#(z|)#",
|
||||
Some("#[foo bar|]# baz"),
|
||||
);
|
||||
without(
|
||||
"#[foo bar|]# #(b|)#a#(z|)#",
|
||||
"foo bar #[b|]#a#(z|)#",
|
||||
Some("#[foo bar|]# baz"),
|
||||
);
|
||||
without(
|
||||
"#[foo bar|]# #(b|)#a#(z|)#",
|
||||
"foo bar #[b|]#a#(z|)#",
|
||||
Some("#[foo bar|]# baz"),
|
||||
);
|
||||
|
||||
// more than one range intersected by a single range on the right
|
||||
without(
|
||||
"#[foo bar|]# #(baz|)#",
|
||||
"foo b#[ar ba|]#z",
|
||||
Some("#[foo b|]#ar ba#(z|)#"),
|
||||
);
|
||||
|
||||
// partial overlap
|
||||
without(
|
||||
"#[foo bar|]# baz",
|
||||
"foo #[bar baz|]#",
|
||||
Some("#[foo |]#bar baz"),
|
||||
);
|
||||
without(
|
||||
"#[foo bar|]# baz",
|
||||
"foo#[ bar baz|]#",
|
||||
Some("#[foo|]# bar baz"),
|
||||
);
|
||||
without(
|
||||
"#[foo bar|]# baz",
|
||||
"foo ba#[r baz|]#",
|
||||
Some("#[foo ba|]#r baz"),
|
||||
);
|
||||
without(
|
||||
"foo ba#[r baz|]#",
|
||||
"#[foo bar|]# baz",
|
||||
Some("foo bar#[ baz|]#"),
|
||||
);
|
||||
|
||||
// primary selection is moved - preference given to the left of a split
|
||||
without(
|
||||
"#(|foo)# #(|bar baz)# #[|quux]#",
|
||||
"f#(o|)#o ba#[r b|]#az q#(uu|)#x",
|
||||
Some("#(|f)#o#(|o)# #(|ba)#r b#(|az)# #[|q]#uu#(|x)#"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue