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.rs111
1 files changed, 55 insertions, 56 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 0c1da8774..35050899d 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,5 +1,5 @@
1use either::Either; 1use either::Either;
2use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay}; 2use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
3use ide_db::{ 3use ide_db::{
4 base_db::SourceDatabase, 4 base_db::SourceDatabase,
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
@@ -30,41 +30,11 @@ use crate::{
30 30
31#[derive(Clone, Debug, PartialEq, Eq)] 31#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct HoverConfig { 32pub struct HoverConfig {
33 pub implementations: bool,
34 pub references: bool,
35 pub run: bool,
36 pub debug: bool,
37 pub goto_type_def: bool,
38 pub links_in_hover: bool, 33 pub links_in_hover: bool,
39 pub markdown: bool, 34 pub markdown: bool,
40 pub documentation: bool, 35 pub documentation: bool,
41} 36}
42 37
43impl HoverConfig {
44 pub const NO_ACTIONS: Self = Self {
45 implementations: false,
46 references: false,
47 run: false,
48 debug: false,
49 goto_type_def: false,
50 links_in_hover: true,
51 markdown: true,
52 documentation: true,
53 };
54
55 pub fn any_actions(&self) -> bool {
56 self.implementations || self.references || self.runnable() || self.goto_type_def
57 }
58
59 pub fn no_actions(&self) -> bool {
60 !self.any_actions()
61 }
62
63 pub fn runnable(&self) -> bool {
64 self.run || self.debug
65 }
66}
67
68#[derive(Debug, Clone)] 38#[derive(Debug, Clone)]
69pub enum HoverAction { 39pub enum HoverAction {
70 Runnable(Runnable), 40 Runnable(Runnable),
@@ -95,9 +65,7 @@ pub struct HoverResult {
95pub(crate) fn hover( 65pub(crate) fn hover(
96 db: &RootDatabase, 66 db: &RootDatabase,
97 position: FilePosition, 67 position: FilePosition,
98 links_in_hover: bool, 68 config: &HoverConfig,
99 documentation: bool,
100 markdown: bool,
101) -> Option<RangeInfo<HoverResult>> { 69) -> Option<RangeInfo<HoverResult>> {
102 let sema = hir::Semantics::new(db); 70 let sema = hir::Semantics::new(db);
103 let file = sema.parse(position.file_id).syntax().clone(); 71 let file = sema.parse(position.file_id).syntax().clone();
@@ -156,10 +124,14 @@ pub(crate) fn hover(
156 } 124 }
157 _ => None, 125 _ => None,
158 }; 126 };
159 if let Some(markup) = 127 if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) {
160 hover_for_definition(db, definition, famous_defs.as_ref(), documentation) 128 res.markup = process_markup(
161 { 129 sema.db,
162 res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); 130 definition,
131 &markup,
132 config.links_in_hover,
133 config.markdown,
134 );
163 if let Some(action) = show_implementations_action(db, definition) { 135 if let Some(action) = show_implementations_action(db, definition) {
164 res.actions.push(action); 136 res.actions.push(action);
165 } 137 }
@@ -181,8 +153,7 @@ pub(crate) fn hover(
181 } 153 }
182 } 154 }
183 155
184 if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token) 156 if let res @ Some(_) = hover_for_keyword(&sema, config, &token) {
185 {
186 return res; 157 return res;
187 } 158 }
188 159
@@ -201,7 +172,7 @@ pub(crate) fn hover(
201 } 172 }
202 }; 173 };
203 174
204 res.markup = if markdown { 175 res.markup = if config.markdown {
205 Markup::fenced_block(&ty.display(db)) 176 Markup::fenced_block(&ty.display(db))
206 } else { 177 } else {
207 ty.display(db).to_string().into() 178 ty.display(db).to_string().into()
@@ -428,7 +399,7 @@ fn hover_for_definition(
428 db: &RootDatabase, 399 db: &RootDatabase,
429 def: Definition, 400 def: Definition,
430 famous_defs: Option<&FamousDefs>, 401 famous_defs: Option<&FamousDefs>,
431 documentation: bool, 402 config: &HoverConfig,
432) -> Option<Markup> { 403) -> Option<Markup> {
433 let mod_path = definition_mod_path(db, &def); 404 let mod_path = definition_mod_path(db, &def);
434 let (label, docs) = match def { 405 let (label, docs) = match def {
@@ -466,7 +437,7 @@ fn hover_for_definition(
466 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), 437 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
467 }; 438 };
468 439
469 return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); 440 return hover_markup(docs.filter(|_| config.documentation).map(Into::into), label, mod_path);
470 441
471 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>) 442 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
472 where 443 where
@@ -502,13 +473,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
502} 473}
503 474
504fn hover_for_keyword( 475fn hover_for_keyword(
505 sema: &hir::Semantics<RootDatabase>, 476 sema: &Semantics<RootDatabase>,
506 links_in_hover: bool, 477 config: &HoverConfig,
507 markdown: bool,
508 documentation: bool,
509 token: &SyntaxToken, 478 token: &SyntaxToken,
510) -> Option<RangeInfo<HoverResult>> { 479) -> Option<RangeInfo<HoverResult>> {
511 if !token.kind().is_keyword() || !documentation { 480 if !token.kind().is_keyword() || !config.documentation {
512 return None; 481 return None;
513 } 482 }
514 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); 483 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate());
@@ -520,8 +489,8 @@ fn hover_for_keyword(
520 sema.db, 489 sema.db,
521 Definition::ModuleDef(doc_owner.into()), 490 Definition::ModuleDef(doc_owner.into()),
522 &hover_markup(Some(docs.into()), token.text().into(), None)?, 491 &hover_markup(Some(docs.into()), token.text().into(), None)?,
523 links_in_hover, 492 config.links_in_hover,
524 markdown, 493 config.markdown,
525 ); 494 );
526 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() })) 495 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
527} 496}
@@ -561,16 +530,28 @@ mod tests {
561 use expect_test::{expect, Expect}; 530 use expect_test::{expect, Expect};
562 use ide_db::base_db::FileLoader; 531 use ide_db::base_db::FileLoader;
563 532
564 use crate::fixture; 533 use crate::{fixture, HoverConfig};
565 534
566 fn check_hover_no_result(ra_fixture: &str) { 535 fn check_hover_no_result(ra_fixture: &str) {
567 let (analysis, position) = fixture::position(ra_fixture); 536 let (analysis, position) = fixture::position(ra_fixture);
568 assert!(analysis.hover(position, true, true, true).unwrap().is_none()); 537 assert!(analysis
538 .hover(
539 position,
540 &HoverConfig { links_in_hover: true, markdown: true, documentation: true }
541 )
542 .unwrap()
543 .is_none());
569 } 544 }
570 545
571 fn check(ra_fixture: &str, expect: Expect) { 546 fn check(ra_fixture: &str, expect: Expect) {
572 let (analysis, position) = fixture::position(ra_fixture); 547 let (analysis, position) = fixture::position(ra_fixture);
573 let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); 548 let hover = analysis
549 .hover(
550 position,
551 &HoverConfig { links_in_hover: true, markdown: true, documentation: true },
552 )
553 .unwrap()
554 .unwrap();
574 555
575 let content = analysis.db.file_text(position.file_id); 556 let content = analysis.db.file_text(position.file_id);
576 let hovered_element = &content[hover.range]; 557 let hovered_element = &content[hover.range];
@@ -581,7 +562,13 @@ mod tests {
581 562
582 fn check_hover_no_links(ra_fixture: &str, expect: Expect) { 563 fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
583 let (analysis, position) = fixture::position(ra_fixture); 564 let (analysis, position) = fixture::position(ra_fixture);
584 let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); 565 let hover = analysis
566 .hover(
567 position,
568 &HoverConfig { links_in_hover: false, markdown: true, documentation: true },
569 )
570 .unwrap()
571 .unwrap();
585 572
586 let content = analysis.db.file_text(position.file_id); 573 let content = analysis.db.file_text(position.file_id);
587 let hovered_element = &content[hover.range]; 574 let hovered_element = &content[hover.range];
@@ -592,7 +579,13 @@ mod tests {
592 579
593 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { 580 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
594 let (analysis, position) = fixture::position(ra_fixture); 581 let (analysis, position) = fixture::position(ra_fixture);
595 let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); 582 let hover = analysis
583 .hover(
584 position,
585 &HoverConfig { links_in_hover: true, markdown: false, documentation: true },
586 )
587 .unwrap()
588 .unwrap();
596 589
597 let content = analysis.db.file_text(position.file_id); 590 let content = analysis.db.file_text(position.file_id);
598 let hovered_element = &content[hover.range]; 591 let hovered_element = &content[hover.range];
@@ -603,7 +596,13 @@ mod tests {
603 596
604 fn check_actions(ra_fixture: &str, expect: Expect) { 597 fn check_actions(ra_fixture: &str, expect: Expect) {
605 let (analysis, position) = fixture::position(ra_fixture); 598 let (analysis, position) = fixture::position(ra_fixture);
606 let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); 599 let hover = analysis
600 .hover(
601 position,
602 &HoverConfig { links_in_hover: true, markdown: true, documentation: true },
603 )
604 .unwrap()
605 .unwrap();
607 expect.assert_debug_eq(&hover.info.actions) 606 expect.assert_debug_eq(&hover.info.actions)
608 } 607 }
609 608