diff options
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 114 |
1 files changed, 83 insertions, 31 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index e9c682557..8b8af35fc 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,6 +1,10 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Adt, HasSource, HirDisplay, Semantics}; | 3 | use hir::{ |
4 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, | ||
5 | ModuleSource, Semantics, | ||
6 | }; | ||
7 | use ra_db::SourceDatabase; | ||
4 | use ra_ide_db::{ | 8 | use ra_ide_db::{ |
5 | defs::{classify_name, classify_name_ref, Definition}, | 9 | defs::{classify_name, classify_name_ref, Definition}, |
6 | RootDatabase, | 10 | RootDatabase, |
@@ -16,6 +20,8 @@ use crate::{ | |||
16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 20 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
17 | FilePosition, RangeInfo, | 21 | FilePosition, RangeInfo, |
18 | }; | 22 | }; |
23 | use itertools::Itertools; | ||
24 | use std::iter::once; | ||
19 | 25 | ||
20 | /// Contains the results when hovering over an item | 26 | /// Contains the results when hovering over an item |
21 | #[derive(Debug, Clone)] | 27 | #[derive(Debug, Clone)] |
@@ -83,44 +89,86 @@ impl HoverResult { | |||
83 | } | 89 | } |
84 | } | 90 | } |
85 | 91 | ||
86 | fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> { | 92 | fn hover_text( |
87 | match (desc, docs) { | 93 | docs: Option<String>, |
88 | (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), | 94 | desc: Option<String>, |
89 | (None, Some(docs)) => Some(docs), | 95 | mod_path: Option<String>, |
96 | ) -> Option<String> { | ||
97 | match (desc, docs, mod_path) { | ||
98 | (Some(desc), docs, mod_path) => Some(rust_code_markup_with_doc(desc, docs, mod_path)), | ||
99 | (None, Some(docs), _) => Some(docs), | ||
100 | _ => None, | ||
101 | } | ||
102 | } | ||
103 | |||
104 | fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> { | ||
105 | match def { | ||
106 | Definition::StructField(f) => Some(f.parent_def(db).name(db)), | ||
107 | Definition::Local(l) => l.parent(db).name(db), | ||
108 | Definition::ModuleDef(md) => match md { | ||
109 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | ||
110 | AssocItemContainer::Trait(t) => Some(t.name(db)), | ||
111 | AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | ||
112 | }, | ||
113 | ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)), | ||
114 | _ => None, | ||
115 | }, | ||
116 | Definition::SelfType(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | ||
90 | _ => None, | 117 | _ => None, |
91 | } | 118 | } |
119 | .map(|name| name.to_string()) | ||
120 | } | ||
121 | |||
122 | fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | ||
123 | let mod_path = def.module(db).map(|module| { | ||
124 | once(db.crate_graph().crate_data(&module.krate().into()).display_name.clone()) | ||
125 | .chain( | ||
126 | module | ||
127 | .path_to_root(db) | ||
128 | .into_iter() | ||
129 | .rev() | ||
130 | .map(|it| it.name(db).map(|name| name.to_string())), | ||
131 | ) | ||
132 | .chain(once(definition_owner_name(db, def))) | ||
133 | .flatten() | ||
134 | .join("::") | ||
135 | }); | ||
136 | mod_path | ||
92 | } | 137 | } |
93 | 138 | ||
94 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { | 139 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { |
140 | let mod_path = determine_mod_path(db, &def); | ||
95 | return match def { | 141 | return match def { |
96 | Definition::Macro(it) => { | 142 | Definition::Macro(it) => { |
97 | let src = it.source(db); | 143 | let src = it.source(db); |
98 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value))) | 144 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) |
99 | } | 145 | } |
100 | Definition::StructField(it) => { | 146 | Definition::StructField(it) => { |
101 | let src = it.source(db); | 147 | let src = it.source(db); |
102 | match src.value { | 148 | match src.value { |
103 | hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), | 149 | FieldSource::Named(it) => { |
150 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | ||
151 | } | ||
104 | _ => None, | 152 | _ => None, |
105 | } | 153 | } |
106 | } | 154 | } |
107 | Definition::ModuleDef(it) => match it { | 155 | Definition::ModuleDef(it) => match it { |
108 | hir::ModuleDef::Module(it) => match it.definition_source(db).value { | 156 | ModuleDef::Module(it) => match it.definition_source(db).value { |
109 | hir::ModuleSource::Module(it) => { | 157 | ModuleSource::Module(it) => { |
110 | hover_text(it.doc_comment_text(), it.short_label()) | 158 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) |
111 | } | 159 | } |
112 | _ => None, | 160 | _ => None, |
113 | }, | 161 | }, |
114 | hir::ModuleDef::Function(it) => from_def_source(db, it), | 162 | ModuleDef::Function(it) => from_def_source(db, it, mod_path), |
115 | hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it), | 163 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), |
116 | hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it), | 164 | ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), |
117 | hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it), | 165 | ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path), |
118 | hir::ModuleDef::EnumVariant(it) => from_def_source(db, it), | 166 | ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path), |
119 | hir::ModuleDef::Const(it) => from_def_source(db, it), | 167 | ModuleDef::Const(it) => from_def_source(db, it, mod_path), |
120 | hir::ModuleDef::Static(it) => from_def_source(db, it), | 168 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
121 | hir::ModuleDef::Trait(it) => from_def_source(db, it), | 169 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
122 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), | 170 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
123 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), | 171 | ModuleDef::BuiltinType(it) => Some(it.to_string()), |
124 | }, | 172 | }, |
125 | Definition::Local(it) => { | 173 | Definition::Local(it) => { |
126 | Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) | 174 | Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) |
@@ -131,13 +179,13 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
131 | } | 179 | } |
132 | }; | 180 | }; |
133 | 181 | ||
134 | fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String> | 182 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> |
135 | where | 183 | where |
136 | D: HasSource<Ast = A>, | 184 | D: HasSource<Ast = A>, |
137 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | 185 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, |
138 | { | 186 | { |
139 | let src = def.source(db); | 187 | let src = def.source(db); |
140 | hover_text(src.value.doc_comment_text(), src.value.short_label()) | 188 | hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) |
141 | } | 189 | } |
142 | } | 190 | } |
143 | 191 | ||
@@ -345,7 +393,7 @@ mod tests { | |||
345 | }; | 393 | }; |
346 | } | 394 | } |
347 | "#, | 395 | "#, |
348 | &["field_a: u32"], | 396 | &["Foo\nfield_a: u32"], |
349 | ); | 397 | ); |
350 | 398 | ||
351 | // Hovering over the field in the definition | 399 | // Hovering over the field in the definition |
@@ -362,7 +410,7 @@ mod tests { | |||
362 | }; | 410 | }; |
363 | } | 411 | } |
364 | "#, | 412 | "#, |
365 | &["field_a: u32"], | 413 | &["Foo\nfield_a: u32"], |
366 | ); | 414 | ); |
367 | } | 415 | } |
368 | 416 | ||
@@ -415,7 +463,7 @@ fn main() { | |||
415 | ", | 463 | ", |
416 | ); | 464 | ); |
417 | let hover = analysis.hover(position).unwrap().unwrap(); | 465 | let hover = analysis.hover(position).unwrap().unwrap(); |
418 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Some")); | 466 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\nSome")); |
419 | 467 | ||
420 | let (analysis, position) = single_file_with_position( | 468 | let (analysis, position) = single_file_with_position( |
421 | " | 469 | " |
@@ -442,6 +490,7 @@ fn main() { | |||
442 | } | 490 | } |
443 | "#, | 491 | "#, |
444 | &[" | 492 | &[" |
493 | Option | ||
445 | None | 494 | None |
446 | ``` | 495 | ``` |
447 | 496 | ||
@@ -462,6 +511,7 @@ The None variant | |||
462 | } | 511 | } |
463 | "#, | 512 | "#, |
464 | &[" | 513 | &[" |
514 | Option | ||
465 | Some | 515 | Some |
466 | ``` | 516 | ``` |
467 | 517 | ||
@@ -528,21 +578,23 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
528 | fn test_hover_infer_associated_method_exact() { | 578 | fn test_hover_infer_associated_method_exact() { |
529 | let (analysis, position) = single_file_with_position( | 579 | let (analysis, position) = single_file_with_position( |
530 | " | 580 | " |
531 | struct Thing { x: u32 } | 581 | mod wrapper { |
582 | struct Thing { x: u32 } | ||
532 | 583 | ||
533 | impl Thing { | 584 | impl Thing { |
534 | fn new() -> Thing { | 585 | fn new() -> Thing { |
535 | Thing { x: 0 } | 586 | Thing { x: 0 } |
587 | } | ||
536 | } | 588 | } |
537 | } | 589 | } |
538 | 590 | ||
539 | fn main() { | 591 | fn main() { |
540 | let foo_test = Thing::new<|>(); | 592 | let foo_test = wrapper::Thing::new<|>(); |
541 | } | 593 | } |
542 | ", | 594 | ", |
543 | ); | 595 | ); |
544 | let hover = analysis.hover(position).unwrap().unwrap(); | 596 | let hover = analysis.hover(position).unwrap().unwrap(); |
545 | assert_eq!(trim_markup_opt(hover.info.first()), Some("fn new() -> Thing")); | 597 | assert_eq!(trim_markup_opt(hover.info.first()), Some("wrapper::Thing\nfn new() -> Thing")); |
546 | assert_eq!(hover.info.is_exact(), true); | 598 | assert_eq!(hover.info.is_exact(), true); |
547 | } | 599 | } |
548 | 600 | ||