@@ -0,0 +1,69 @@
1+use crate::RopeSlice;
2+
3+pub fn find_nth_next(text: RopeSlice, ch: char, pos: usize, n: usize) -> Option<usize> {
4+ // start searching right after pos
5+ let mut byte_idx = text.char_to_byte(pos + 1);
6+
7+ let (mut chunks, mut chunk_byte_idx, _chunk_char_idx, _chunk_line_idx) =
8+ text.chunks_at_byte(byte_idx);
9+
10+ let mut chunk = chunks.next().unwrap_or("");
11+
12+ chunk = &chunk[(byte_idx - chunk_byte_idx)..];
13+
14+ for _ in 0..n {
15+ loop {
16+ match chunk.find(ch) {
17+ Some(pos) => {
18+ byte_idx += pos;
19+ chunk = &chunk[pos + 1..];
20+ break;
21+ }
22+ None => match chunks.next() {
23+ Some(next_chunk) => {
24+ byte_idx += chunk.len();
25+ chunk = next_chunk;
26+ }
27+ None => {
28+ log::info!("no more chunks");
29+ return None;
30+ }
31+ },
32+ }
33+ }
34+ }
35+ Some(text.byte_to_char(byte_idx))
36+}
37+
38+pub fn find_nth_prev(text: RopeSlice, ch: char, pos: usize, n: usize) -> Option<usize> {
39+ // start searching right before pos
40+ let mut byte_idx = text.char_to_byte(pos.saturating_sub(1));
41+
42+ let (mut chunks, mut chunk_byte_idx, _chunk_char_idx, _chunk_line_idx) =
43+ text.chunks_at_byte(byte_idx);
44+
45+ let mut chunk = chunks.prev().unwrap_or("");
46+
47+ // start searching from pos
48+ chunk = &chunk[..=byte_idx - chunk_byte_idx];
49+
50+ for _ in 0..n {
51+ loop {
52+ match chunk.rfind(ch) {
53+ Some(pos) => {
54+ byte_idx = chunk_byte_idx + pos;
55+ chunk = &chunk[..pos];
56+ break;
57+ }
58+ None => match chunks.prev() {
59+ Some(prev_chunk) => {
60+ chunk_byte_idx -= chunk.len();
61+ chunk = prev_chunk;
62+ }
63+ None => return None,
64+ },
65+ }
66+ }
67+ }
68+ Some(text.byte_to_char(byte_idx))
69+}