diff options
Diffstat (limited to 'crates/libanalysis/idx.rs')
-rw-r--r-- | crates/libanalysis/idx.rs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/crates/libanalysis/idx.rs b/crates/libanalysis/idx.rs new file mode 100644 index 000000000..69a635aef --- /dev/null +++ b/crates/libanalysis/idx.rs | |||
@@ -0,0 +1,84 @@ | |||
1 | use std::path::PathBuf; | ||
2 | |||
3 | use fst; | ||
4 | use fst::IntoStreamer; | ||
5 | use file; | ||
6 | |||
7 | use fall_tree::{TextRange, NodeType}; | ||
8 | use indxr::{FileIndex, IndexableFileSet}; | ||
9 | |||
10 | use editor::line_index::{LineCol, LineIndex}; | ||
11 | use editor::fst_subseq::FstSubSeq; | ||
12 | use editor::file_symbols::process_symbols; | ||
13 | |||
14 | use syntax::{STRUCT_DEF, ENUM_DEF, TRAIT_DEF, TYPE_DEF}; | ||
15 | |||
16 | |||
17 | pub struct SymbolIndex { | ||
18 | index: FileIndex<FileSymbols>, | ||
19 | } | ||
20 | |||
21 | impl SymbolIndex { | ||
22 | pub fn new(roots: Vec<PathBuf>) -> SymbolIndex { | ||
23 | let file_set = IndexableFileSet::new(roots, "rs"); | ||
24 | let index = FileIndex::new(file_set, Box::new(|path| { | ||
25 | let text = file::get_text(path).ok()?; | ||
26 | Some(FileSymbols::new(text)) | ||
27 | })); | ||
28 | SymbolIndex { index } | ||
29 | } | ||
30 | |||
31 | pub fn query(&self, query: &str) -> Vec<(PathBuf, Symbol)> { | ||
32 | let mut query = Query::new(query); | ||
33 | let mut result = Vec::new(); | ||
34 | self.process_query(&query, &mut result); | ||
35 | if result.is_empty() && !query.all_symbols { | ||
36 | query.all_symbols = true; | ||
37 | self.process_query(&query, &mut result); | ||
38 | } | ||
39 | result | ||
40 | } | ||
41 | |||
42 | fn process_query(&self, query: &Query, acc: &mut Vec<(PathBuf, Symbol)>) { | ||
43 | self.index.process_files(&mut |file| { | ||
44 | query.process(&file.value, &mut |symbol| { | ||
45 | acc.push((file.path.clone(), symbol)) | ||
46 | }); | ||
47 | acc.len() > 512 | ||
48 | }); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | struct Query { | ||
53 | query: String, | ||
54 | all_symbols: bool, | ||
55 | } | ||
56 | |||
57 | impl Query { | ||
58 | fn new(query: &str) -> Query { | ||
59 | let all_symbols = query.contains("#"); | ||
60 | let query: String = query.chars() | ||
61 | .filter(|&c| c != '#') | ||
62 | .flat_map(char::to_lowercase) | ||
63 | .collect(); | ||
64 | Query { query, all_symbols } | ||
65 | } | ||
66 | |||
67 | fn process(&self, file: &FileSymbols, acc: &mut FnMut(Symbol)) { | ||
68 | fn is_type(ty: NodeType) -> bool { | ||
69 | match ty { | ||
70 | STRUCT_DEF | ENUM_DEF | TRAIT_DEF| TYPE_DEF => true, | ||
71 | _ => false, | ||
72 | } | ||
73 | } | ||
74 | |||
75 | let a = FstSubSeq::new(&self.query); | ||
76 | for idx in file.map.search(a).into_stream().into_values() { | ||
77 | let idx = idx as usize; | ||
78 | let symbol = file.symbols[idx].clone(); | ||
79 | if self.all_symbols || is_type(symbol.ty) { | ||
80 | acc(symbol) | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | } | ||