aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/symbol_index.rs
blob: 88d5c499520f420ff23e391f9dfbec4acf64b6e8 (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
85
86
use libeditor::{FileSymbol, file_symbols};
use libsyntax2::{
    ast,
    SyntaxKind::{self, *},
};
use fst::{self, IntoStreamer, Streamer};

#[derive(Debug)]
pub(crate) struct FileSymbols {
    symbols: Vec<FileSymbol>,
    map: fst::Map,
}

impl FileSymbols {
    pub(crate) fn new(file: &ast::File) -> FileSymbols {
        let mut symbols = file_symbols(file)
            .into_iter()
            .map(|s| (s.name.as_str().to_lowercase(), s))
            .collect::<Vec<_>>();

        symbols.sort_by(|s1, s2| s1.0.cmp(&s2.0));
        symbols.dedup_by(|s1, s2| s1.0 == s2.0);
        let (names, symbols): (Vec<String>, Vec<FileSymbol>) =
            symbols.into_iter().unzip();

        let map = fst::Map::from_iter(
            names.into_iter().zip(0u64..)
        ).unwrap();
        FileSymbols { symbols, map }
    }
}

pub struct Query {
    query: String,
    lowercased: String,
    only_types: bool,
    exact: bool,
}

impl Query {
    pub fn new(query: String) -> Query {
        let lowercased = query.to_lowercase();
        Query {
            query,
            lowercased,
            only_types: false,
            exact: false,
        }
    }

    pub fn only_types(&mut self) {
        self.only_types = true;
    }

    pub fn exact(&mut self) {
        self.exact = true;
    }

    pub(crate) fn process<'a>(
        &self,
        file: &'a FileSymbols,
    ) -> impl Iterator<Item=&'a FileSymbol> + 'a {
        fn is_type(kind: SyntaxKind) -> bool {
            match kind {
                STRUCT | ENUM | TRAIT | TYPE_ITEM => true,
                _ => false,
            }
        }
        let automaton = fst::automaton::Subsequence::new(&self.lowercased);
        let mut stream = file.map.search(automaton).into_stream();
        let mut res = Vec::new();
        while let Some((_, idx)) = stream.next() {
            let idx = idx as usize;
            let symbol = &file.symbols[idx];
            if self.only_types && !is_type(symbol.kind) {
                continue;
            }
            if self.exact && symbol.name != self.query {
                continue;
            }
            res.push(symbol)
        }
        res.into_iter()
    }
}