aboutsummaryrefslogtreecommitdiff
path: root/helix-core/src/search.rs
blob: 7d790d66515063516edcac69a19a907a9f667216 (plain) (blame)
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
69
use crate::RopeSlice;

pub fn find_nth_next(text: RopeSlice, ch: char, pos: usize, n: usize) -> Option<usize> {
    // start searching right after pos
    let mut byte_idx = text.char_to_byte(pos + 1);

    let (mut chunks, mut chunk_byte_idx, _chunk_char_idx, _chunk_line_idx) =
        text.chunks_at_byte(byte_idx);

    let mut chunk = chunks.next().unwrap_or("");

    chunk = &chunk[(byte_idx - chunk_byte_idx)..];

    for _ in 0..n {
        loop {
            match chunk.find(ch) {
                Some(pos) => {
                    byte_idx += pos;
                    chunk = &chunk[pos + 1..];
                    break;
                }
                None => match chunks.next() {
                    Some(next_chunk) => {
                        byte_idx += chunk.len();
                        chunk = next_chunk;
                    }
                    None => {
                        log::info!("no more chunks");
                        return None;
                    }
                },
            }
        }
    }
    Some(text.byte_to_char(byte_idx))
}

pub fn find_nth_prev(text: RopeSlice, ch: char, pos: usize, n: usize) -> Option<usize> {
    // start searching right before pos
    let mut byte_idx = text.char_to_byte(pos.saturating_sub(1));

    let (mut chunks, mut chunk_byte_idx, _chunk_char_idx, _chunk_line_idx) =
        text.chunks_at_byte(byte_idx);

    let mut chunk = chunks.prev().unwrap_or("");

    // start searching from pos
    chunk = &chunk[..=byte_idx - chunk_byte_idx];

    for _ in 0..n {
        loop {
            match chunk.rfind(ch) {
                Some(pos) => {
                    byte_idx = chunk_byte_idx + pos;
                    chunk = &chunk[..pos];
                    break;
                }
                None => match chunks.prev() {
                    Some(prev_chunk) => {
                        chunk_byte_idx -= chunk.len();
                        chunk = prev_chunk;
                    }
                    None => return None,
                },
            }
        }
    }
    Some(text.byte_to_char(byte_idx))
}