diff options
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r-- | crates/ide/src/hover.rs | 187 |
1 files changed, 172 insertions, 15 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c43089476..9de653739 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{ | 2 | use hir::{ |
3 | AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module, | 3 | AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module, |
4 | ModuleDef, Semantics, | 4 | ModuleDef, Semantics, |
5 | }; | 5 | }; |
6 | use ide_db::{ | 6 | use ide_db::{ |
@@ -16,8 +16,8 @@ use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, Toke | |||
16 | use crate::{ | 16 | use crate::{ |
17 | display::{macro_label, TryToNav}, | 17 | display::{macro_label, TryToNav}, |
18 | doc_links::{ | 18 | doc_links::{ |
19 | doc_owner_to_def, extract_positioned_link_from_comment, remove_links, | 19 | doc_attributes, extract_definitions_from_markdown, remove_links, resolve_doc_path_for_def, |
20 | resolve_doc_path_for_def, rewrite_links, | 20 | rewrite_links, |
21 | }, | 21 | }, |
22 | markdown_remove::remove_markdown, | 22 | markdown_remove::remove_markdown, |
23 | markup::Markup, | 23 | markup::Markup, |
@@ -82,6 +82,8 @@ pub struct HoverResult { | |||
82 | // | 82 | // |
83 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. | 83 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. |
84 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. | 84 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. |
85 | // | ||
86 | // image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] | ||
85 | pub(crate) fn hover( | 87 | pub(crate) fn hover( |
86 | db: &RootDatabase, | 88 | db: &RootDatabase, |
87 | position: FilePosition, | 89 | position: FilePosition, |
@@ -114,11 +116,19 @@ pub(crate) fn hover( | |||
114 | ), | 116 | ), |
115 | 117 | ||
116 | _ => ast::Comment::cast(token.clone()) | 118 | _ => ast::Comment::cast(token.clone()) |
117 | .and_then(|comment| { | 119 | .and_then(|_| { |
120 | let (attributes, def) = doc_attributes(&sema, &node)?; | ||
121 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; | ||
118 | let (idl_range, link, ns) = | 122 | let (idl_range, link, ns) = |
119 | extract_positioned_link_from_comment(position.offset, &comment)?; | 123 | extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { |
124 | let InFile { file_id, value: range } = doc_mapping.map(range.clone())?; | ||
125 | if file_id == position.file_id.into() && range.contains(position.offset) { | ||
126 | Some((range, link, ns)) | ||
127 | } else { | ||
128 | None | ||
129 | } | ||
130 | })?; | ||
120 | range = Some(idl_range); | 131 | range = Some(idl_range); |
121 | let def = doc_owner_to_def(&sema, &node)?; | ||
122 | resolve_doc_path_for_def(db, def, &link, ns) | 132 | resolve_doc_path_for_def(db, def, &link, ns) |
123 | }) | 133 | }) |
124 | .map(Definition::ModuleDef), | 134 | .map(Definition::ModuleDef), |
@@ -195,7 +205,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
195 | let adt = match def { | 205 | let adt = match def { |
196 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 206 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
197 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 207 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
198 | Definition::SelfType(it) => it.target_ty(db).as_adt(), | 208 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
199 | _ => None, | 209 | _ => None, |
200 | }?; | 210 | }?; |
201 | adt.try_to_nav(db).map(to_action) | 211 | adt.try_to_nav(db).map(to_action) |
@@ -318,7 +328,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
318 | Definition::ModuleDef(md) => match md { | 328 | Definition::ModuleDef(md) => match md { |
319 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 329 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
320 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 330 | AssocItemContainer::Trait(t) => Some(t.name(db)), |
321 | AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), | 331 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
322 | }, | 332 | }, |
323 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 333 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
324 | _ => None, | 334 | _ => None, |
@@ -376,7 +386,7 @@ fn hover_for_definition( | |||
376 | }, | 386 | }, |
377 | Definition::Local(it) => hover_for_local(it, db), | 387 | Definition::Local(it) => hover_for_local(it, db), |
378 | Definition::SelfType(impl_def) => { | 388 | Definition::SelfType(impl_def) => { |
379 | impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 389 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) |
380 | } | 390 | } |
381 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 391 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), |
382 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 392 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
@@ -470,6 +480,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> | |||
470 | 480 | ||
471 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 481 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
472 | return tokens.max_by_key(priority); | 482 | return tokens.max_by_key(priority); |
483 | |||
473 | fn priority(n: &SyntaxToken) -> usize { | 484 | fn priority(n: &SyntaxToken) -> usize { |
474 | match n.kind() { | 485 | match n.kind() { |
475 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, | 486 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, |
@@ -1235,6 +1246,37 @@ fn f() { fo$0o!(); } | |||
1235 | } | 1246 | } |
1236 | 1247 | ||
1237 | #[test] | 1248 | #[test] |
1249 | fn test_hover_macro2_invocation() { | ||
1250 | check( | ||
1251 | r#" | ||
1252 | /// foo bar | ||
1253 | /// | ||
1254 | /// foo bar baz | ||
1255 | macro foo() {} | ||
1256 | |||
1257 | fn f() { fo$0o!(); } | ||
1258 | "#, | ||
1259 | expect![[r#" | ||
1260 | *foo* | ||
1261 | |||
1262 | ```rust | ||
1263 | test | ||
1264 | ``` | ||
1265 | |||
1266 | ```rust | ||
1267 | macro foo | ||
1268 | ``` | ||
1269 | |||
1270 | --- | ||
1271 | |||
1272 | foo bar | ||
1273 | |||
1274 | foo bar baz | ||
1275 | "#]], | ||
1276 | ) | ||
1277 | } | ||
1278 | |||
1279 | #[test] | ||
1238 | fn test_hover_tuple_field() { | 1280 | fn test_hover_tuple_field() { |
1239 | check( | 1281 | check( |
1240 | r#"struct TS(String, i32$0);"#, | 1282 | r#"struct TS(String, i32$0);"#, |
@@ -3780,24 +3822,139 @@ fn main() { | |||
3780 | fn hover_intra_doc_links() { | 3822 | fn hover_intra_doc_links() { |
3781 | check( | 3823 | check( |
3782 | r#" | 3824 | r#" |
3783 | /// This is the [`foo`](foo$0) function. | 3825 | |
3784 | fn foo() {} | 3826 | pub mod theitem { |
3827 | /// This is the item. Cool! | ||
3828 | pub struct TheItem; | ||
3829 | } | ||
3830 | |||
3831 | /// Gives you a [`TheItem$0`]. | ||
3832 | /// | ||
3833 | /// [`TheItem`]: theitem::TheItem | ||
3834 | pub fn gimme() -> theitem::TheItem { | ||
3835 | theitem::TheItem | ||
3836 | } | ||
3785 | "#, | 3837 | "#, |
3786 | expect![[r#" | 3838 | expect![[r#" |
3787 | *[`foo`](foo)* | 3839 | *[`TheItem`]* |
3788 | 3840 | ||
3789 | ```rust | 3841 | ```rust |
3790 | test | 3842 | test::theitem |
3791 | ``` | 3843 | ``` |
3792 | 3844 | ||
3793 | ```rust | 3845 | ```rust |
3794 | fn foo() | 3846 | pub struct TheItem |
3795 | ``` | 3847 | ``` |
3796 | 3848 | ||
3797 | --- | 3849 | --- |
3798 | 3850 | ||
3799 | This is the [`foo`](https://docs.rs/test/*/test/fn.foo.html) function. | 3851 | This is the item. Cool! |
3852 | "#]], | ||
3853 | ); | ||
3854 | } | ||
3855 | |||
3856 | #[test] | ||
3857 | fn hover_generic_assoc() { | ||
3858 | check( | ||
3859 | r#" | ||
3860 | fn foo<T: A>() where T::Assoc$0: {} | ||
3861 | |||
3862 | trait A { | ||
3863 | type Assoc; | ||
3864 | }"#, | ||
3865 | expect![[r#" | ||
3866 | *Assoc* | ||
3867 | |||
3868 | ```rust | ||
3869 | test | ||
3870 | ``` | ||
3871 | |||
3872 | ```rust | ||
3873 | type Assoc | ||
3874 | ``` | ||
3875 | "#]], | ||
3876 | ); | ||
3877 | check( | ||
3878 | r#" | ||
3879 | fn foo<T: A>() { | ||
3880 | let _: <T>::Assoc$0; | ||
3881 | } | ||
3882 | |||
3883 | trait A { | ||
3884 | type Assoc; | ||
3885 | }"#, | ||
3886 | expect![[r#" | ||
3887 | *Assoc* | ||
3888 | |||
3889 | ```rust | ||
3890 | test | ||
3891 | ``` | ||
3892 | |||
3893 | ```rust | ||
3894 | type Assoc | ||
3895 | ``` | ||
3896 | "#]], | ||
3897 | ); | ||
3898 | check( | ||
3899 | r#" | ||
3900 | trait A where | ||
3901 | Self::Assoc$0: , | ||
3902 | { | ||
3903 | type Assoc; | ||
3904 | }"#, | ||
3905 | expect![[r#" | ||
3906 | *Assoc* | ||
3907 | |||
3908 | ```rust | ||
3909 | test | ||
3910 | ``` | ||
3911 | |||
3912 | ```rust | ||
3913 | type Assoc | ||
3914 | ``` | ||
3800 | "#]], | 3915 | "#]], |
3801 | ); | 3916 | ); |
3802 | } | 3917 | } |
3918 | |||
3919 | #[test] | ||
3920 | fn string_shadowed_with_inner_items() { | ||
3921 | check( | ||
3922 | r#" | ||
3923 | //- /main.rs crate:main deps:alloc | ||
3924 | |||
3925 | /// Custom `String` type. | ||
3926 | struct String; | ||
3927 | |||
3928 | fn f() { | ||
3929 | let _: String$0; | ||
3930 | |||
3931 | fn inner() {} | ||
3932 | } | ||
3933 | |||
3934 | //- /alloc.rs crate:alloc | ||
3935 | #[prelude_import] | ||
3936 | pub use string::*; | ||
3937 | |||
3938 | mod string { | ||
3939 | /// This is `alloc::String`. | ||
3940 | pub struct String; | ||
3941 | } | ||
3942 | "#, | ||
3943 | expect![[r#" | ||
3944 | *String* | ||
3945 | |||
3946 | ```rust | ||
3947 | main | ||
3948 | ``` | ||
3949 | |||
3950 | ```rust | ||
3951 | struct String | ||
3952 | ``` | ||
3953 | |||
3954 | --- | ||
3955 | |||
3956 | Custom `String` type. | ||
3957 | "#]], | ||
3958 | ) | ||
3959 | } | ||
3803 | } | 3960 | } |