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.rs113
1 files changed, 104 insertions, 9 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 37171cbef..bb9f12cd3 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -14,7 +14,7 @@ use test_utils::mark;
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, ShortLabel, ToNav, TryToNav}, 16 display::{macro_label, ShortLabel, ToNav, TryToNav},
17 link_rewrite::rewrite_links, 17 link_rewrite::{remove_links, rewrite_links},
18 markup::Markup, 18 markup::Markup,
19 runnables::runnable, 19 runnables::runnable,
20 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 20 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
@@ -26,17 +26,29 @@ pub struct HoverConfig {
26 pub run: bool, 26 pub run: bool,
27 pub debug: bool, 27 pub debug: bool,
28 pub goto_type_def: bool, 28 pub goto_type_def: bool,
29 pub links_in_hover: bool,
29} 30}
30 31
31impl Default for HoverConfig { 32impl Default for HoverConfig {
32 fn default() -> Self { 33 fn default() -> Self {
33 Self { implementations: true, run: true, debug: true, goto_type_def: true } 34 Self {
35 implementations: true,
36 run: true,
37 debug: true,
38 goto_type_def: true,
39 links_in_hover: true,
40 }
34 } 41 }
35} 42}
36 43
37impl HoverConfig { 44impl HoverConfig {
38 pub const NO_ACTIONS: Self = 45 pub const NO_ACTIONS: Self = Self {
39 Self { implementations: false, run: false, debug: false, goto_type_def: false }; 46 implementations: false,
47 run: false,
48 debug: false,
49 goto_type_def: false,
50 links_in_hover: true,
51 };
40 52
41 pub fn any(&self) -> bool { 53 pub fn any(&self) -> bool {
42 self.implementations || self.runnable() || self.goto_type_def 54 self.implementations || self.runnable() || self.goto_type_def
@@ -75,7 +87,11 @@ pub struct HoverResult {
75// 87//
76// Shows additional information, like type of an expression or documentation for definition when "focusing" code. 88// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
77// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. 89// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
78pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 90pub(crate) fn hover(
91 db: &RootDatabase,
92 position: FilePosition,
93 links_in_hover: bool,
94) -> Option<RangeInfo<HoverResult>> {
79 let sema = Semantics::new(db); 95 let sema = Semantics::new(db);
80 let file = sema.parse(position.file_id).syntax().clone(); 96 let file = sema.parse(position.file_id).syntax().clone();
81 let token = pick_best(file.token_at_offset(position.offset))?; 97 let token = pick_best(file.token_at_offset(position.offset))?;
@@ -93,7 +109,11 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
93 }; 109 };
94 if let Some(definition) = definition { 110 if let Some(definition) = definition {
95 if let Some(markup) = hover_for_definition(db, definition) { 111 if let Some(markup) = hover_for_definition(db, definition) {
96 let markup = rewrite_links(db, &markup.as_str(), &definition); 112 let markup = if links_in_hover {
113 rewrite_links(db, &markup.as_str(), &definition)
114 } else {
115 remove_links(&markup.as_str())
116 };
97 res.markup = Markup::from(markup); 117 res.markup = Markup::from(markup);
98 if let Some(action) = show_implementations_action(db, definition) { 118 if let Some(action) = show_implementations_action(db, definition) {
99 res.actions.push(action); 119 res.actions.push(action);
@@ -363,12 +383,23 @@ mod tests {
363 383
364 fn check_hover_no_result(ra_fixture: &str) { 384 fn check_hover_no_result(ra_fixture: &str) {
365 let (analysis, position) = analysis_and_position(ra_fixture); 385 let (analysis, position) = analysis_and_position(ra_fixture);
366 assert!(analysis.hover(position).unwrap().is_none()); 386 assert!(analysis.hover(position, true).unwrap().is_none());
367 } 387 }
368 388
369 fn check(ra_fixture: &str, expect: Expect) { 389 fn check(ra_fixture: &str, expect: Expect) {
370 let (analysis, position) = analysis_and_position(ra_fixture); 390 let (analysis, position) = analysis_and_position(ra_fixture);
371 let hover = analysis.hover(position).unwrap().unwrap(); 391 let hover = analysis.hover(position, true).unwrap().unwrap();
392
393 let content = analysis.db.file_text(position.file_id);
394 let hovered_element = &content[hover.range];
395
396 let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
397 expect.assert_eq(&actual)
398 }
399
400 fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
401 let (analysis, position) = analysis_and_position(ra_fixture);
402 let hover = analysis.hover(position, false).unwrap().unwrap();
372 403
373 let content = analysis.db.file_text(position.file_id); 404 let content = analysis.db.file_text(position.file_id);
374 let hovered_element = &content[hover.range]; 405 let hovered_element = &content[hover.range];
@@ -379,7 +410,7 @@ mod tests {
379 410
380 fn check_actions(ra_fixture: &str, expect: Expect) { 411 fn check_actions(ra_fixture: &str, expect: Expect) {
381 let (analysis, position) = analysis_and_position(ra_fixture); 412 let (analysis, position) = analysis_and_position(ra_fixture);
382 let hover = analysis.hover(position).unwrap().unwrap(); 413 let hover = analysis.hover(position, true).unwrap().unwrap();
383 expect.assert_debug_eq(&hover.info.actions) 414 expect.assert_debug_eq(&hover.info.actions)
384 } 415 }
385 416
@@ -1810,6 +1841,70 @@ struct S {
1810 } 1841 }
1811 1842
1812 #[test] 1843 #[test]
1844 fn test_hover_no_links() {
1845 check_hover_no_links(
1846 r#"
1847/// Test cases:
1848/// case 1. bare URL: https://www.example.com/
1849/// case 2. inline URL with title: [example](https://www.example.com/)
1850/// case 3. code refrence: [`Result`]
1851/// case 4. code refrence but miss footnote: [`String`]
1852/// case 5. autolink: <http://www.example.com/>
1853/// case 6. email address: <[email protected]>
1854/// case 7. refrence: [example][example]
1855/// case 8. collapsed link: [example][]
1856/// case 9. shortcut link: [example]
1857/// case 10. inline without URL: [example]()
1858/// case 11. refrence: [foo][foo]
1859/// case 12. refrence: [foo][bar]
1860/// case 13. collapsed link: [foo][]
1861/// case 14. shortcut link: [foo]
1862/// case 15. inline without URL: [foo]()
1863/// case 16. just escaped text: \[foo]
1864/// case 17. inline link: [Foo](foo::Foo)
1865///
1866/// [`Result`]: ../../std/result/enum.Result.html
1867/// [^example]: https://www.example.com/
1868pub fn fo<|>o() {}
1869"#,
1870 expect![[r#"
1871 *foo*
1872
1873 ```rust
1874 test
1875 ```
1876
1877 ```rust
1878 pub fn foo()
1879 ```
1880
1881 ---
1882
1883 Test cases:
1884 case 1. bare URL: https://www.example.com/
1885 case 2. inline URL with title: [example](https://www.example.com/)
1886 case 3. code refrence: `Result`
1887 case 4. code refrence but miss footnote: `String`
1888 case 5. autolink: http://www.example.com/
1889 case 6. email address: [email protected]
1890 case 7. refrence: example
1891 case 8. collapsed link: example
1892 case 9. shortcut link: example
1893 case 10. inline without URL: example
1894 case 11. refrence: foo
1895 case 12. refrence: foo
1896 case 13. collapsed link: foo
1897 case 14. shortcut link: foo
1898 case 15. inline without URL: foo
1899 case 16. just escaped text: \[foo]
1900 case 17. inline link: Foo
1901
1902 [^example]: https://www.example.com/
1903 "#]],
1904 );
1905 }
1906
1907 #[test]
1813 fn test_hover_macro_generated_struct_fn_doc_comment() { 1908 fn test_hover_macro_generated_struct_fn_doc_comment() {
1814 mark::check!(hover_macro_generated_struct_fn_doc_comment); 1909 mark::check!(hover_macro_generated_struct_fn_doc_comment);
1815 1910