aboutsummaryrefslogtreecommitdiff
path: root/helix-core
diff options
context:
space:
mode:
Diffstat (limited to 'helix-core')
-rw-r--r--helix-core/Cargo.toml1
-rw-r--r--helix-core/src/movement.rs14
-rw-r--r--helix-core/src/test.rs59
-rw-r--r--helix-core/src/textobject.rs6
4 files changed, 54 insertions, 26 deletions
diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml
index 62ec87b4..8618f586 100644
--- a/helix-core/Cargo.toml
+++ b/helix-core/Cargo.toml
@@ -49,3 +49,4 @@ textwrap = "0.16.0"
[dev-dependencies]
quickcheck = { version = "1", default-features = false }
+indoc = "1.0.6"
diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs
index 8e6b6306..bbb37bf4 100644
--- a/helix-core/src/movement.rs
+++ b/helix-core/src/movement.rs
@@ -1474,7 +1474,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Move));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -1497,7 +1497,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_prev_paragraph(text.slice(..), r, 2, Movement::Move));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -1520,7 +1520,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Extend));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -1540,7 +1540,7 @@ mod test {
"a\nb\n\n#[goto\nthird\n\n|]#paragraph",
),
(
- "a\nb#[\n|]#\ngoto\nsecond\n\nparagraph",
+ "a\nb#[\n|]#\n\ngoto\nsecond\n\nparagraph",
"a\nb#[\n\n|]#goto\nsecond\n\nparagraph",
),
(
@@ -1562,7 +1562,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Move));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -1585,7 +1585,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_next_paragraph(text.slice(..), r, 2, Movement::Move));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -1608,7 +1608,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Extend));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs
index 17523ed7..1d967f23 100644
--- a/helix-core/src/test.rs
+++ b/helix-core/src/test.rs
@@ -2,6 +2,7 @@
use crate::{Range, Selection};
use smallvec::SmallVec;
use std::cmp::Reverse;
+use unicode_segmentation::UnicodeSegmentation;
/// Convert annotated test string to test string and selection.
///
@@ -10,6 +11,10 @@ use std::cmp::Reverse;
/// `#[` for primary selection with head after anchor followed by `|]#`.
/// `#(` for secondary selection with head after anchor followed by `|)#`.
///
+/// If the selection contains any LF or CRLF sequences, which are immediately
+/// followed by the same grapheme, then the subsequent one is removed. This is
+/// to allow representing having the cursor over the end of the line.
+///
/// # Examples
///
/// ```
@@ -30,23 +35,23 @@ use std::cmp::Reverse;
pub fn print(s: &str) -> (String, Selection) {
let mut primary_idx = None;
let mut ranges = SmallVec::new();
- let mut iter = s.chars().peekable();
+ let mut iter = UnicodeSegmentation::graphemes(s, true).peekable();
let mut left = String::with_capacity(s.len());
'outer: while let Some(c) = iter.next() {
let start = left.chars().count();
- if c != '#' {
- left.push(c);
+ if c != "#" {
+ left.push_str(c);
continue;
}
let (is_primary, close_pair) = match iter.next() {
- Some('[') => (true, ']'),
- Some('(') => (false, ')'),
+ Some("[") => (true, "]"),
+ Some("(") => (false, ")"),
Some(ch) => {
left.push('#');
- left.push(ch);
+ left.push_str(ch);
continue;
}
None => break,
@@ -56,24 +61,45 @@ pub fn print(s: &str) -> (String, Selection) {
panic!("primary `#[` already appeared {:?} {:?}", left, s);
}
- let head_at_beg = iter.next_if_eq(&'|').is_some();
+ let head_at_beg = iter.next_if_eq(&"|").is_some();
+ let last_grapheme = |s: &str| {
+ UnicodeSegmentation::graphemes(s, true)
+ .last()
+ .map(String::from)
+ };
while let Some(c) = iter.next() {
- if !(c == close_pair && iter.peek() == Some(&'#')) {
- left.push(c);
+ let next = iter.peek();
+ let mut prev = last_grapheme(left.as_str());
+
+ if !(c == close_pair && next == Some(&"#")) {
+ left.push_str(c);
continue;
}
if !head_at_beg {
- let prev = left.pop().unwrap();
- if prev != '|' {
- left.push(prev);
- left.push(c);
- continue;
+ match &prev {
+ Some(p) if p != "|" => {
+ left.push_str(c);
+ continue;
+ }
+ Some(p) if p == "|" => {
+ left.pop().unwrap(); // pop the |
+ prev = last_grapheme(left.as_str());
+ }
+ _ => (),
}
}
iter.next(); // skip "#"
+ let next = iter.peek();
+
+ // skip explicit line end inside selection
+ if (prev == Some(String::from("\r\n")) || prev == Some(String::from("\n")))
+ && next.map(|n| String::from(*n)) == prev
+ {
+ iter.next();
+ }
if is_primary {
primary_idx = Some(ranges.len());
@@ -118,11 +144,11 @@ pub fn print(s: &str) -> (String, Selection) {
/// use smallvec::smallvec;
///
/// assert_eq!(
-/// plain("abc", Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)),
+/// plain("abc", &Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)),
/// "#[a|]#b#(|c)#".to_owned()
/// );
/// ```
-pub fn plain(s: &str, selection: Selection) -> String {
+pub fn plain(s: &str, selection: &Selection) -> String {
let primary = selection.primary_index();
let mut out = String::with_capacity(s.len() + 5 * selection.len());
out.push_str(s);
@@ -147,6 +173,7 @@ pub fn plain(s: &str, selection: Selection) -> String {
out
}
+#[allow(clippy::module_inception)]
#[cfg(test)]
#[allow(clippy::module_inception)]
mod test {
diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs
index 972a80e7..6e3f18cf 100644
--- a/helix-core/src/textobject.rs
+++ b/helix-core/src/textobject.rs
@@ -437,7 +437,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 1));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -460,7 +460,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 2));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
@@ -491,7 +491,7 @@ mod test {
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Around, 1));
- let actual = crate::test::plain(&s, selection);
+ let actual = crate::test::plain(&s, &selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}