summaryrefslogtreecommitdiff
path: root/mut/neovim/pack/plugins/start/blink.cmp/lua/blink/cmp/fuzzy/keyword.rs
blob: 13d5020adb5fe021b667bd707ee7286c5036a670 (plain)
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
    static ref BACKWARD_REGEX: Regex = Regex::new(r"[\p{L}0-9_][\p{L}0-9_\\-]*$").unwrap();
    static ref FORWARD_REGEX: Regex = Regex::new(r"^[\p{L}0-9_\\-]+").unwrap();
}

/// Given a line and cursor position, returns the start and end indices of the keyword
pub fn get_keyword_range(line: &str, col: usize, match_suffix: bool) -> (usize, usize) {
    let before_match_start = BACKWARD_REGEX
        .find(&line[0..col.min(line.len())])
        .map(|m| m.start());
    if !match_suffix {
        return (before_match_start.unwrap_or(col), col);
    }

    let after_match_end = FORWARD_REGEX
        .find(&line[col.min(line.len())..])
        .map(|m| m.end() + col);
    (
        before_match_start.unwrap_or(col),
        after_match_end.unwrap_or(col),
    )
}

/// Given a string, guesses the start and end indices in the line for the specific item
/// 1. Get the keyword range (alphanumeric, underscore, hyphen) on the line and end of the item
///    text
/// 2. Check if the suffix of the item text matches the suffix of the line text, if so, include the
///    suffix in the range
///
/// Example:
///   line: example/str/trim
///   item: str/trim
///   matches on: str/trim
///
///   line: example/trim
///   item: str/trim
///   matches on: trim
///
/// TODO:
///   line: '
///   item: 'tabline'
///   matches on: '
pub fn guess_keyword_range_from_item(
    item_text: &str,
    line: &str,
    cursor_col: usize,
    match_suffix: bool,
) -> (usize, usize) {
    let line_range = get_keyword_range(line, cursor_col, match_suffix);
    let text_range = get_keyword_range(item_text, item_text.len(), false);

    let line_prefix = line.chars().take(line_range.0).collect::<String>();
    let text_prefix = item_text.chars().take(text_range.0).collect::<String>();
    if line_prefix.ends_with(&text_prefix) {
        return (line_range.0 - text_prefix.len(), line_range.1);
    }

    line_range
}

pub fn guess_keyword_from_item(
    item_text: &str,
    line: &str,
    cursor_col: usize,
    match_suffix: bool,
) -> String {
    let (start, end) = guess_keyword_range_from_item(item_text, line, cursor_col, match_suffix);
    line[start..end].to_string()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_keyword_range_unicode() {
        let line = "'вest'";
        let col = line.len() - 1;
        assert_eq!(get_keyword_range(line, col, false), (1, line.len() - 1));
    }
}