1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
use crate::movement::{categorize, is_punctuation, is_word, skip_over_prev};
use ropey::RopeSlice;
#[must_use]
pub fn nth_prev_word_boundary(slice: RopeSlice, mut char_idx: usize, count: usize) -> usize {
let mut with_end = false;
for _ in 0..count {
if char_idx == 0 {
break;
}
// return if not skip while?
skip_over_prev(slice, &mut char_idx, |ch| ch == '\n');
with_end = skip_over_prev(slice, &mut char_idx, char::is_whitespace);
// refetch
let ch = slice.char(char_idx);
if is_word(ch) {
with_end = skip_over_prev(slice, &mut char_idx, is_word);
} else if is_punctuation(ch) {
with_end = skip_over_prev(slice, &mut char_idx, is_punctuation);
}
}
if with_end || char_idx == 0 {
char_idx
} else {
char_idx + 1
}
}
#[test]
fn different_prev_word_boundary() {
use ropey::Rope;
let t = |x, y| {
let text = Rope::from(x);
let out = nth_prev_word_boundary(text.slice(..), text.len_chars().saturating_sub(1), 1);
assert_eq!(text.slice(..out), y, r#"from "{}""#, x);
};
t("abcd\nefg\nwrs", "abcd\nefg\n");
t("abcd\nefg\n", "abcd\n");
t("abcd\n", "");
t("hello, world!", "hello, world");
t("hello, world", "hello, ");
t("hello, ", "hello");
t("hello", "");
t(",", "");
t("こんにちは、世界!", "こんにちは、世界");
t("こんにちは、世界", "こんにちは、");
t("こんにちは、", "こんにちは");
t("こんにちは", "");
t("この世界。", "この世界");
t("この世界", "");
t("お前はもう死んでいる", "");
t("その300円です", ""); // TODO: should stop at 300
t("唱k", ""); // TODO: should stop at 唱
t(",", "");
t("1 + 1 = 2", "1 + 1 = ");
t("1 + 1 =", "1 + 1 ");
t("1 + 1", "1 + ");
t("1 + ", "1 ");
t("1 ", "");
t("1+1=2", "1+1=");
t("", "");
}
|