aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/display.rs10
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs286
-rw-r--r--crates/ra_ide_api/src/display/short_label.rs91
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs49
-rw-r--r--crates/ra_ide_api/src/hover.rs6
-rw-r--r--crates/ra_ide_api/src/lib.rs2
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 @@
4mod function_signature; 4mod function_signature;
5mod navigation_target; 5mod navigation_target;
6mod structure; 6mod structure;
7mod short_label;
7 8
8use crate::db::RootDatabase;
9use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; 9use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}};
10 10
11pub use navigation_target::NavigationTarget; 11pub use navigation_target::NavigationTarget;
12pub use structure::{StructureNode, file_structure}; 12pub use structure::{StructureNode, file_structure};
13pub use function_signature::FunctionSignature; 13pub use function_signature::FunctionSignature;
14 14
15pub(crate) use short_label::ShortLabel;
16
15pub(crate) fn function_label(node: &ast::FnDef) -> String { 17pub(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`.
76pub(crate) fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { 78pub(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 @@
1use ra_db::{FileId, SourceDatabase}; 1use ra_db::{FileId, SourceDatabase};
2use ra_syntax::{ 2use 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};
8use hir::{ModuleSource, FieldSource, ImplItem}; 8use hir::{ModuleSource, FieldSource, ImplItem};
9 9
10use crate::{FileSymbol, db::RootDatabase}; 10use crate::{FileSymbol, db::RootDatabase};
11use 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
27impl NavigationTarget { 30impl 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>> { 416fn 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 ")) 442fn 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 @@
1use ra_syntax::{
2 ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner, AstNode},
3};
4
5pub(crate) trait ShortLabel {
6 fn short_label(&self) -> Option<String>;
7}
8
9impl ShortLabel for ast::FnDef {
10 fn short_label(&self) -> Option<String> {
11 Some(crate::display::function_label(self))
12 }
13}
14
15impl ShortLabel for ast::StructDef {
16 fn short_label(&self) -> Option<String> {
17 short_label_from_node(self, "struct ")
18 }
19}
20
21impl ShortLabel for ast::EnumDef {
22 fn short_label(&self) -> Option<String> {
23 short_label_from_node(self, "enum ")
24 }
25}
26
27impl ShortLabel for ast::TraitDef {
28 fn short_label(&self) -> Option<String> {
29 short_label_from_node(self, "trait ")
30 }
31}
32
33impl ShortLabel for ast::Module {
34 fn short_label(&self) -> Option<String> {
35 short_label_from_node(self, "mod ")
36 }
37}
38
39impl ShortLabel for ast::TypeAliasDef {
40 fn short_label(&self) -> Option<String> {
41 short_label_from_node(self, "type ")
42 }
43}
44
45impl ShortLabel for ast::ConstDef {
46 fn short_label(&self) -> Option<String> {
47 short_label_from_ascribed_node(self, "const ")
48 }
49}
50
51impl ShortLabel for ast::StaticDef {
52 fn short_label(&self) -> Option<String> {
53 short_label_from_ascribed_node(self, "static ")
54 }
55}
56
57impl ShortLabel for ast::NamedFieldDef {
58 fn short_label(&self) -> Option<String> {
59 short_label_from_ascribed_node(self, "")
60 }
61}
62
63impl ShortLabel for ast::EnumVariant {
64 fn short_label(&self) -> Option<String> {
65 Some(self.name()?.text().to_string())
66 }
67}
68
69fn short_label_from_ascribed_node<T>(node: &T, prefix: &str) -> Option<String>
70where
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
83fn short_label_from_node<T>(node: &T, label: &str) -> Option<String>
84where
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 @@
1use ra_db::{FileId, SourceDatabase}; 1use ra_db::{FileId, SourceDatabase};
2use ra_syntax::{ 2use 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
18pub(crate) fn goto_definition( 19pub(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
115fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { 116fn 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 }