aboutsummaryrefslogtreecommitdiff
path: root/helix-core/src/test.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-core/src/test.rs')
-rw-r--r--helix-core/src/test.rs145
1 files changed, 97 insertions, 48 deletions
diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs
index da4f8fac..964a770a 100644
--- a/helix-core/src/test.rs
+++ b/helix-core/src/test.rs
@@ -5,8 +5,10 @@ use std::cmp::Reverse;
/// Convert annotated test string to test string and selection.
///
-/// `^` for `anchor` and `|` for head (`@` for primary), both must appear
-/// or otherwise it will panic.
+/// `#[|` for primary selection with head before anchor followed by `]#`.
+/// `#(|` for secondary selection with head before anchor followed by `)#`.
+/// `#[` for primary selection with head after anchor followed by `|]#`.
+/// `#(` for secondary selection with head after anchor followed by `|)#`.
///
/// # Examples
///
@@ -15,7 +17,7 @@ use std::cmp::Reverse;
/// use smallvec::smallvec;
///
/// assert_eq!(
-/// print("^a@b|c^"),
+/// print("#[a|]#b#(|c)#"),
/// ("abc".to_owned(), Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0))
/// );
/// ```
@@ -26,56 +28,101 @@ use std::cmp::Reverse;
/// Panics when missing head or anchor.
/// Panics when head come after head or anchor come after anchor.
pub fn print(s: &str) -> (String, Selection) {
- let mut anchor = None;
- let mut head = None;
let mut primary = None;
let mut ranges = SmallVec::new();
- let mut i = 0;
- let s = s
- .chars()
- .filter(|c| {
- match c {
- '^' if anchor != None => panic!("anchor without head {s:?}"),
- '^' if head == None => anchor = Some(i),
- '^' => ranges.push(Range::new(i, head.take().unwrap())),
- '|' if head != None => panic!("head without anchor {s:?}"),
- '|' if anchor == None => head = Some(i),
- '|' => ranges.push(Range::new(anchor.take().unwrap(), i)),
- '@' if primary != None => panic!("head (primary) already appeared {s:?}"),
- '@' if head != None => panic!("head (primary) without anchor {s:?}"),
- '@' if anchor == None => {
- primary = Some(ranges.len());
- head = Some(i);
+ let mut iter = s.chars().peekable();
+ let mut left = String::with_capacity(s.len());
+ 'outer: while let Some(c) = iter.next() {
+ let start = left.len();
+ if c == '#' {
+ if iter.next_if_eq(&'[').is_some() {
+ if primary.is_some() {
+ panic!("primary `#[` already appeared {left:?} {s:?}");
}
- '@' => {
- primary = Some(ranges.len());
- ranges.push(Range::new(anchor.take().unwrap(), i));
+ if iter.next_if_eq(&'|').is_some() {
+ while let Some(c) = iter.next() {
+ if c == ']' && iter.next_if_eq(&'#').is_some() {
+ primary = Some(ranges.len());
+ ranges.push(Range::new(left.len(), start));
+ continue 'outer;
+ } else {
+ left.push(c);
+ }
+ }
+ panic!("missing primary end `]#` {left:?} {s:?}");
+ } else {
+ while let Some(c) = iter.next() {
+ if c == '|' {
+ if let Some(cc) = iter.next_if_eq(&']') {
+ if iter.next_if_eq(&'#').is_some() {
+ primary = Some(ranges.len());
+ ranges.push(Range::new(start, left.len()));
+ continue 'outer;
+ } else {
+ left.push(c);
+ left.push(cc);
+ }
+ } else {
+ left.push(c);
+ }
+ } else {
+ left.push(c);
+ }
+ }
+ panic!("missing primary end `|]#` {left:?} {s:?}");
}
- _ => {
- i += 1;
- return true;
+ } else if iter.next_if_eq(&'(').is_some() {
+ if iter.next_if_eq(&'|').is_some() {
+ while let Some(c) = iter.next() {
+ if c == ')' && iter.next_if_eq(&'#').is_some() {
+ ranges.push(Range::new(left.len(), start));
+ continue 'outer;
+ } else {
+ left.push(c);
+ }
+ }
+ panic!("missing end `)#` {left:?} {s:?}");
+ } else {
+ while let Some(c) = iter.next() {
+ if c == '|' {
+ if let Some(cc) = iter.next_if_eq(&')') {
+ if iter.next_if_eq(&'#').is_some() {
+ ranges.push(Range::new(start, left.len()));
+ continue 'outer;
+ } else {
+ left.push(c);
+ left.push(cc);
+ }
+ } else {
+ left.push(c);
+ }
+ } else {
+ left.push(c);
+ }
+ }
+ panic!("missing end `|)#` {left:?} {s:?}");
}
- };
- false
- })
- .collect();
- if head.is_some() {
- panic!("missing anchor (|) {s:?}");
- }
- if anchor.is_some() {
- panic!("missing head (^) {s:?}");
+ } else {
+ left.push(c);
+ }
+ } else {
+ left.push(c);
+ }
}
let primary = match primary {
Some(i) => i,
- None => panic!("missing primary (@) {s:?}"),
+ None => panic!("missing primary `#[|]#` {s:?}"),
};
let selection = Selection::new(ranges, primary);
- (s, selection)
+ (left, selection)
}
/// Convert test string and selection to annotated test string.
///
-/// `^` for `anchor` and `|` for head (`@` for primary).
+/// `#[|` for primary selection with head before anchor followed by `]#`.
+/// `#(|` for secondary selection with head before anchor followed by `)#`.
+/// `#[` for primary selection with head after anchor followed by `|]#`.
+/// `#(` for secondary selection with head after anchor followed by `|)#`.
///
/// # Examples
///
@@ -85,28 +132,30 @@ pub fn print(s: &str) -> (String, Selection) {
///
/// assert_eq!(
/// plain("abc", Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)),
-/// "^a@b|c^".to_owned()
+/// "#[a|]#b#(|c)#".to_owned()
/// );
/// ```
pub fn plain(s: &str, selection: Selection) -> String {
let primary = selection.primary_index();
- let mut out = String::with_capacity(s.len() + 2 * selection.len());
+ let mut out = String::with_capacity(s.len() + 5 * selection.len());
out.push_str(s);
let mut insertion: Vec<_> = selection
.iter()
.enumerate()
.flat_map(|(i, range)| {
- [
- // sort like this before reversed so anchor < head later
- (range.head, if i == primary { '@' } else { '|' }),
- (range.anchor, '^'),
- ]
+ // sort like this before reversed so anchor < head later
+ match (range.anchor < range.head, i == primary) {
+ (true, true) => [(range.anchor, "#["), (range.head, "|]#")],
+ (true, false) => [(range.anchor, "#("), (range.head, "|)#")],
+ (false, true) => [(range.anchor, "]#"), (range.head, "#[|")],
+ (false, false) => [(range.anchor, ")#"), (range.head, "#(|")],
+ }
})
.collect();
// insert in reverse order
insertion.sort_unstable_by_key(|k| Reverse(k.0));
- for (i, c) in insertion {
- out.insert(i, c);
+ for (i, s) in insertion {
+ out.insert_str(i, s);
}
out
}