diff options
author | Kirill Bulatov <[email protected]> | 2020-03-05 23:02:14 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-03-07 21:20:18 +0000 |
commit | 32f5276465266522ebc01b8417feeba99bf00f6f (patch) | |
tree | 6388994a0cc67c7ca60658e81489a832569e3c4e | |
parent | aff82cf7ac172f213cb5dcca637cb2c5332294c1 (diff) |
Show mod path in hover tooltip
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 24 | ||||
-rw-r--r-- | crates/ra_ide/src/display.rs | 14 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 119 | ||||
-rw-r--r-- | crates/ra_ide_db/src/lib.rs | 4 |
4 files changed, 132 insertions, 29 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 2944926e6..dca5f27b2 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -480,6 +480,14 @@ impl Adt { | |||
480 | pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> { | 480 | pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> { |
481 | Some(self.module(db).krate()) | 481 | Some(self.module(db).krate()) |
482 | } | 482 | } |
483 | |||
484 | pub fn name(&self, db: &impl HirDatabase) -> Name { | ||
485 | match self { | ||
486 | Adt::Struct(s) => s.name(db), | ||
487 | Adt::Union(u) => u.name(db), | ||
488 | Adt::Enum(e) => e.name(db), | ||
489 | } | ||
490 | } | ||
483 | } | 491 | } |
484 | 492 | ||
485 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 493 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
@@ -507,6 +515,14 @@ impl VariantDef { | |||
507 | } | 515 | } |
508 | } | 516 | } |
509 | 517 | ||
518 | pub fn name(&self, db: &impl HirDatabase) -> Name { | ||
519 | match self { | ||
520 | VariantDef::Struct(s) => s.name(db), | ||
521 | VariantDef::Union(u) => u.name(db), | ||
522 | VariantDef::EnumVariant(e) => e.name(db), | ||
523 | } | ||
524 | } | ||
525 | |||
510 | pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { | 526 | pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { |
511 | match self { | 527 | match self { |
512 | VariantDef::Struct(it) => it.variant_data(db), | 528 | VariantDef::Struct(it) => it.variant_data(db), |
@@ -534,6 +550,14 @@ impl DefWithBody { | |||
534 | DefWithBody::Static(s) => s.module(db), | 550 | DefWithBody::Static(s) => s.module(db), |
535 | } | 551 | } |
536 | } | 552 | } |
553 | |||
554 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
555 | match self { | ||
556 | DefWithBody::Function(f) => Some(f.name(db)), | ||
557 | DefWithBody::Static(s) => s.name(db), | ||
558 | DefWithBody::Const(c) => c.name(db), | ||
559 | } | ||
560 | } | ||
537 | } | 561 | } |
538 | 562 | ||
539 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 563 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
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 | } |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 79f48c9e3..efa472c7d 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -104,6 +104,10 @@ impl RootDatabase { | |||
104 | db.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); | 104 | db.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); |
105 | db | 105 | db |
106 | } | 106 | } |
107 | |||
108 | pub fn get_crate_original_name(&self, crate_id: &CrateId) -> Option<String> { | ||
109 | self.debug_data.crate_names.get(crate_id).cloned() | ||
110 | } | ||
107 | } | 111 | } |
108 | 112 | ||
109 | impl salsa::ParallelDatabase for RootDatabase { | 113 | impl salsa::ParallelDatabase for RootDatabase { |