diff options
author | Aleksey Kladov <[email protected]> | 2018-09-03 17:46:30 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-09-03 17:46:30 +0100 |
commit | b04c14d4ad51433b0055e2e5799f98da20d15d58 (patch) | |
tree | 18bd67e27c515d48be6725230b274b2eb55c740d /crates/libanalysis/src | |
parent | 2f2feef9afe8f1c75f743a56f945a1560ca85af4 (diff) |
dispatch acros roots
Diffstat (limited to 'crates/libanalysis/src')
-rw-r--r-- | crates/libanalysis/src/imp.rs | 65 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 4 | ||||
-rw-r--r-- | crates/libanalysis/src/roots.rs | 143 | ||||
-rw-r--r-- | crates/libanalysis/src/symbol_index.rs | 35 |
5 files changed, 180 insertions, 75 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 73a6f4306..c1e144025 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -17,8 +17,8 @@ use libsyntax2::{ | |||
17 | use { | 17 | use { |
18 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, | 18 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, |
19 | JobToken, CrateGraph, CrateId, | 19 | JobToken, CrateGraph, CrateId, |
20 | module_map::Problem, | 20 | module_map::{ModuleMap, Problem}, |
21 | roots::SourceRoot, | 21 | roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | #[derive(Debug)] | 24 | #[derive(Debug)] |
@@ -57,6 +57,10 @@ impl AnalysisHostImpl { | |||
57 | } | 57 | } |
58 | self.data_mut().crate_graph = graph; | 58 | self.data_mut().crate_graph = graph; |
59 | } | 59 | } |
60 | pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) { | ||
61 | let libs = libs.map(ReadonlySourceRoot::new).collect::<Vec<_>>(); | ||
62 | self.data_mut().libs = Arc::new(libs); | ||
63 | } | ||
60 | fn data_mut(&mut self) -> &mut WorldData { | 64 | fn data_mut(&mut self) -> &mut WorldData { |
61 | Arc::make_mut(&mut self.data) | 65 | Arc::make_mut(&mut self.data) |
62 | } | 66 | } |
@@ -85,19 +89,33 @@ impl Clone for AnalysisImpl { | |||
85 | } | 89 | } |
86 | 90 | ||
87 | impl AnalysisImpl { | 91 | impl AnalysisImpl { |
92 | fn root(&self, file_id: FileId) -> &SourceRoot { | ||
93 | if self.data.root.contains(file_id) { | ||
94 | return &self.data.root; | ||
95 | } | ||
96 | self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() | ||
97 | } | ||
88 | pub fn file_syntax(&self, file_id: FileId) -> &File { | 98 | pub fn file_syntax(&self, file_id: FileId) -> &File { |
89 | self.data.root.syntax(file_id) | 99 | self.root(file_id).syntax(file_id) |
90 | } | 100 | } |
91 | pub fn file_line_index(&self, file_id: FileId) -> &LineIndex { | 101 | pub fn file_line_index(&self, file_id: FileId) -> &LineIndex { |
92 | self.data.root.lines(file_id) | 102 | self.root(file_id).lines(file_id) |
93 | } | 103 | } |
94 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 104 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
95 | self.reindex(); | 105 | self.reindex(); |
96 | query.search(&self.data.root.symbols(), token) | 106 | let mut buf = Vec::new(); |
107 | if query.libs { | ||
108 | self.data.libs.iter() | ||
109 | .for_each(|it| it.symbols(&mut buf)); | ||
110 | } else { | ||
111 | self.data.root.symbols(&mut buf); | ||
112 | } | ||
113 | query.search(&buf, token) | ||
114 | |||
97 | } | 115 | } |
98 | pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> { | 116 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { |
99 | let module_map = self.data.root.module_map(); | 117 | let module_map = self.root(file_id).module_map(); |
100 | let id = module_map.file2module(id); | 118 | let id = module_map.file2module(file_id); |
101 | module_map | 119 | module_map |
102 | .parent_modules( | 120 | .parent_modules( |
103 | id, | 121 | id, |
@@ -117,12 +135,12 @@ impl AnalysisImpl { | |||
117 | .collect() | 135 | .collect() |
118 | } | 136 | } |
119 | 137 | ||
120 | pub fn crate_for(&self, id: FileId) -> Vec<CrateId> { | 138 | pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { |
121 | let module_map = self.data.root.module_map(); | 139 | let module_map = self.root(file_id).module_map(); |
122 | let crate_graph = &self.data.crate_graph; | 140 | let crate_graph = &self.data.crate_graph; |
123 | let mut res = Vec::new(); | 141 | let mut res = Vec::new(); |
124 | let mut work = VecDeque::new(); | 142 | let mut work = VecDeque::new(); |
125 | work.push_back(id); | 143 | work.push_back(file_id); |
126 | let mut visited = HashSet::new(); | 144 | let mut visited = HashSet::new(); |
127 | while let Some(id) = work.pop_front() { | 145 | while let Some(id) = work.pop_front() { |
128 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) { | 146 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) { |
@@ -148,11 +166,13 @@ impl AnalysisImpl { | |||
148 | } | 166 | } |
149 | pub fn approximately_resolve_symbol( | 167 | pub fn approximately_resolve_symbol( |
150 | &self, | 168 | &self, |
151 | id: FileId, | 169 | file_id: FileId, |
152 | offset: TextUnit, | 170 | offset: TextUnit, |
153 | token: &JobToken, | 171 | token: &JobToken, |
154 | ) -> Vec<(FileId, FileSymbol)> { | 172 | ) -> Vec<(FileId, FileSymbol)> { |
155 | let file = self.file_syntax(id); | 173 | let root = self.root(file_id); |
174 | let module_map = root.module_map(); | ||
175 | let file = root.syntax(file_id); | ||
156 | let syntax = file.syntax(); | 176 | let syntax = file.syntax(); |
157 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 177 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
158 | return self.index_resolve(name_ref, token); | 178 | return self.index_resolve(name_ref, token); |
@@ -160,7 +180,7 @@ impl AnalysisImpl { | |||
160 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { | 180 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { |
161 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 181 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
162 | if module.has_semi() { | 182 | if module.has_semi() { |
163 | let file_ids = self.resolve_module(id, module); | 183 | let file_ids = self.resolve_module(module_map, file_id, module); |
164 | 184 | ||
165 | let res = file_ids.into_iter().map(|id| { | 185 | let res = file_ids.into_iter().map(|id| { |
166 | let name = module.name() | 186 | let name = module.name() |
@@ -182,13 +202,16 @@ impl AnalysisImpl { | |||
182 | } | 202 | } |
183 | 203 | ||
184 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { | 204 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { |
185 | let syntax = self.file_syntax(file_id); | 205 | let root = self.root(file_id); |
206 | let module_map = root.module_map(); | ||
207 | let syntax = root.syntax(file_id); | ||
208 | |||
186 | let mut res = libeditor::diagnostics(&syntax) | 209 | let mut res = libeditor::diagnostics(&syntax) |
187 | .into_iter() | 210 | .into_iter() |
188 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) | 211 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) |
189 | .collect::<Vec<_>>(); | 212 | .collect::<Vec<_>>(); |
190 | 213 | ||
191 | self.data.root.module_map().problems( | 214 | module_map.problems( |
192 | file_id, | 215 | file_id, |
193 | &*self.file_resolver, | 216 | &*self.file_resolver, |
194 | &|file_id| self.file_syntax(file_id), | 217 | &|file_id| self.file_syntax(file_id), |
@@ -257,13 +280,12 @@ impl AnalysisImpl { | |||
257 | self.world_symbols(query, token) | 280 | self.world_symbols(query, token) |
258 | } | 281 | } |
259 | 282 | ||
260 | fn resolve_module(&self, id: FileId, module: ast::Module) -> Vec<FileId> { | 283 | fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::Module) -> Vec<FileId> { |
261 | let name = match module.name() { | 284 | let name = match module.name() { |
262 | Some(name) => name.text(), | 285 | Some(name) => name.text(), |
263 | None => return Vec::new(), | 286 | None => return Vec::new(), |
264 | }; | 287 | }; |
265 | let module_map = self.data.root.module_map(); | 288 | let id = module_map.file2module(file_id); |
266 | let id = module_map.file2module(id); | ||
267 | module_map | 289 | module_map |
268 | .child_module_by_name( | 290 | .child_module_by_name( |
269 | id, name.as_str(), | 291 | id, name.as_str(), |
@@ -285,7 +307,8 @@ impl AnalysisImpl { | |||
285 | #[derive(Clone, Default, Debug)] | 307 | #[derive(Clone, Default, Debug)] |
286 | struct WorldData { | 308 | struct WorldData { |
287 | crate_graph: CrateGraph, | 309 | crate_graph: CrateGraph, |
288 | root: SourceRoot, | 310 | root: WritableSourceRoot, |
311 | libs: Arc<Vec<ReadonlySourceRoot>>, | ||
289 | } | 312 | } |
290 | 313 | ||
291 | impl SourceChange { | 314 | impl SourceChange { |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index b044fdae8..9ae87d46c 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -68,6 +68,9 @@ impl AnalysisHost { | |||
68 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 68 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
69 | self.imp.set_crate_graph(graph) | 69 | self.imp.set_crate_graph(graph) |
70 | } | 70 | } |
71 | pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) { | ||
72 | self.imp.set_libraries(libs) | ||
73 | } | ||
71 | } | 74 | } |
72 | 75 | ||
73 | #[derive(Debug)] | 76 | #[derive(Debug)] |
@@ -114,6 +117,7 @@ pub struct Query { | |||
114 | query: String, | 117 | query: String, |
115 | lowercased: String, | 118 | lowercased: String, |
116 | only_types: bool, | 119 | only_types: bool, |
120 | libs: bool, | ||
117 | exact: bool, | 121 | exact: bool, |
118 | limit: usize, | 122 | limit: usize, |
119 | } | 123 | } |
@@ -125,6 +129,7 @@ impl Query { | |||
125 | query, | 129 | query, |
126 | lowercased, | 130 | lowercased, |
127 | only_types: false, | 131 | only_types: false, |
132 | libs: false, | ||
128 | exact: false, | 133 | exact: false, |
129 | limit: usize::max_value() | 134 | limit: usize::max_value() |
130 | } | 135 | } |
@@ -132,6 +137,9 @@ impl Query { | |||
132 | pub fn only_types(&mut self) { | 137 | pub fn only_types(&mut self) { |
133 | self.only_types = true; | 138 | self.only_types = true; |
134 | } | 139 | } |
140 | pub fn libs(&mut self) { | ||
141 | self.libs = true; | ||
142 | } | ||
135 | pub fn exact(&mut self) { | 143 | pub fn exact(&mut self) { |
136 | self.exact = true; | 144 | self.exact = true; |
137 | } | 145 | } |
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs index 5ceb71817..1b225ecee 100644 --- a/crates/libanalysis/src/module_map.rs +++ b/crates/libanalysis/src/module_map.rs | |||
@@ -56,6 +56,10 @@ pub enum Problem { | |||
56 | } | 56 | } |
57 | 57 | ||
58 | impl ModuleMap { | 58 | impl ModuleMap { |
59 | pub fn new() -> ModuleMap { | ||
60 | Default::default() | ||
61 | } | ||
62 | |||
59 | pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) { | 63 | pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) { |
60 | self.state.get_mut().changes.push((file, change_kind)); | 64 | self.state.get_mut().changes.push((file, change_kind)); |
61 | } | 65 | } |
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs index 01de3e128..a65668c9b 100644 --- a/crates/libanalysis/src/roots.rs +++ b/crates/libanalysis/src/roots.rs | |||
@@ -13,16 +13,24 @@ use libsyntax2::File; | |||
13 | use { | 13 | use { |
14 | FileId, | 14 | FileId, |
15 | module_map::{ModuleMap, ChangeKind}, | 15 | module_map::{ModuleMap, ChangeKind}, |
16 | symbol_index::FileSymbols, | 16 | symbol_index::SymbolIndex, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | pub(crate) trait SourceRoot { | ||
20 | fn contains(&self, file_id: FileId) -> bool; | ||
21 | fn module_map(&self) -> &ModuleMap; | ||
22 | fn lines(&self, file_id: FileId) -> &LineIndex; | ||
23 | fn syntax(&self, file_id: FileId) -> &File; | ||
24 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>); | ||
25 | } | ||
26 | |||
19 | #[derive(Clone, Default, Debug)] | 27 | #[derive(Clone, Default, Debug)] |
20 | pub(crate) struct SourceRoot { | 28 | pub(crate) struct WritableSourceRoot { |
21 | file_map: HashMap<FileId, Arc<(FileData, OnceCell<FileSymbols>)>>, | 29 | file_map: HashMap<FileId, Arc<(FileData, OnceCell<SymbolIndex>)>>, |
22 | module_map: ModuleMap, | 30 | module_map: ModuleMap, |
23 | } | 31 | } |
24 | 32 | ||
25 | impl SourceRoot { | 33 | impl WritableSourceRoot { |
26 | pub fn update(&mut self, file_id: FileId, text: Option<String>) { | 34 | pub fn update(&mut self, file_id: FileId, text: Option<String>) { |
27 | let change_kind = if self.file_map.remove(&file_id).is_some() { | 35 | let change_kind = if self.file_map.remove(&file_id).is_some() { |
28 | if text.is_some() { | 36 | if text.is_some() { |
@@ -40,31 +48,6 @@ impl SourceRoot { | |||
40 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); | 48 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); |
41 | } | 49 | } |
42 | } | 50 | } |
43 | pub fn module_map(&self) -> &ModuleMap { | ||
44 | &self.module_map | ||
45 | } | ||
46 | pub fn lines(&self, file_id: FileId) -> &LineIndex { | ||
47 | let data = self.data(file_id); | ||
48 | data.lines.get_or_init(|| LineIndex::new(&data.text)) | ||
49 | } | ||
50 | pub fn syntax(&self, file_id: FileId) -> &File { | ||
51 | let data = self.data(file_id); | ||
52 | let text = &data.text; | ||
53 | let syntax = &data.syntax; | ||
54 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
55 | Ok(file) => file, | ||
56 | Err(err) => { | ||
57 | error!("Parser paniced on:\n------\n{}\n------\n", &data.text); | ||
58 | panic::resume_unwind(err) | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | pub(crate) fn symbols(&self) -> Vec<&FileSymbols> { | ||
63 | self.file_map | ||
64 | .iter() | ||
65 | .map(|(&file_id, data)| symbols(file_id, data)) | ||
66 | .collect() | ||
67 | } | ||
68 | pub fn reindex(&self) { | 51 | pub fn reindex(&self) { |
69 | let now = Instant::now(); | 52 | let now = Instant::now(); |
70 | self.file_map | 53 | self.file_map |
@@ -83,9 +66,31 @@ impl SourceRoot { | |||
83 | } | 66 | } |
84 | } | 67 | } |
85 | 68 | ||
86 | fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<FileSymbols>)) -> &FileSymbols { | 69 | impl SourceRoot for WritableSourceRoot { |
70 | fn contains(&self, file_id: FileId) -> bool { | ||
71 | self.file_map.contains_key(&file_id) | ||
72 | } | ||
73 | fn module_map(&self) -> &ModuleMap { | ||
74 | &self.module_map | ||
75 | } | ||
76 | fn lines(&self, file_id: FileId) -> &LineIndex { | ||
77 | self.data(file_id).lines() | ||
78 | } | ||
79 | fn syntax(&self, file_id: FileId) -> &File { | ||
80 | self.data(file_id).syntax() | ||
81 | } | ||
82 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { | ||
83 | acc.extend( | ||
84 | self.file_map | ||
85 | .iter() | ||
86 | .map(|(&file_id, data)| symbols(file_id, data)) | ||
87 | ) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<SymbolIndex>)) -> &SymbolIndex { | ||
87 | let syntax = data.syntax_transient(); | 92 | let syntax = data.syntax_transient(); |
88 | symbols.get_or_init(|| FileSymbols::new(file_id, &syntax)) | 93 | symbols.get_or_init(|| SymbolIndex::for_file(file_id, syntax)) |
89 | } | 94 | } |
90 | 95 | ||
91 | #[derive(Debug)] | 96 | #[derive(Debug)] |
@@ -103,19 +108,77 @@ impl FileData { | |||
103 | lines: OnceCell::new(), | 108 | lines: OnceCell::new(), |
104 | } | 109 | } |
105 | } | 110 | } |
111 | fn lines(&self) -> &LineIndex { | ||
112 | self.lines.get_or_init(|| LineIndex::new(&self.text)) | ||
113 | } | ||
114 | fn syntax(&self) -> &File { | ||
115 | let text = &self.text; | ||
116 | let syntax = &self.syntax; | ||
117 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
118 | Ok(file) => file, | ||
119 | Err(err) => { | ||
120 | error!("Parser paniced on:\n------\n{}\n------\n", text); | ||
121 | panic::resume_unwind(err) | ||
122 | } | ||
123 | } | ||
124 | } | ||
106 | fn syntax_transient(&self) -> File { | 125 | fn syntax_transient(&self) -> File { |
107 | self.syntax.get().map(|s| s.clone()) | 126 | self.syntax.get().map(|s| s.clone()) |
108 | .unwrap_or_else(|| File::parse(&self.text)) | 127 | .unwrap_or_else(|| File::parse(&self.text)) |
109 | } | 128 | } |
110 | } | 129 | } |
111 | 130 | ||
112 | // #[derive(Clone, Default, Debug)] | 131 | #[derive(Debug)] |
113 | // pub(crate) struct ReadonlySourceRoot { | 132 | pub(crate) struct ReadonlySourceRoot { |
114 | // data: Arc<ReadonlySourceRoot> | 133 | symbol_index: SymbolIndex, |
115 | // } | 134 | file_map: HashMap<FileId, FileData>, |
135 | module_map: ModuleMap, | ||
136 | } | ||
116 | 137 | ||
117 | // #[derive(Clone, Default, Debug)] | 138 | impl ReadonlySourceRoot { |
118 | // pub(crate) struct ReadonlySourceRootInner { | 139 | pub fn new(files: impl Iterator<Item=(FileId, String)>) -> ReadonlySourceRoot { |
119 | // file_map: HashMap<FileId, FileData>, | 140 | let mut module_map = ModuleMap::new(); |
120 | // module_map: ModuleMap, | 141 | let file_map: HashMap<FileId, FileData> = files |
121 | // } | 142 | .map(|(id, text)| { |
143 | module_map.update_file(id, ChangeKind::Insert); | ||
144 | (id, FileData::new(text)) | ||
145 | }) | ||
146 | .collect(); | ||
147 | let symbol_index = SymbolIndex::for_files( | ||
148 | file_map.par_iter().map(|(&file_id, file_data)| { | ||
149 | (file_id, file_data.syntax_transient()) | ||
150 | }) | ||
151 | ); | ||
152 | |||
153 | ReadonlySourceRoot { | ||
154 | symbol_index, | ||
155 | file_map, | ||
156 | module_map, | ||
157 | } | ||
158 | } | ||
159 | |||
160 | fn data(&self, file_id: FileId) -> &FileData { | ||
161 | match self.file_map.get(&file_id) { | ||
162 | Some(data) => data, | ||
163 | None => panic!("unknown file: {:?}", file_id), | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | impl SourceRoot for ReadonlySourceRoot { | ||
169 | fn contains(&self, file_id: FileId) -> bool { | ||
170 | self.file_map.contains_key(&file_id) | ||
171 | } | ||
172 | fn module_map(&self) -> &ModuleMap { | ||
173 | &self.module_map | ||
174 | } | ||
175 | fn lines(&self, file_id: FileId) -> &LineIndex { | ||
176 | self.data(file_id).lines() | ||
177 | } | ||
178 | fn syntax(&self, file_id: FileId) -> &File { | ||
179 | self.data(file_id).syntax() | ||
180 | } | ||
181 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { | ||
182 | acc.push(&self.symbol_index) | ||
183 | } | ||
184 | } | ||
diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs index 54952cb94..8fef326ab 100644 --- a/crates/libanalysis/src/symbol_index.rs +++ b/crates/libanalysis/src/symbol_index.rs | |||
@@ -4,39 +4,46 @@ use libsyntax2::{ | |||
4 | SyntaxKind::{self, *}, | 4 | SyntaxKind::{self, *}, |
5 | }; | 5 | }; |
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
7 | use rayon::prelude::*; | ||
7 | use {Query, FileId, JobToken}; | 8 | use {Query, FileId, JobToken}; |
8 | 9 | ||
9 | #[derive(Debug)] | 10 | #[derive(Debug)] |
10 | pub(crate) struct FileSymbols { | 11 | pub(crate) struct SymbolIndex { |
11 | symbols: Vec<(FileId, FileSymbol)>, | 12 | symbols: Vec<(FileId, FileSymbol)>, |
12 | map: fst::Map, | 13 | map: fst::Map, |
13 | } | 14 | } |
14 | 15 | ||
15 | impl FileSymbols { | 16 | impl SymbolIndex { |
16 | pub(crate) fn new(file_id: FileId, file: &File) -> FileSymbols { | 17 | pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex { |
17 | let mut symbols = file_symbols(file) | 18 | let mut symbols = files |
18 | .into_iter() | 19 | .flat_map(|(file_id, file)| { |
19 | .map(|s| (s.name.as_str().to_lowercase(), s)) | 20 | file_symbols(&file) |
21 | .into_iter() | ||
22 | .map(move |symbol| { | ||
23 | (symbol.name.as_str().to_lowercase(), (file_id, symbol)) | ||
24 | }) | ||
25 | .collect::<Vec<_>>() | ||
26 | }) | ||
20 | .collect::<Vec<_>>(); | 27 | .collect::<Vec<_>>(); |
21 | 28 | symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0)); | |
22 | symbols.sort_by(|s1, s2| s1.0.cmp(&s2.0)); | ||
23 | symbols.dedup_by(|s1, s2| s1.0 == s2.0); | 29 | symbols.dedup_by(|s1, s2| s1.0 == s2.0); |
24 | let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = | 30 | let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = |
25 | symbols.into_iter() | 31 | symbols.into_iter().unzip(); |
26 | .map(|(name, symbol)| (name, (file_id, symbol))) | ||
27 | .unzip(); | ||
28 | |||
29 | let map = fst::Map::from_iter( | 32 | let map = fst::Map::from_iter( |
30 | names.into_iter().zip(0u64..) | 33 | names.into_iter().zip(0u64..) |
31 | ).unwrap(); | 34 | ).unwrap(); |
32 | FileSymbols { symbols, map } | 35 | SymbolIndex { symbols, map } |
36 | } | ||
37 | |||
38 | pub(crate) fn for_file(file_id: FileId, file: File) -> SymbolIndex { | ||
39 | SymbolIndex::for_files(::rayon::iter::once((file_id, file))) | ||
33 | } | 40 | } |
34 | } | 41 | } |
35 | 42 | ||
36 | impl Query { | 43 | impl Query { |
37 | pub(crate) fn search( | 44 | pub(crate) fn search( |
38 | mut self, | 45 | mut self, |
39 | indices: &[&FileSymbols], | 46 | indices: &[&SymbolIndex], |
40 | token: &JobToken, | 47 | token: &JobToken, |
41 | ) -> Vec<(FileId, FileSymbol)> { | 48 | ) -> Vec<(FileId, FileSymbol)> { |
42 | 49 | ||