diff options
Diffstat (limited to 'crates/ra_analysis/src/symbol_index.rs')
-rw-r--r-- | crates/ra_analysis/src/symbol_index.rs | 123 |
1 files changed, 119 insertions, 4 deletions
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index e5bdf0aa1..edb2268fb 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -4,10 +4,11 @@ use std::{ | |||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
7 | use ra_editor::{self, FileSymbol}; | ||
8 | use ra_syntax::{ | 7 | use ra_syntax::{ |
9 | SourceFileNode, | 8 | AstNode, SyntaxNodeRef, SourceFileNode, SmolStr, TextRange, |
9 | algo::visit::{visitor, Visitor}, | ||
10 | SyntaxKind::{self, *}, | 10 | SyntaxKind::{self, *}, |
11 | ast::{self, NameOwner, DocCommentsOwner}, | ||
11 | }; | 12 | }; |
12 | use ra_db::{SyntaxDatabase, SourceRootId}; | 13 | use ra_db::{SyntaxDatabase, SourceRootId}; |
13 | use rayon::prelude::*; | 14 | use rayon::prelude::*; |
@@ -65,8 +66,9 @@ impl SymbolIndex { | |||
65 | ) -> SymbolIndex { | 66 | ) -> SymbolIndex { |
66 | let mut symbols = files | 67 | let mut symbols = files |
67 | .flat_map(|(file_id, file)| { | 68 | .flat_map(|(file_id, file)| { |
68 | ra_editor::file_symbols(&file) | 69 | file.syntax() |
69 | .into_iter() | 70 | .descendants() |
71 | .filter_map(to_symbol) | ||
70 | .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) | 72 | .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) |
71 | .collect::<Vec<_>>() | 73 | .collect::<Vec<_>>() |
72 | }) | 74 | }) |
@@ -121,3 +123,116 @@ fn is_type(kind: SyntaxKind) -> bool { | |||
121 | _ => false, | 123 | _ => false, |
122 | } | 124 | } |
123 | } | 125 | } |
126 | |||
127 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
128 | pub struct FileSymbol { | ||
129 | pub name: SmolStr, | ||
130 | pub node_range: TextRange, | ||
131 | pub kind: SyntaxKind, | ||
132 | } | ||
133 | |||
134 | impl FileSymbol { | ||
135 | pub fn docs(&self, file: &SourceFileNode) -> Option<String> { | ||
136 | file.syntax() | ||
137 | .descendants() | ||
138 | .filter(|node| node.kind() == self.kind && node.range() == self.node_range) | ||
139 | .filter_map(|node: SyntaxNodeRef| { | ||
140 | fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option<String> { | ||
141 | let comments = node.doc_comment_text(); | ||
142 | if comments.is_empty() { | ||
143 | None | ||
144 | } else { | ||
145 | Some(comments) | ||
146 | } | ||
147 | } | ||
148 | |||
149 | visitor() | ||
150 | .visit(doc_comments::<ast::FnDef>) | ||
151 | .visit(doc_comments::<ast::StructDef>) | ||
152 | .visit(doc_comments::<ast::EnumDef>) | ||
153 | .visit(doc_comments::<ast::TraitDef>) | ||
154 | .visit(doc_comments::<ast::Module>) | ||
155 | .visit(doc_comments::<ast::TypeDef>) | ||
156 | .visit(doc_comments::<ast::ConstDef>) | ||
157 | .visit(doc_comments::<ast::StaticDef>) | ||
158 | .accept(node)? | ||
159 | }) | ||
160 | .nth(0) | ||
161 | } | ||
162 | /// Get a description of this node. | ||
163 | /// | ||
164 | /// e.g. `struct Name`, `enum Name`, `fn Name` | ||
165 | pub fn description(&self, file: &SourceFileNode) -> Option<String> { | ||
166 | // TODO: After type inference is done, add type information to improve the output | ||
167 | file.syntax() | ||
168 | .descendants() | ||
169 | .filter(|node| node.kind() == self.kind && node.range() == self.node_range) | ||
170 | .filter_map(|node: SyntaxNodeRef| { | ||
171 | // TODO: Refactor to be have less repetition | ||
172 | visitor() | ||
173 | .visit(|node: ast::FnDef| { | ||
174 | let mut string = "fn ".to_string(); | ||
175 | node.name()?.syntax().text().push_to(&mut string); | ||
176 | Some(string) | ||
177 | }) | ||
178 | .visit(|node: ast::StructDef| { | ||
179 | let mut string = "struct ".to_string(); | ||
180 | node.name()?.syntax().text().push_to(&mut string); | ||
181 | Some(string) | ||
182 | }) | ||
183 | .visit(|node: ast::EnumDef| { | ||
184 | let mut string = "enum ".to_string(); | ||
185 | node.name()?.syntax().text().push_to(&mut string); | ||
186 | Some(string) | ||
187 | }) | ||
188 | .visit(|node: ast::TraitDef| { | ||
189 | let mut string = "trait ".to_string(); | ||
190 | node.name()?.syntax().text().push_to(&mut string); | ||
191 | Some(string) | ||
192 | }) | ||
193 | .visit(|node: ast::Module| { | ||
194 | let mut string = "mod ".to_string(); | ||
195 | node.name()?.syntax().text().push_to(&mut string); | ||
196 | Some(string) | ||
197 | }) | ||
198 | .visit(|node: ast::TypeDef| { | ||
199 | let mut string = "type ".to_string(); | ||
200 | node.name()?.syntax().text().push_to(&mut string); | ||
201 | Some(string) | ||
202 | }) | ||
203 | .visit(|node: ast::ConstDef| { | ||
204 | let mut string = "const ".to_string(); | ||
205 | node.name()?.syntax().text().push_to(&mut string); | ||
206 | Some(string) | ||
207 | }) | ||
208 | .visit(|node: ast::StaticDef| { | ||
209 | let mut string = "static ".to_string(); | ||
210 | node.name()?.syntax().text().push_to(&mut string); | ||
211 | Some(string) | ||
212 | }) | ||
213 | .accept(node)? | ||
214 | }) | ||
215 | .nth(0) | ||
216 | } | ||
217 | } | ||
218 | |||
219 | fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { | ||
220 | fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> { | ||
221 | let name = node.name()?; | ||
222 | Some(FileSymbol { | ||
223 | name: name.text(), | ||
224 | node_range: node.syntax().range(), | ||
225 | kind: node.syntax().kind(), | ||
226 | }) | ||
227 | } | ||
228 | visitor() | ||
229 | .visit(decl::<ast::FnDef>) | ||
230 | .visit(decl::<ast::StructDef>) | ||
231 | .visit(decl::<ast::EnumDef>) | ||
232 | .visit(decl::<ast::TraitDef>) | ||
233 | .visit(decl::<ast::Module>) | ||
234 | .visit(decl::<ast::TypeDef>) | ||
235 | .visit(decl::<ast::ConstDef>) | ||
236 | .visit(decl::<ast::StaticDef>) | ||
237 | .accept(node)? | ||
238 | } | ||