diff options
Diffstat (limited to 'crates/ra_analysis/src/symbol_index.rs')
-rw-r--r-- | crates/ra_analysis/src/symbol_index.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs new file mode 100644 index 000000000..ffbb6a29f --- /dev/null +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -0,0 +1,94 @@ | |||
1 | use std::{ | ||
2 | sync::Arc, | ||
3 | hash::{Hash, Hasher}, | ||
4 | }; | ||
5 | use ra_editor::{FileSymbol, file_symbols}; | ||
6 | use ra_syntax::{ | ||
7 | File, | ||
8 | SyntaxKind::{self, *}, | ||
9 | }; | ||
10 | use fst::{self, Streamer}; | ||
11 | use rayon::prelude::*; | ||
12 | use {Query, FileId, JobToken}; | ||
13 | |||
14 | #[derive(Debug)] | ||
15 | pub(crate) struct SymbolIndex { | ||
16 | symbols: Vec<(FileId, FileSymbol)>, | ||
17 | map: fst::Map, | ||
18 | } | ||
19 | |||
20 | impl Hash for SymbolIndex { | ||
21 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
22 | self.symbols.hash(hasher) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | impl SymbolIndex { | ||
27 | pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex { | ||
28 | let mut symbols = files | ||
29 | .flat_map(|(file_id, file)| { | ||
30 | file_symbols(&file) | ||
31 | .into_iter() | ||
32 | .map(move |symbol| { | ||
33 | (symbol.name.as_str().to_lowercase(), (file_id, symbol)) | ||
34 | }) | ||
35 | .collect::<Vec<_>>() | ||
36 | }) | ||
37 | .collect::<Vec<_>>(); | ||
38 | symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0)); | ||
39 | symbols.dedup_by(|s1, s2| s1.0 == s2.0); | ||
40 | let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = | ||
41 | symbols.into_iter().unzip(); | ||
42 | let map = fst::Map::from_iter( | ||
43 | names.into_iter().zip(0u64..) | ||
44 | ).unwrap(); | ||
45 | SymbolIndex { symbols, map } | ||
46 | } | ||
47 | |||
48 | pub(crate) fn for_file(file_id: FileId, file: File) -> SymbolIndex { | ||
49 | SymbolIndex::for_files(::rayon::iter::once((file_id, file))) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | impl Query { | ||
54 | pub(crate) fn search( | ||
55 | self, | ||
56 | indices: &[Arc<SymbolIndex>], | ||
57 | token: &JobToken, | ||
58 | ) -> Vec<(FileId, FileSymbol)> { | ||
59 | |||
60 | let mut op = fst::map::OpBuilder::new(); | ||
61 | for file_symbols in indices.iter() { | ||
62 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); | ||
63 | op = op.add(file_symbols.map.search(automaton)) | ||
64 | } | ||
65 | let mut stream = op.union(); | ||
66 | let mut res = Vec::new(); | ||
67 | while let Some((_, indexed_values)) = stream.next() { | ||
68 | if res.len() >= self.limit || token.is_canceled() { | ||
69 | break; | ||
70 | } | ||
71 | for indexed_value in indexed_values { | ||
72 | let file_symbols = &indices[indexed_value.index]; | ||
73 | let idx = indexed_value.value as usize; | ||
74 | |||
75 | let (file_id, symbol) = &file_symbols.symbols[idx]; | ||
76 | if self.only_types && !is_type(symbol.kind) { | ||
77 | continue; | ||
78 | } | ||
79 | if self.exact && symbol.name != self.query { | ||
80 | continue; | ||
81 | } | ||
82 | res.push((*file_id, symbol.clone())); | ||
83 | } | ||
84 | } | ||
85 | res | ||
86 | } | ||
87 | } | ||
88 | |||
89 | fn is_type(kind: SyntaxKind) -> bool { | ||
90 | match kind { | ||
91 | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true, | ||
92 | _ => false, | ||
93 | } | ||
94 | } | ||