aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/hover.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r--crates/ide/src/hover.rs63
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};
12use itertools::Itertools; 12use itertools::Itertools;
13use stdx::format_to; 13use stdx::format_to;
14use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 14use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
15 15
16use crate::{ 16use 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#"
3488fn no_hover() { 3508fn 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.
3784fn 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}