diff options
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r-- | crates/ide/src/hover.rs | 63 |
1 files changed, 54 insertions, 9 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index a3fb17c0a..c43089476 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -11,11 +11,14 @@ use ide_db::{ | |||
11 | }; | 11 | }; |
12 | use itertools::Itertools; | 12 | use itertools::Itertools; |
13 | use stdx::format_to; | 13 | use stdx::format_to; |
14 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 14 | use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | display::{macro_label, TryToNav}, | 17 | display::{macro_label, TryToNav}, |
18 | doc_links::{remove_links, rewrite_links}, | 18 | doc_links::{ |
19 | doc_owner_to_def, extract_positioned_link_from_comment, remove_links, | ||
20 | resolve_doc_path_for_def, rewrite_links, | ||
21 | }, | ||
19 | markdown_remove::remove_markdown, | 22 | markdown_remove::remove_markdown, |
20 | markup::Markup, | 23 | markup::Markup, |
21 | runnables::{runnable_fn, runnable_mod}, | 24 | runnables::{runnable_fn, runnable_mod}, |
@@ -93,20 +96,35 @@ pub(crate) fn hover( | |||
93 | let mut res = HoverResult::default(); | 96 | let mut res = HoverResult::default(); |
94 | 97 | ||
95 | let node = token.parent()?; | 98 | let node = token.parent()?; |
99 | let mut range = None; | ||
96 | let definition = match_ast! { | 100 | let definition = match_ast! { |
97 | match node { | 101 | match node { |
98 | // we don't use NameClass::referenced_or_defined here as we do not want to resolve | 102 | // we don't use NameClass::referenced_or_defined here as we do not want to resolve |
99 | // field pattern shorthands to their definition | 103 | // field pattern shorthands to their definition |
100 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|class| match class { | 104 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|class| match class { |
101 | NameClass::ConstReference(def) => Some(def), | 105 | NameClass::ConstReference(def) => Some(def), |
102 | def => def.defined(sema.db), | 106 | def => def.defined(db), |
103 | }), | 107 | }), |
104 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 108 | ast::NameRef(name_ref) => { |
105 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) | 109 | NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(db)) |
106 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), | 110 | }, |
107 | _ => None, | 111 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime).map_or_else( |
112 | || NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(db)), | ||
113 | |d| d.defined(db), | ||
114 | ), | ||
115 | |||
116 | _ => ast::Comment::cast(token.clone()) | ||
117 | .and_then(|comment| { | ||
118 | let (idl_range, link, ns) = | ||
119 | extract_positioned_link_from_comment(position.offset, &comment)?; | ||
120 | range = Some(idl_range); | ||
121 | let def = doc_owner_to_def(&sema, &node)?; | ||
122 | resolve_doc_path_for_def(db, def, &link, ns) | ||
123 | }) | ||
124 | .map(Definition::ModuleDef), | ||
108 | } | 125 | } |
109 | }; | 126 | }; |
127 | |||
110 | if let Some(definition) = definition { | 128 | if let Some(definition) = definition { |
111 | let famous_defs = match &definition { | 129 | let famous_defs = match &definition { |
112 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => { | 130 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => { |
@@ -128,15 +146,16 @@ pub(crate) fn hover( | |||
128 | res.actions.push(action); | 146 | res.actions.push(action); |
129 | } | 147 | } |
130 | 148 | ||
131 | let range = sema.original_range(&node).range; | 149 | let range = range.unwrap_or_else(|| sema.original_range(&node).range); |
132 | return Some(RangeInfo::new(range, res)); | 150 | return Some(RangeInfo::new(range, res)); |
133 | } | 151 | } |
134 | } | 152 | } |
135 | 153 | ||
136 | if token.kind() == syntax::SyntaxKind::COMMENT { | 154 | if token.kind() == syntax::SyntaxKind::COMMENT { |
137 | // don't highlight the entire parent node on comment hover | 155 | cov_mark::hit!(no_highlight_on_comment_hover); |
138 | return None; | 156 | return None; |
139 | } | 157 | } |
158 | |||
140 | if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, &token) { | 159 | if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, &token) { |
141 | return res; | 160 | return res; |
142 | } | 161 | } |
@@ -3483,6 +3502,7 @@ fn foo$0() {} | |||
3483 | 3502 | ||
3484 | #[test] | 3503 | #[test] |
3485 | fn hover_comments_dont_highlight_parent() { | 3504 | fn hover_comments_dont_highlight_parent() { |
3505 | cov_mark::check!(no_highlight_on_comment_hover); | ||
3486 | check_hover_no_result( | 3506 | check_hover_no_result( |
3487 | r#" | 3507 | r#" |
3488 | fn no_hover() { | 3508 | fn no_hover() { |
@@ -3755,4 +3775,29 @@ fn main() { | |||
3755 | "#]], | 3775 | "#]], |
3756 | ) | 3776 | ) |
3757 | } | 3777 | } |
3778 | |||
3779 | #[test] | ||
3780 | fn hover_intra_doc_links() { | ||
3781 | check( | ||
3782 | r#" | ||
3783 | /// This is the [`foo`](foo$0) function. | ||
3784 | fn foo() {} | ||
3785 | "#, | ||
3786 | expect![[r#" | ||
3787 | *[`foo`](foo)* | ||
3788 | |||
3789 | ```rust | ||
3790 | test | ||
3791 | ``` | ||
3792 | |||
3793 | ```rust | ||
3794 | fn foo() | ||
3795 | ``` | ||
3796 | |||
3797 | --- | ||
3798 | |||
3799 | This is the [`foo`](https://docs.rs/test/*/test/fn.foo.html) function. | ||
3800 | "#]], | ||
3801 | ); | ||
3802 | } | ||
3758 | } | 3803 | } |