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.rs135
1 files changed, 78 insertions, 57 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 0c1da8774..c6d6bb74a 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,39 +30,20 @@ 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 documentation: Option<HoverDocFormat>,
40 pub documentation: bool,
41} 35}
42 36
43impl HoverConfig { 37impl HoverConfig {
44 pub const NO_ACTIONS: Self = Self { 38 fn markdown(&self) -> bool {
45 implementations: false, 39 matches!(self.documentation, Some(HoverDocFormat::Markdown))
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 } 40 }
41}
62 42
63 pub fn runnable(&self) -> bool { 43#[derive(Clone, Debug, PartialEq, Eq)]
64 self.run || self.debug 44pub enum HoverDocFormat {
65 } 45 Markdown,
46 PlainText,
66} 47}
67 48
68#[derive(Debug, Clone)] 49#[derive(Debug, Clone)]
@@ -95,9 +76,7 @@ pub struct HoverResult {
95pub(crate) fn hover( 76pub(crate) fn hover(
96 db: &RootDatabase, 77 db: &RootDatabase,
97 position: FilePosition, 78 position: FilePosition,
98 links_in_hover: bool, 79 config: &HoverConfig,
99 documentation: bool,
100 markdown: bool,
101) -> Option<RangeInfo<HoverResult>> { 80) -> Option<RangeInfo<HoverResult>> {
102 let sema = hir::Semantics::new(db); 81 let sema = hir::Semantics::new(db);
103 let file = sema.parse(position.file_id).syntax().clone(); 82 let file = sema.parse(position.file_id).syntax().clone();
@@ -156,10 +135,8 @@ pub(crate) fn hover(
156 } 135 }
157 _ => None, 136 _ => None,
158 }; 137 };
159 if let Some(markup) = 138 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) 139 res.markup = process_markup(sema.db, definition, &markup, config);
161 {
162 res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown);
163 if let Some(action) = show_implementations_action(db, definition) { 140 if let Some(action) = show_implementations_action(db, definition) {
164 res.actions.push(action); 141 res.actions.push(action);
165 } 142 }
@@ -181,8 +158,7 @@ pub(crate) fn hover(
181 } 158 }
182 } 159 }
183 160
184 if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token) 161 if let res @ Some(_) = hover_for_keyword(&sema, config, &token) {
185 {
186 return res; 162 return res;
187 } 163 }
188 164
@@ -201,7 +177,7 @@ pub(crate) fn hover(
201 } 177 }
202 }; 178 };
203 179
204 res.markup = if markdown { 180 res.markup = if config.markdown() {
205 Markup::fenced_block(&ty.display(db)) 181 Markup::fenced_block(&ty.display(db))
206 } else { 182 } else {
207 ty.display(db).to_string().into() 183 ty.display(db).to_string().into()
@@ -375,13 +351,12 @@ fn process_markup(
375 db: &RootDatabase, 351 db: &RootDatabase,
376 def: Definition, 352 def: Definition,
377 markup: &Markup, 353 markup: &Markup,
378 links_in_hover: bool, 354 config: &HoverConfig,
379 markdown: bool,
380) -> Markup { 355) -> Markup {
381 let markup = markup.as_str(); 356 let markup = markup.as_str();
382 let markup = if !markdown { 357 let markup = if !config.markdown() {
383 remove_markdown(markup) 358 remove_markdown(markup)
384 } else if links_in_hover { 359 } else if config.links_in_hover {
385 rewrite_links(db, markup, &def) 360 rewrite_links(db, markup, &def)
386 } else { 361 } else {
387 remove_links(markup) 362 remove_links(markup)
@@ -428,7 +403,7 @@ fn hover_for_definition(
428 db: &RootDatabase, 403 db: &RootDatabase,
429 def: Definition, 404 def: Definition,
430 famous_defs: Option<&FamousDefs>, 405 famous_defs: Option<&FamousDefs>,
431 documentation: bool, 406 config: &HoverConfig,
432) -> Option<Markup> { 407) -> Option<Markup> {
433 let mod_path = definition_mod_path(db, &def); 408 let mod_path = definition_mod_path(db, &def);
434 let (label, docs) = match def { 409 let (label, docs) = match def {
@@ -466,7 +441,11 @@ fn hover_for_definition(
466 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), 441 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
467 }; 442 };
468 443
469 return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); 444 return hover_markup(
445 docs.filter(|_| config.documentation.is_some()).map(Into::into),
446 label,
447 mod_path,
448 );
470 449
471 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>) 450 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
472 where 451 where
@@ -502,13 +481,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
502} 481}
503 482
504fn hover_for_keyword( 483fn hover_for_keyword(
505 sema: &hir::Semantics<RootDatabase>, 484 sema: &Semantics<RootDatabase>,
506 links_in_hover: bool, 485 config: &HoverConfig,
507 markdown: bool,
508 documentation: bool,
509 token: &SyntaxToken, 486 token: &SyntaxToken,
510) -> Option<RangeInfo<HoverResult>> { 487) -> Option<RangeInfo<HoverResult>> {
511 if !token.kind().is_keyword() || !documentation { 488 if !token.kind().is_keyword() || !config.documentation.is_some() {
512 return None; 489 return None;
513 } 490 }
514 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); 491 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate());
@@ -520,8 +497,7 @@ fn hover_for_keyword(
520 sema.db, 497 sema.db,
521 Definition::ModuleDef(doc_owner.into()), 498 Definition::ModuleDef(doc_owner.into()),
522 &hover_markup(Some(docs.into()), token.text().into(), None)?, 499 &hover_markup(Some(docs.into()), token.text().into(), None)?,
523 links_in_hover, 500 config,
524 markdown,
525 ); 501 );
526 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() })) 502 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
527} 503}
@@ -561,16 +537,34 @@ mod tests {
561 use expect_test::{expect, Expect}; 537 use expect_test::{expect, Expect};
562 use ide_db::base_db::FileLoader; 538 use ide_db::base_db::FileLoader;
563 539
564 use crate::fixture; 540 use crate::{fixture, hover::HoverDocFormat, HoverConfig};
565 541
566 fn check_hover_no_result(ra_fixture: &str) { 542 fn check_hover_no_result(ra_fixture: &str) {
567 let (analysis, position) = fixture::position(ra_fixture); 543 let (analysis, position) = fixture::position(ra_fixture);
568 assert!(analysis.hover(position, true, true, true).unwrap().is_none()); 544 assert!(analysis
545 .hover(
546 position,
547 &HoverConfig {
548 links_in_hover: true,
549 documentation: Some(HoverDocFormat::Markdown)
550 }
551 )
552 .unwrap()
553 .is_none());
569 } 554 }
570 555
571 fn check(ra_fixture: &str, expect: Expect) { 556 fn check(ra_fixture: &str, expect: Expect) {
572 let (analysis, position) = fixture::position(ra_fixture); 557 let (analysis, position) = fixture::position(ra_fixture);
573 let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); 558 let hover = analysis
559 .hover(
560 position,
561 &HoverConfig {
562 links_in_hover: true,
563 documentation: Some(HoverDocFormat::Markdown),
564 },
565 )
566 .unwrap()
567 .unwrap();
574 568
575 let content = analysis.db.file_text(position.file_id); 569 let content = analysis.db.file_text(position.file_id);
576 let hovered_element = &content[hover.range]; 570 let hovered_element = &content[hover.range];
@@ -581,7 +575,16 @@ mod tests {
581 575
582 fn check_hover_no_links(ra_fixture: &str, expect: Expect) { 576 fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
583 let (analysis, position) = fixture::position(ra_fixture); 577 let (analysis, position) = fixture::position(ra_fixture);
584 let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); 578 let hover = analysis
579 .hover(
580 position,
581 &HoverConfig {
582 links_in_hover: false,
583 documentation: Some(HoverDocFormat::Markdown),
584 },
585 )
586 .unwrap()
587 .unwrap();
585 588
586 let content = analysis.db.file_text(position.file_id); 589 let content = analysis.db.file_text(position.file_id);
587 let hovered_element = &content[hover.range]; 590 let hovered_element = &content[hover.range];
@@ -592,7 +595,16 @@ mod tests {
592 595
593 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { 596 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
594 let (analysis, position) = fixture::position(ra_fixture); 597 let (analysis, position) = fixture::position(ra_fixture);
595 let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); 598 let hover = analysis
599 .hover(
600 position,
601 &HoverConfig {
602 links_in_hover: true,
603 documentation: Some(HoverDocFormat::PlainText),
604 },
605 )
606 .unwrap()
607 .unwrap();
596 608
597 let content = analysis.db.file_text(position.file_id); 609 let content = analysis.db.file_text(position.file_id);
598 let hovered_element = &content[hover.range]; 610 let hovered_element = &content[hover.range];
@@ -603,7 +615,16 @@ mod tests {
603 615
604 fn check_actions(ra_fixture: &str, expect: Expect) { 616 fn check_actions(ra_fixture: &str, expect: Expect) {
605 let (analysis, position) = fixture::position(ra_fixture); 617 let (analysis, position) = fixture::position(ra_fixture);
606 let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); 618 let hover = analysis
619 .hover(
620 position,
621 &HoverConfig {
622 links_in_hover: true,
623 documentation: Some(HoverDocFormat::Markdown),
624 },
625 )
626 .unwrap()
627 .unwrap();
607 expect.assert_debug_eq(&hover.info.actions) 628 expect.assert_debug_eq(&hover.info.actions)
608 } 629 }
609 630