diff options
-rw-r--r-- | crates/ra_ide_api/src/display.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 286 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/short_label.rs | 91 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 49 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 2 |
6 files changed, 323 insertions, 121 deletions
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index 1b06abf94..f11af0a0b 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs | |||
@@ -4,14 +4,16 @@ | |||
4 | mod function_signature; | 4 | mod function_signature; |
5 | mod navigation_target; | 5 | mod navigation_target; |
6 | mod structure; | 6 | mod structure; |
7 | mod short_label; | ||
7 | 8 | ||
8 | use crate::db::RootDatabase; | ||
9 | use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; | 9 | use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; |
10 | 10 | ||
11 | pub use navigation_target::NavigationTarget; | 11 | pub use navigation_target::NavigationTarget; |
12 | pub use structure::{StructureNode, file_structure}; | 12 | pub use structure::{StructureNode, file_structure}; |
13 | pub use function_signature::FunctionSignature; | 13 | pub use function_signature::FunctionSignature; |
14 | 14 | ||
15 | pub(crate) use short_label::ShortLabel; | ||
16 | |||
15 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 17 | pub(crate) fn function_label(node: &ast::FnDef) -> String { |
16 | FunctionSignature::from(node).to_string() | 18 | FunctionSignature::from(node).to_string() |
17 | } | 19 | } |
@@ -73,10 +75,10 @@ where | |||
73 | 75 | ||
74 | // FIXME: this should not really use navigation target. Rather, approximately | 76 | // FIXME: this should not really use navigation target. Rather, approximately |
75 | // resolved symbol should return a `DefId`. | 77 | // resolved symbol should return a `DefId`. |
76 | pub(crate) fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { | 78 | pub(crate) fn doc_text_for(nav: NavigationTarget) -> Option<String> { |
77 | match (nav.description(db), nav.docs(db)) { | 79 | match (nav.description(), nav.docs()) { |
78 | (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), | 80 | (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), |
79 | (None, Some(docs)) => Some(docs), | 81 | (None, Some(docs)) => Some(docs.to_string()), |
80 | _ => None, | 82 | _ => None, |
81 | } | 83 | } |
82 | } | 84 | } |
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 45002d098..983ebe788 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs | |||
@@ -1,13 +1,14 @@ | |||
1 | use ra_db::{FileId, SourceDatabase}; | 1 | use ra_db::{FileId, SourceDatabase}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | SyntaxNode, AstNode, SmolStr, TextRange, TreeArc, AstPtr, | 3 | SyntaxNode, AstNode, SmolStr, TextRange, AstPtr, |
4 | SyntaxKind::{self, NAME}, | 4 | SyntaxKind::{self, NAME}, |
5 | ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, | 5 | ast::{self, DocCommentsOwner}, |
6 | algo::visit::{visitor, Visitor}, | 6 | algo::visit::{visitor, Visitor}, |
7 | }; | 7 | }; |
8 | use hir::{ModuleSource, FieldSource, ImplItem}; | 8 | use hir::{ModuleSource, FieldSource, ImplItem}; |
9 | 9 | ||
10 | use crate::{FileSymbol, db::RootDatabase}; | 10 | use crate::{FileSymbol, db::RootDatabase}; |
11 | use super::short_label::ShortLabel; | ||
11 | 12 | ||
12 | /// `NavigationTarget` represents and element in the editor's UI which you can | 13 | /// `NavigationTarget` represents and element in the editor's UI which you can |
13 | /// click on to navigate to a particular piece of code. | 14 | /// click on to navigate to a particular piece of code. |
@@ -22,6 +23,8 @@ pub struct NavigationTarget { | |||
22 | full_range: TextRange, | 23 | full_range: TextRange, |
23 | focus_range: Option<TextRange>, | 24 | focus_range: Option<TextRange>, |
24 | container_name: Option<SmolStr>, | 25 | container_name: Option<SmolStr>, |
26 | description: Option<String>, | ||
27 | docs: Option<String>, | ||
25 | } | 28 | } |
26 | 29 | ||
27 | impl NavigationTarget { | 30 | impl NavigationTarget { |
@@ -51,6 +54,14 @@ impl NavigationTarget { | |||
51 | self.full_range | 54 | self.full_range |
52 | } | 55 | } |
53 | 56 | ||
57 | pub fn docs(&self) -> Option<&str> { | ||
58 | self.docs.as_ref().map(String::as_str) | ||
59 | } | ||
60 | |||
61 | pub fn description(&self) -> Option<&str> { | ||
62 | self.description.as_ref().map(String::as_str) | ||
63 | } | ||
64 | |||
54 | /// A "most interesting" range withing the `full_range`. | 65 | /// A "most interesting" range withing the `full_range`. |
55 | /// | 66 | /// |
56 | /// Typically, `full_range` is the whole syntax node, | 67 | /// Typically, `full_range` is the whole syntax node, |
@@ -60,10 +71,10 @@ impl NavigationTarget { | |||
60 | } | 71 | } |
61 | 72 | ||
62 | pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { | 73 | pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { |
63 | NavigationTarget::from_named(file_id, pat) | 74 | NavigationTarget::from_named(file_id, pat, None, None) |
64 | } | 75 | } |
65 | 76 | ||
66 | pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget { | 77 | pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { |
67 | NavigationTarget { | 78 | NavigationTarget { |
68 | file_id: symbol.file_id, | 79 | file_id: symbol.file_id, |
69 | name: symbol.name.clone(), | 80 | name: symbol.name.clone(), |
@@ -71,6 +82,8 @@ impl NavigationTarget { | |||
71 | full_range: symbol.ptr.range(), | 82 | full_range: symbol.ptr.range(), |
72 | focus_range: symbol.name_range, | 83 | focus_range: symbol.name_range, |
73 | container_name: symbol.container_name.clone(), | 84 | container_name: symbol.container_name.clone(), |
85 | description: description_from_symbol(db, &symbol), | ||
86 | docs: docs_from_symbol(db, &symbol), | ||
74 | } | 87 | } |
75 | } | 88 | } |
76 | 89 | ||
@@ -84,6 +97,7 @@ impl NavigationTarget { | |||
84 | ast::PatKind::BindPat(pat) => return NavigationTarget::from_bind_pat(file_id, &pat), | 97 | ast::PatKind::BindPat(pat) => return NavigationTarget::from_bind_pat(file_id, &pat), |
85 | _ => ("_".into(), pat.syntax_node_ptr().range()), | 98 | _ => ("_".into(), pat.syntax_node_ptr().range()), |
86 | }; | 99 | }; |
100 | |||
87 | NavigationTarget { | 101 | NavigationTarget { |
88 | file_id, | 102 | file_id, |
89 | name, | 103 | name, |
@@ -91,6 +105,8 @@ impl NavigationTarget { | |||
91 | focus_range: None, | 105 | focus_range: None, |
92 | kind: NAME, | 106 | kind: NAME, |
93 | container_name: None, | 107 | container_name: None, |
108 | description: None, //< No documentation for Description | ||
109 | docs: None, //< No documentation for Pattern | ||
94 | } | 110 | } |
95 | } | 111 | } |
96 | 112 | ||
@@ -99,6 +115,7 @@ impl NavigationTarget { | |||
99 | par: AstPtr<ast::SelfParam>, | 115 | par: AstPtr<ast::SelfParam>, |
100 | ) -> NavigationTarget { | 116 | ) -> NavigationTarget { |
101 | let (name, full_range) = ("self".into(), par.syntax_node_ptr().range()); | 117 | let (name, full_range) = ("self".into(), par.syntax_node_ptr().range()); |
118 | |||
102 | NavigationTarget { | 119 | NavigationTarget { |
103 | file_id, | 120 | file_id, |
104 | name, | 121 | name, |
@@ -106,6 +123,8 @@ impl NavigationTarget { | |||
106 | focus_range: None, | 123 | focus_range: None, |
107 | kind: NAME, | 124 | kind: NAME, |
108 | container_name: None, | 125 | container_name: None, |
126 | description: None, //< No document node for SelfParam | ||
127 | docs: None, //< No document node for SelfParam | ||
109 | } | 128 | } |
110 | } | 129 | } |
111 | 130 | ||
@@ -115,11 +134,16 @@ impl NavigationTarget { | |||
115 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 134 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
116 | match source { | 135 | match source { |
117 | ModuleSource::SourceFile(node) => { | 136 | ModuleSource::SourceFile(node) => { |
118 | NavigationTarget::from_syntax(file_id, name, None, node.syntax()) | 137 | NavigationTarget::from_syntax(file_id, name, None, node.syntax(), None, None) |
119 | } | ||
120 | ModuleSource::Module(node) => { | ||
121 | NavigationTarget::from_syntax(file_id, name, None, node.syntax()) | ||
122 | } | 138 | } |
139 | ModuleSource::Module(node) => NavigationTarget::from_syntax( | ||
140 | file_id, | ||
141 | name, | ||
142 | None, | ||
143 | node.syntax(), | ||
144 | node.doc_comment_text(), | ||
145 | node.short_label(), | ||
146 | ), | ||
123 | } | 147 | } |
124 | } | 148 | } |
125 | 149 | ||
@@ -127,23 +151,37 @@ impl NavigationTarget { | |||
127 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 151 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
128 | if let Some((file_id, source)) = module.declaration_source(db) { | 152 | if let Some((file_id, source)) = module.declaration_source(db) { |
129 | let file_id = file_id.as_original_file(); | 153 | let file_id = file_id.as_original_file(); |
130 | return NavigationTarget::from_syntax(file_id, name, None, source.syntax()); | 154 | return NavigationTarget::from_syntax( |
155 | file_id, | ||
156 | name, | ||
157 | None, | ||
158 | source.syntax(), | ||
159 | source.doc_comment_text(), | ||
160 | source.short_label(), | ||
161 | ); | ||
131 | } | 162 | } |
132 | NavigationTarget::from_module(db, module) | 163 | NavigationTarget::from_module(db, module) |
133 | } | 164 | } |
134 | 165 | ||
135 | pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget { | 166 | pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget { |
136 | let (file_id, fn_def) = func.source(db); | 167 | let (file_id, fn_def) = func.source(db); |
137 | NavigationTarget::from_named(file_id.original_file(db), &*fn_def) | 168 | NavigationTarget::from_named( |
169 | file_id.original_file(db), | ||
170 | &*fn_def, | ||
171 | fn_def.doc_comment_text(), | ||
172 | fn_def.short_label(), | ||
173 | ) | ||
138 | } | 174 | } |
139 | 175 | ||
140 | pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { | 176 | pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { |
141 | let (file_id, field) = field.source(db); | 177 | let (file_id, field) = field.source(db); |
142 | let file_id = file_id.original_file(db); | 178 | let file_id = file_id.original_file(db); |
143 | match field { | 179 | match field { |
144 | FieldSource::Named(it) => NavigationTarget::from_named(file_id, &*it), | 180 | FieldSource::Named(it) => { |
181 | NavigationTarget::from_named(file_id, &*it, it.doc_comment_text(), it.short_label()) | ||
182 | } | ||
145 | FieldSource::Pos(it) => { | 183 | FieldSource::Pos(it) => { |
146 | NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax()) | 184 | NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax(), None, None) |
147 | } | 185 | } |
148 | } | 186 | } |
149 | } | 187 | } |
@@ -152,15 +190,30 @@ impl NavigationTarget { | |||
152 | match adt_def { | 190 | match adt_def { |
153 | hir::AdtDef::Struct(s) => { | 191 | hir::AdtDef::Struct(s) => { |
154 | let (file_id, node) = s.source(db); | 192 | let (file_id, node) = s.source(db); |
155 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 193 | NavigationTarget::from_named( |
194 | file_id.original_file(db), | ||
195 | &*node, | ||
196 | node.doc_comment_text(), | ||
197 | node.short_label(), | ||
198 | ) | ||
156 | } | 199 | } |
157 | hir::AdtDef::Union(s) => { | 200 | hir::AdtDef::Union(s) => { |
158 | let (file_id, node) = s.source(db); | 201 | let (file_id, node) = s.source(db); |
159 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 202 | NavigationTarget::from_named( |
203 | file_id.original_file(db), | ||
204 | &*node, | ||
205 | node.doc_comment_text(), | ||
206 | node.short_label(), | ||
207 | ) | ||
160 | } | 208 | } |
161 | hir::AdtDef::Enum(s) => { | 209 | hir::AdtDef::Enum(s) => { |
162 | let (file_id, node) = s.source(db); | 210 | let (file_id, node) = s.source(db); |
163 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 211 | NavigationTarget::from_named( |
212 | file_id.original_file(db), | ||
213 | &*node, | ||
214 | node.doc_comment_text(), | ||
215 | node.short_label(), | ||
216 | ) | ||
164 | } | 217 | } |
165 | } | 218 | } |
166 | } | 219 | } |
@@ -174,35 +227,75 @@ impl NavigationTarget { | |||
174 | hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func), | 227 | hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func), |
175 | hir::ModuleDef::Struct(s) => { | 228 | hir::ModuleDef::Struct(s) => { |
176 | let (file_id, node) = s.source(db); | 229 | let (file_id, node) = s.source(db); |
177 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 230 | NavigationTarget::from_named( |
231 | file_id.original_file(db), | ||
232 | &*node, | ||
233 | node.doc_comment_text(), | ||
234 | node.short_label(), | ||
235 | ) | ||
178 | } | 236 | } |
179 | hir::ModuleDef::Union(s) => { | 237 | hir::ModuleDef::Union(s) => { |
180 | let (file_id, node) = s.source(db); | 238 | let (file_id, node) = s.source(db); |
181 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 239 | NavigationTarget::from_named( |
240 | file_id.original_file(db), | ||
241 | &*node, | ||
242 | node.doc_comment_text(), | ||
243 | node.short_label(), | ||
244 | ) | ||
182 | } | 245 | } |
183 | hir::ModuleDef::Const(s) => { | 246 | hir::ModuleDef::Const(s) => { |
184 | let (file_id, node) = s.source(db); | 247 | let (file_id, node) = s.source(db); |
185 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 248 | NavigationTarget::from_named( |
249 | file_id.original_file(db), | ||
250 | &*node, | ||
251 | node.doc_comment_text(), | ||
252 | node.short_label(), | ||
253 | ) | ||
186 | } | 254 | } |
187 | hir::ModuleDef::Static(s) => { | 255 | hir::ModuleDef::Static(s) => { |
188 | let (file_id, node) = s.source(db); | 256 | let (file_id, node) = s.source(db); |
189 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 257 | NavigationTarget::from_named( |
258 | file_id.original_file(db), | ||
259 | &*node, | ||
260 | node.doc_comment_text(), | ||
261 | node.short_label(), | ||
262 | ) | ||
190 | } | 263 | } |
191 | hir::ModuleDef::Enum(e) => { | 264 | hir::ModuleDef::Enum(e) => { |
192 | let (file_id, node) = e.source(db); | 265 | let (file_id, node) = e.source(db); |
193 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 266 | NavigationTarget::from_named( |
267 | file_id.original_file(db), | ||
268 | &*node, | ||
269 | node.doc_comment_text(), | ||
270 | node.short_label(), | ||
271 | ) | ||
194 | } | 272 | } |
195 | hir::ModuleDef::EnumVariant(var) => { | 273 | hir::ModuleDef::EnumVariant(var) => { |
196 | let (file_id, node) = var.source(db); | 274 | let (file_id, node) = var.source(db); |
197 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 275 | NavigationTarget::from_named( |
276 | file_id.original_file(db), | ||
277 | &*node, | ||
278 | node.doc_comment_text(), | ||
279 | node.short_label(), | ||
280 | ) | ||
198 | } | 281 | } |
199 | hir::ModuleDef::Trait(e) => { | 282 | hir::ModuleDef::Trait(e) => { |
200 | let (file_id, node) = e.source(db); | 283 | let (file_id, node) = e.source(db); |
201 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 284 | NavigationTarget::from_named( |
285 | file_id.original_file(db), | ||
286 | &*node, | ||
287 | node.doc_comment_text(), | ||
288 | node.short_label(), | ||
289 | ) | ||
202 | } | 290 | } |
203 | hir::ModuleDef::TypeAlias(e) => { | 291 | hir::ModuleDef::TypeAlias(e) => { |
204 | let (file_id, node) = e.source(db); | 292 | let (file_id, node) = e.source(db); |
205 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 293 | NavigationTarget::from_named( |
294 | file_id.original_file(db), | ||
295 | &*node, | ||
296 | node.doc_comment_text(), | ||
297 | node.short_label(), | ||
298 | ) | ||
206 | } | 299 | } |
207 | hir::ModuleDef::BuiltinType(..) => { | 300 | hir::ModuleDef::BuiltinType(..) => { |
208 | return None; | 301 | return None; |
@@ -221,6 +314,8 @@ impl NavigationTarget { | |||
221 | "impl".into(), | 314 | "impl".into(), |
222 | None, | 315 | None, |
223 | node.syntax(), | 316 | node.syntax(), |
317 | None, | ||
318 | None, | ||
224 | ) | 319 | ) |
225 | } | 320 | } |
226 | 321 | ||
@@ -229,11 +324,21 @@ impl NavigationTarget { | |||
229 | ImplItem::Method(f) => NavigationTarget::from_function(db, f), | 324 | ImplItem::Method(f) => NavigationTarget::from_function(db, f), |
230 | ImplItem::Const(c) => { | 325 | ImplItem::Const(c) => { |
231 | let (file_id, node) = c.source(db); | 326 | let (file_id, node) = c.source(db); |
232 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 327 | NavigationTarget::from_named( |
328 | file_id.original_file(db), | ||
329 | &*node, | ||
330 | node.doc_comment_text(), | ||
331 | node.short_label(), | ||
332 | ) | ||
233 | } | 333 | } |
234 | ImplItem::TypeAlias(a) => { | 334 | ImplItem::TypeAlias(a) => { |
235 | let (file_id, node) = a.source(db); | 335 | let (file_id, node) = a.source(db); |
236 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 336 | NavigationTarget::from_named( |
337 | file_id.original_file(db), | ||
338 | &*node, | ||
339 | node.doc_comment_text(), | ||
340 | node.short_label(), | ||
341 | ) | ||
237 | } | 342 | } |
238 | } | 343 | } |
239 | } | 344 | } |
@@ -241,7 +346,12 @@ impl NavigationTarget { | |||
241 | pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { | 346 | pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { |
242 | let (file_id, node) = macro_call.source(db); | 347 | let (file_id, node) = macro_call.source(db); |
243 | log::debug!("nav target {}", node.syntax().debug_dump()); | 348 | log::debug!("nav target {}", node.syntax().debug_dump()); |
244 | NavigationTarget::from_named(file_id.original_file(db), &*node) | 349 | NavigationTarget::from_named( |
350 | file_id.original_file(db), | ||
351 | &*node, | ||
352 | node.doc_comment_text(), | ||
353 | None, | ||
354 | ) | ||
245 | } | 355 | } |
246 | 356 | ||
247 | #[cfg(test)] | 357 | #[cfg(test)] |
@@ -269,11 +379,16 @@ impl NavigationTarget { | |||
269 | } | 379 | } |
270 | 380 | ||
271 | /// Allows `NavigationTarget` to be created from a `NameOwner` | 381 | /// Allows `NavigationTarget` to be created from a `NameOwner` |
272 | pub(crate) fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget { | 382 | pub(crate) fn from_named( |
383 | file_id: FileId, | ||
384 | node: &impl ast::NameOwner, | ||
385 | docs: Option<String>, | ||
386 | description: Option<String>, | ||
387 | ) -> NavigationTarget { | ||
273 | //FIXME: use `_` instead of empty string | 388 | //FIXME: use `_` instead of empty string |
274 | let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); | 389 | let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); |
275 | let focus_range = node.name().map(|it| it.syntax().range()); | 390 | let focus_range = node.name().map(|it| it.syntax().range()); |
276 | NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax()) | 391 | NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax(), docs, description) |
277 | } | 392 | } |
278 | 393 | ||
279 | fn from_syntax( | 394 | fn from_syntax( |
@@ -281,6 +396,8 @@ impl NavigationTarget { | |||
281 | name: SmolStr, | 396 | name: SmolStr, |
282 | focus_range: Option<TextRange>, | 397 | focus_range: Option<TextRange>, |
283 | node: &SyntaxNode, | 398 | node: &SyntaxNode, |
399 | docs: Option<String>, | ||
400 | description: Option<String>, | ||
284 | ) -> NavigationTarget { | 401 | ) -> NavigationTarget { |
285 | NavigationTarget { | 402 | NavigationTarget { |
286 | file_id, | 403 | file_id, |
@@ -290,83 +407,52 @@ impl NavigationTarget { | |||
290 | focus_range, | 407 | focus_range, |
291 | // ptr: Some(LocalSyntaxPtr::new(node)), | 408 | // ptr: Some(LocalSyntaxPtr::new(node)), |
292 | container_name: None, | 409 | container_name: None, |
410 | description, | ||
411 | docs, | ||
293 | } | 412 | } |
294 | } | 413 | } |
414 | } | ||
295 | 415 | ||
296 | pub(crate) fn node(&self, db: &RootDatabase) -> Option<TreeArc<SyntaxNode>> { | 416 | fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { |
297 | let source_file = db.parse(self.file_id()).tree; | 417 | let file = db.parse(symbol.file_id).tree; |
298 | let source_file = source_file.syntax(); | 418 | let node = symbol.ptr.to_node(file.syntax()).to_owned(); |
299 | let node = source_file | ||
300 | .descendants() | ||
301 | .find(|node| node.kind() == self.kind() && node.range() == self.full_range())? | ||
302 | .to_owned(); | ||
303 | Some(node) | ||
304 | } | ||
305 | 419 | ||
306 | pub(crate) fn docs(&self, db: &RootDatabase) -> Option<String> { | 420 | fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> { |
307 | let node = self.node(db)?; | 421 | node.doc_comment_text() |
308 | fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> { | ||
309 | node.doc_comment_text() | ||
310 | } | ||
311 | |||
312 | visitor() | ||
313 | .visit(doc_comments::<ast::FnDef>) | ||
314 | .visit(doc_comments::<ast::StructDef>) | ||
315 | .visit(doc_comments::<ast::EnumDef>) | ||
316 | .visit(doc_comments::<ast::TraitDef>) | ||
317 | .visit(doc_comments::<ast::Module>) | ||
318 | .visit(doc_comments::<ast::TypeAliasDef>) | ||
319 | .visit(doc_comments::<ast::ConstDef>) | ||
320 | .visit(doc_comments::<ast::StaticDef>) | ||
321 | .visit(doc_comments::<ast::NamedFieldDef>) | ||
322 | .visit(doc_comments::<ast::EnumVariant>) | ||
323 | .visit(doc_comments::<ast::MacroCall>) | ||
324 | .accept(&node)? | ||
325 | } | 422 | } |
326 | 423 | ||
327 | /// Get a description of this node. | 424 | visitor() |
328 | /// | 425 | .visit(doc_comments::<ast::FnDef>) |
329 | /// e.g. `struct Name`, `enum Name`, `fn Name` | 426 | .visit(doc_comments::<ast::StructDef>) |
330 | pub(crate) fn description(&self, db: &RootDatabase) -> Option<String> { | 427 | .visit(doc_comments::<ast::EnumDef>) |
331 | // FIXME: After type inference is done, add type information to improve the output | 428 | .visit(doc_comments::<ast::TraitDef>) |
332 | let node = self.node(db)?; | 429 | .visit(doc_comments::<ast::Module>) |
333 | 430 | .visit(doc_comments::<ast::TypeAliasDef>) | |
334 | fn visit_ascribed_node<T>(node: &T, prefix: &str) -> Option<String> | 431 | .visit(doc_comments::<ast::ConstDef>) |
335 | where | 432 | .visit(doc_comments::<ast::StaticDef>) |
336 | T: NameOwner + VisibilityOwner + TypeAscriptionOwner, | 433 | .visit(doc_comments::<ast::NamedFieldDef>) |
337 | { | 434 | .visit(doc_comments::<ast::EnumVariant>) |
338 | let mut string = visit_node(node, prefix)?; | 435 | .visit(doc_comments::<ast::MacroCall>) |
339 | 436 | .accept(&node)? | |
340 | if let Some(type_ref) = node.ascribed_type() { | 437 | } |
341 | string.push_str(": "); | ||
342 | type_ref.syntax().text().push_to(&mut string); | ||
343 | } | ||
344 | |||
345 | Some(string) | ||
346 | } | ||
347 | |||
348 | fn visit_node<T>(node: &T, label: &str) -> Option<String> | ||
349 | where | ||
350 | T: NameOwner + VisibilityOwner, | ||
351 | { | ||
352 | let mut string = | ||
353 | node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default(); | ||
354 | string.push_str(label); | ||
355 | string.push_str(node.name()?.text().as_str()); | ||
356 | Some(string) | ||
357 | } | ||
358 | 438 | ||
359 | visitor() | 439 | /// Get a description of a symbol. |
360 | .visit(|node: &ast::FnDef| Some(crate::display::function_label(node))) | 440 | /// |
361 | .visit(|node: &ast::StructDef| visit_node(node, "struct ")) | 441 | /// e.g. `struct Name`, `enum Name`, `fn Name` |
362 | .visit(|node: &ast::EnumDef| visit_node(node, "enum ")) | 442 | fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { |
363 | .visit(|node: &ast::TraitDef| visit_node(node, "trait ")) | 443 | let file = db.parse(symbol.file_id).tree; |
364 | .visit(|node: &ast::Module| visit_node(node, "mod ")) | 444 | let node = symbol.ptr.to_node(file.syntax()).to_owned(); |
365 | .visit(|node: &ast::TypeAliasDef| visit_node(node, "type ")) | 445 | |
366 | .visit(|node: &ast::ConstDef| visit_ascribed_node(node, "const ")) | 446 | visitor() |
367 | .visit(|node: &ast::StaticDef| visit_ascribed_node(node, "static ")) | 447 | .visit(|node: &ast::FnDef| node.short_label()) |
368 | .visit(|node: &ast::NamedFieldDef| visit_ascribed_node(node, "")) | 448 | .visit(|node: &ast::StructDef| node.short_label()) |
369 | .visit(|node: &ast::EnumVariant| Some(node.name()?.text().to_string())) | 449 | .visit(|node: &ast::EnumDef| node.short_label()) |
370 | .accept(&node)? | 450 | .visit(|node: &ast::TraitDef| node.short_label()) |
371 | } | 451 | .visit(|node: &ast::Module| node.short_label()) |
452 | .visit(|node: &ast::TypeAliasDef| node.short_label()) | ||
453 | .visit(|node: &ast::ConstDef| node.short_label()) | ||
454 | .visit(|node: &ast::StaticDef| node.short_label()) | ||
455 | .visit(|node: &ast::NamedFieldDef| node.short_label()) | ||
456 | .visit(|node: &ast::EnumVariant| node.short_label()) | ||
457 | .accept(&node)? | ||
372 | } | 458 | } |
diff --git a/crates/ra_ide_api/src/display/short_label.rs b/crates/ra_ide_api/src/display/short_label.rs new file mode 100644 index 000000000..dc8245c34 --- /dev/null +++ b/crates/ra_ide_api/src/display/short_label.rs | |||
@@ -0,0 +1,91 @@ | |||
1 | use ra_syntax::{ | ||
2 | ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner, AstNode}, | ||
3 | }; | ||
4 | |||
5 | pub(crate) trait ShortLabel { | ||
6 | fn short_label(&self) -> Option<String>; | ||
7 | } | ||
8 | |||
9 | impl ShortLabel for ast::FnDef { | ||
10 | fn short_label(&self) -> Option<String> { | ||
11 | Some(crate::display::function_label(self)) | ||
12 | } | ||
13 | } | ||
14 | |||
15 | impl ShortLabel for ast::StructDef { | ||
16 | fn short_label(&self) -> Option<String> { | ||
17 | short_label_from_node(self, "struct ") | ||
18 | } | ||
19 | } | ||
20 | |||
21 | impl ShortLabel for ast::EnumDef { | ||
22 | fn short_label(&self) -> Option<String> { | ||
23 | short_label_from_node(self, "enum ") | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl ShortLabel for ast::TraitDef { | ||
28 | fn short_label(&self) -> Option<String> { | ||
29 | short_label_from_node(self, "trait ") | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl ShortLabel for ast::Module { | ||
34 | fn short_label(&self) -> Option<String> { | ||
35 | short_label_from_node(self, "mod ") | ||
36 | } | ||
37 | } | ||
38 | |||
39 | impl ShortLabel for ast::TypeAliasDef { | ||
40 | fn short_label(&self) -> Option<String> { | ||
41 | short_label_from_node(self, "type ") | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl ShortLabel for ast::ConstDef { | ||
46 | fn short_label(&self) -> Option<String> { | ||
47 | short_label_from_ascribed_node(self, "const ") | ||
48 | } | ||
49 | } | ||
50 | |||
51 | impl ShortLabel for ast::StaticDef { | ||
52 | fn short_label(&self) -> Option<String> { | ||
53 | short_label_from_ascribed_node(self, "static ") | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl ShortLabel for ast::NamedFieldDef { | ||
58 | fn short_label(&self) -> Option<String> { | ||
59 | short_label_from_ascribed_node(self, "") | ||
60 | } | ||
61 | } | ||
62 | |||
63 | impl ShortLabel for ast::EnumVariant { | ||
64 | fn short_label(&self) -> Option<String> { | ||
65 | Some(self.name()?.text().to_string()) | ||
66 | } | ||
67 | } | ||
68 | |||
69 | fn short_label_from_ascribed_node<T>(node: &T, prefix: &str) -> Option<String> | ||
70 | where | ||
71 | T: NameOwner + VisibilityOwner + TypeAscriptionOwner, | ||
72 | { | ||
73 | let mut buf = short_label_from_node(node, prefix)?; | ||
74 | |||
75 | if let Some(type_ref) = node.ascribed_type() { | ||
76 | buf.push_str(": "); | ||
77 | type_ref.syntax().text().push_to(&mut buf); | ||
78 | } | ||
79 | |||
80 | Some(buf) | ||
81 | } | ||
82 | |||
83 | fn short_label_from_node<T>(node: &T, label: &str) -> Option<String> | ||
84 | where | ||
85 | T: NameOwner + VisibilityOwner, | ||
86 | { | ||
87 | let mut buf = node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default(); | ||
88 | buf.push_str(label); | ||
89 | buf.push_str(node.name()?.text().as_str()); | ||
90 | Some(buf) | ||
91 | } | ||
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index e72b7a6e7..325a5a4f3 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_db::{FileId, SourceDatabase}; | 1 | use ra_db::{FileId, SourceDatabase}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | AstNode, ast, | 3 | AstNode, ast::{self, DocCommentsOwner}, |
4 | algo::{ | 4 | algo::{ |
5 | find_node_at_offset, | 5 | find_node_at_offset, |
6 | visit::{visitor, Visitor}, | 6 | visit::{visitor, Visitor}, |
@@ -13,6 +13,7 @@ use crate::{ | |||
13 | db::RootDatabase, | 13 | db::RootDatabase, |
14 | RangeInfo, | 14 | RangeInfo, |
15 | name_ref_kind::{NameRefKind::*, classify_name_ref}, | 15 | name_ref_kind::{NameRefKind::*, classify_name_ref}, |
16 | display::ShortLabel, | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | pub(crate) fn goto_definition( | 19 | pub(crate) fn goto_definition( |
@@ -82,7 +83,7 @@ pub(crate) fn reference_definition( | |||
82 | // Fallback index based approach: | 83 | // Fallback index based approach: |
83 | let navs = crate::symbol_index::index_resolve(db, name_ref) | 84 | let navs = crate::symbol_index::index_resolve(db, name_ref) |
84 | .into_iter() | 85 | .into_iter() |
85 | .map(NavigationTarget::from_symbol) | 86 | .map(|s| NavigationTarget::from_symbol(db, s)) |
86 | .collect(); | 87 | .collect(); |
87 | Approximate(navs) | 88 | Approximate(navs) |
88 | } | 89 | } |
@@ -114,17 +115,39 @@ pub(crate) fn name_definition( | |||
114 | 115 | ||
115 | fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { | 116 | fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { |
116 | visitor() | 117 | visitor() |
117 | .visit(|node: &ast::StructDef| NavigationTarget::from_named(file_id, node)) | 118 | .visit(|node: &ast::StructDef| { |
118 | .visit(|node: &ast::EnumDef| NavigationTarget::from_named(file_id, node)) | 119 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) |
119 | .visit(|node: &ast::EnumVariant| NavigationTarget::from_named(file_id, node)) | 120 | }) |
120 | .visit(|node: &ast::FnDef| NavigationTarget::from_named(file_id, node)) | 121 | .visit(|node: &ast::EnumDef| { |
121 | .visit(|node: &ast::TypeAliasDef| NavigationTarget::from_named(file_id, node)) | 122 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) |
122 | .visit(|node: &ast::ConstDef| NavigationTarget::from_named(file_id, node)) | 123 | }) |
123 | .visit(|node: &ast::StaticDef| NavigationTarget::from_named(file_id, node)) | 124 | .visit(|node: &ast::EnumVariant| { |
124 | .visit(|node: &ast::TraitDef| NavigationTarget::from_named(file_id, node)) | 125 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) |
125 | .visit(|node: &ast::NamedFieldDef| NavigationTarget::from_named(file_id, node)) | 126 | }) |
126 | .visit(|node: &ast::Module| NavigationTarget::from_named(file_id, node)) | 127 | .visit(|node: &ast::FnDef| { |
127 | .visit(|node: &ast::MacroCall| NavigationTarget::from_named(file_id, node)) | 128 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) |
129 | }) | ||
130 | .visit(|node: &ast::TypeAliasDef| { | ||
131 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) | ||
132 | }) | ||
133 | .visit(|node: &ast::ConstDef| { | ||
134 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) | ||
135 | }) | ||
136 | .visit(|node: &ast::StaticDef| { | ||
137 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) | ||
138 | }) | ||
139 | .visit(|node: &ast::TraitDef| { | ||
140 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) | ||
141 | }) | ||
142 | .visit(|node: &ast::NamedFieldDef| { | ||
143 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) | ||
144 | }) | ||
145 | .visit(|node: &ast::Module| { | ||
146 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), node.short_label()) | ||
147 | }) | ||
148 | .visit(|node: &ast::MacroCall| { | ||
149 | NavigationTarget::from_named(file_id, node, node.doc_comment_text(), None) | ||
150 | }) | ||
128 | .accept(node) | 151 | .accept(node) |
129 | } | 152 | } |
130 | 153 | ||
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index f56965ef5..cb676eb12 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -86,13 +86,13 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
86 | use crate::goto_definition::{ReferenceResult::*, reference_definition}; | 86 | use crate::goto_definition::{ReferenceResult::*, reference_definition}; |
87 | let ref_result = reference_definition(db, position.file_id, name_ref); | 87 | let ref_result = reference_definition(db, position.file_id, name_ref); |
88 | match ref_result { | 88 | match ref_result { |
89 | Exact(nav) => res.extend(doc_text_for(db, nav)), | 89 | Exact(nav) => res.extend(doc_text_for(nav)), |
90 | Approximate(navs) => { | 90 | Approximate(navs) => { |
91 | // We are no longer exact | 91 | // We are no longer exact |
92 | res.exact = false; | 92 | res.exact = false; |
93 | 93 | ||
94 | for nav in navs { | 94 | for nav in navs { |
95 | res.extend(doc_text_for(db, nav)) | 95 | res.extend(doc_text_for(nav)) |
96 | } | 96 | } |
97 | } | 97 | } |
98 | } | 98 | } |
@@ -104,7 +104,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
104 | 104 | ||
105 | if let Some(navs) = navs { | 105 | if let Some(navs) = navs { |
106 | for nav in navs { | 106 | for nav in navs { |
107 | res.extend(doc_text_for(db, nav)) | 107 | res.extend(doc_text_for(nav)) |
108 | } | 108 | } |
109 | } | 109 | } |
110 | 110 | ||
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 2fe46cd13..dbebf50a6 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -393,7 +393,7 @@ impl Analysis { | |||
393 | self.with_db(|db| { | 393 | self.with_db(|db| { |
394 | symbol_index::world_symbols(db, query) | 394 | symbol_index::world_symbols(db, query) |
395 | .into_iter() | 395 | .into_iter() |
396 | .map(NavigationTarget::from_symbol) | 396 | .map(|s| NavigationTarget::from_symbol(db, s)) |
397 | .collect::<Vec<_>>() | 397 | .collect::<Vec<_>>() |
398 | }) | 398 | }) |
399 | } | 399 | } |