aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/idx.rs
blob: 69a635aefe6db4a27c871e8c0e7e9c0dad87c6b2 (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 std::path::PathBuf;

use fst;
use fst::IntoStreamer;
use file;

use fall_tree::{TextRange, NodeType};
use indxr::{FileIndex, IndexableFileSet};

use editor::line_index::{LineCol, LineIndex};
use editor::fst_subseq::FstSubSeq;
use editor::file_symbols::process_symbols;

use syntax::{STRUCT_DEF, ENUM_DEF, TRAIT_DEF, TYPE_DEF};


pub struct SymbolIndex {
    index: FileIndex<FileSymbols>,
}

impl SymbolIndex {
    pub fn new(roots: Vec<PathBuf>) -> SymbolIndex {
        let file_set = IndexableFileSet::new(roots, "rs");
        let index = FileIndex::new(file_set, Box::new(|path| {
            let text = file::get_text(path).ok()?;
            Some(FileSymbols::new(text))
        }));
        SymbolIndex { index }
    }

    pub fn query(&self, query: &str) -> Vec<(PathBuf, Symbol)> {
        let mut query = Query::new(query);
        let mut result = Vec::new();
        self.process_query(&query, &mut result);
        if result.is_empty() && !query.all_symbols {
            query.all_symbols = true;
            self.process_query(&query, &mut result);
        }
        result
    }

    fn process_query(&self, query: &Query, acc: &mut Vec<(PathBuf, Symbol)>) {
        self.index.process_files(&mut |file| {
            query.process(&file.value, &mut |symbol| {
                acc.push((file.path.clone(), symbol))
            });
            acc.len() > 512
        });
    }
}

struct Query {
    query: String,
    all_symbols: bool,
}

impl Query {
    fn new(query: &str) -> Query {
        let all_symbols = query.contains("#");
        let query: String = query.chars()
            .filter(|&c| c != '#')
            .flat_map(char::to_lowercase)
            .collect();
        Query { query, all_symbols }
    }

    fn process(&self, file: &FileSymbols, acc: &mut FnMut(Symbol)) {
        fn is_type(ty: NodeType) -> bool {
            match ty {
                STRUCT_DEF | ENUM_DEF | TRAIT_DEF| TYPE_DEF => true,
                _ => false,
            }
        }

        let a = FstSubSeq::new(&self.query);
        for idx in file.map.search(a).into_stream().into_values() {
            let idx = idx as usize;
            let symbol = file.symbols[idx].clone();
            if self.all_symbols || is_type(symbol.ty) {
                acc(symbol)
            }
        }
    }
}