diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/display.rs | 14 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 119 |
2 files changed, 104 insertions, 29 deletions
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 1c26a8697..eaeaaa2b4 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -68,17 +68,23 @@ pub(crate) fn macro_label(node: &ast::MacroCall) -> String { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String { | 70 | pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String { |
71 | rust_code_markup_with_doc::<_, &str>(val, None) | 71 | rust_code_markup_with_doc::<_, &str>(val, None, None) |
72 | } | 72 | } |
73 | 73 | ||
74 | pub(crate) fn rust_code_markup_with_doc<CODE, DOC>(val: CODE, doc: Option<DOC>) -> String | 74 | pub(crate) fn rust_code_markup_with_doc<CODE, DOC>( |
75 | val: CODE, | ||
76 | doc: Option<DOC>, | ||
77 | mod_path: Option<String>, | ||
78 | ) -> String | ||
75 | where | 79 | where |
76 | CODE: AsRef<str>, | 80 | CODE: AsRef<str>, |
77 | DOC: AsRef<str>, | 81 | DOC: AsRef<str>, |
78 | { | 82 | { |
83 | let mod_path = | ||
84 | mod_path.filter(|path| !path.is_empty()).map(|path| path + "\n").unwrap_or_default(); | ||
79 | if let Some(doc) = doc { | 85 | if let Some(doc) = doc { |
80 | format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref()) | 86 | format!("```rust\n{}{}\n```\n\n{}", mod_path, val.as_ref(), doc.as_ref()) |
81 | } else { | 87 | } else { |
82 | format!("```rust\n{}\n```", val.as_ref()) | 88 | format!("```rust\n{}{}\n```", mod_path, val.as_ref()) |
83 | } | 89 | } |
84 | } | 90 | } |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index e9c682557..da3b67943 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,6 +1,8 @@ | |||
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, HasSource, HirDisplay, ModuleDef, ModuleSource, Semantics, | ||
5 | }; | ||
4 | use ra_ide_db::{ | 6 | use ra_ide_db::{ |
5 | defs::{classify_name, classify_name_ref, Definition}, | 7 | defs::{classify_name, classify_name_ref, Definition}, |
6 | RootDatabase, | 8 | RootDatabase, |
@@ -16,6 +18,8 @@ use crate::{ | |||
16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 18 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
17 | FilePosition, RangeInfo, | 19 | FilePosition, RangeInfo, |
18 | }; | 20 | }; |
21 | use itertools::Itertools; | ||
22 | use std::iter::once; | ||
19 | 23 | ||
20 | /// Contains the results when hovering over an item | 24 | /// Contains the results when hovering over an item |
21 | #[derive(Debug, Clone)] | 25 | #[derive(Debug, Clone)] |
@@ -83,44 +87,86 @@ impl HoverResult { | |||
83 | } | 87 | } |
84 | } | 88 | } |
85 | 89 | ||
86 | fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> { | 90 | fn hover_text( |
87 | match (desc, docs) { | 91 | docs: Option<String>, |
88 | (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), | 92 | desc: Option<String>, |
89 | (None, Some(docs)) => Some(docs), | 93 | mod_path: Option<String>, |
94 | ) -> Option<String> { | ||
95 | match (desc, docs, mod_path) { | ||
96 | (Some(desc), docs, mod_path) => Some(rust_code_markup_with_doc(desc, docs, mod_path)), | ||
97 | (None, Some(docs), _) => Some(docs), | ||
90 | _ => None, | 98 | _ => None, |
91 | } | 99 | } |
92 | } | 100 | } |
93 | 101 | ||
102 | fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> { | ||
103 | match def { | ||
104 | Definition::StructField(f) => Some(f.parent_def(db).name(db)), | ||
105 | Definition::Local(l) => l.parent(db).name(db), | ||
106 | Definition::ModuleDef(md) => match md { | ||
107 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | ||
108 | AssocItemContainer::Trait(t) => Some(t.name(db)), | ||
109 | AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | ||
110 | }, | ||
111 | ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)), | ||
112 | _ => None, | ||
113 | }, | ||
114 | Definition::SelfType(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | ||
115 | _ => None, | ||
116 | } | ||
117 | .map(|name| name.to_string()) | ||
118 | } | ||
119 | |||
120 | fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | ||
121 | let mod_path = def.module(db).map(|module| { | ||
122 | once(db.get_crate_original_name(&module.krate().into())) | ||
123 | .chain( | ||
124 | module | ||
125 | .path_to_root(db) | ||
126 | .into_iter() | ||
127 | .rev() | ||
128 | .map(|it| it.name(db).map(|name| name.to_string())), | ||
129 | ) | ||
130 | .chain(once(definition_owner_name(db, def))) | ||
131 | .filter_map(std::convert::identity) | ||
132 | .join("::") | ||
133 | }); | ||
134 | mod_path | ||
135 | } | ||
136 | |||
94 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { | 137 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { |
138 | let mod_path = determine_mod_path(db, &def); | ||
95 | return match def { | 139 | return match def { |
96 | Definition::Macro(it) => { | 140 | Definition::Macro(it) => { |
97 | let src = it.source(db); | 141 | let src = it.source(db); |
98 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value))) | 142 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) |
99 | } | 143 | } |
100 | Definition::StructField(it) => { | 144 | Definition::StructField(it) => { |
101 | let src = it.source(db); | 145 | let src = it.source(db); |
102 | match src.value { | 146 | match src.value { |
103 | hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), | 147 | hir::FieldSource::Named(it) => { |
148 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | ||
149 | } | ||
104 | _ => None, | 150 | _ => None, |
105 | } | 151 | } |
106 | } | 152 | } |
107 | Definition::ModuleDef(it) => match it { | 153 | Definition::ModuleDef(it) => match it { |
108 | hir::ModuleDef::Module(it) => match it.definition_source(db).value { | 154 | ModuleDef::Module(it) => match it.definition_source(db).value { |
109 | hir::ModuleSource::Module(it) => { | 155 | ModuleSource::Module(it) => { |
110 | hover_text(it.doc_comment_text(), it.short_label()) | 156 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) |
111 | } | 157 | } |
112 | _ => None, | 158 | _ => None, |
113 | }, | 159 | }, |
114 | hir::ModuleDef::Function(it) => from_def_source(db, it), | 160 | ModuleDef::Function(it) => from_def_source(db, it, mod_path), |
115 | hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it), | 161 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), |
116 | hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it), | 162 | ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), |
117 | hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it), | 163 | ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path), |
118 | hir::ModuleDef::EnumVariant(it) => from_def_source(db, it), | 164 | ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path), |
119 | hir::ModuleDef::Const(it) => from_def_source(db, it), | 165 | ModuleDef::Const(it) => from_def_source(db, it, mod_path), |
120 | hir::ModuleDef::Static(it) => from_def_source(db, it), | 166 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
121 | hir::ModuleDef::Trait(it) => from_def_source(db, it), | 167 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
122 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), | 168 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
123 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), | 169 | ModuleDef::BuiltinType(it) => Some(it.to_string()), |
124 | }, | 170 | }, |
125 | Definition::Local(it) => { | 171 | Definition::Local(it) => { |
126 | Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) | 172 | Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) |
@@ -131,13 +177,13 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
131 | } | 177 | } |
132 | }; | 178 | }; |
133 | 179 | ||
134 | fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String> | 180 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> |
135 | where | 181 | where |
136 | D: HasSource<Ast = A>, | 182 | D: HasSource<Ast = A>, |
137 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | 183 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, |
138 | { | 184 | { |
139 | let src = def.source(db); | 185 | let src = def.source(db); |
140 | hover_text(src.value.doc_comment_text(), src.value.short_label()) | 186 | hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) |
141 | } | 187 | } |
142 | } | 188 | } |
143 | 189 | ||
@@ -345,7 +391,7 @@ mod tests { | |||
345 | }; | 391 | }; |
346 | } | 392 | } |
347 | "#, | 393 | "#, |
348 | &["field_a: u32"], | 394 | &["Foo\nfield_a: u32"], |
349 | ); | 395 | ); |
350 | 396 | ||
351 | // Hovering over the field in the definition | 397 | // Hovering over the field in the definition |
@@ -362,7 +408,7 @@ mod tests { | |||
362 | }; | 408 | }; |
363 | } | 409 | } |
364 | "#, | 410 | "#, |
365 | &["field_a: u32"], | 411 | &["Foo\nfield_a: u32"], |
366 | ); | 412 | ); |
367 | } | 413 | } |
368 | 414 | ||
@@ -415,7 +461,7 @@ fn main() { | |||
415 | ", | 461 | ", |
416 | ); | 462 | ); |
417 | let hover = analysis.hover(position).unwrap().unwrap(); | 463 | let hover = analysis.hover(position).unwrap().unwrap(); |
418 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Some")); | 464 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\nSome")); |
419 | 465 | ||
420 | let (analysis, position) = single_file_with_position( | 466 | let (analysis, position) = single_file_with_position( |
421 | " | 467 | " |
@@ -442,6 +488,7 @@ fn main() { | |||
442 | } | 488 | } |
443 | "#, | 489 | "#, |
444 | &[" | 490 | &[" |
491 | Option | ||
445 | None | 492 | None |
446 | ``` | 493 | ``` |
447 | 494 | ||
@@ -462,6 +509,7 @@ The None variant | |||
462 | } | 509 | } |
463 | "#, | 510 | "#, |
464 | &[" | 511 | &[" |
512 | Option | ||
465 | Some | 513 | Some |
466 | ``` | 514 | ``` |
467 | 515 | ||
@@ -815,4 +863,25 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
815 | &["fn foo()\n```\n\n<- `\u{3000}` here"], | 863 | &["fn foo()\n```\n\n<- `\u{3000}` here"], |
816 | ); | 864 | ); |
817 | } | 865 | } |
866 | |||
867 | #[test] | ||
868 | fn zzz() { | ||
869 | check_hover_result( | ||
870 | " | ||
871 | //- /main.rs | ||
872 | mod vvv { | ||
873 | pub struct Test; | ||
874 | |||
875 | impl Test { | ||
876 | pub fn whatever() {} | ||
877 | } | ||
878 | } | ||
879 | |||
880 | fn main() { | ||
881 | vvv::Test::what<|>ever(); | ||
882 | } | ||
883 | ", | ||
884 | &["vvv::Test\npub fn whatever()"], | ||
885 | ); | ||
886 | } | ||
818 | } | 887 | } |