diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/hover.rs | 135 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 9 |
2 files changed, 82 insertions, 62 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 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay}; | 2 | use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics}; |
3 | use ide_db::{ | 3 | use 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)] |
32 | pub struct HoverConfig { | 32 | pub 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 | ||
43 | impl HoverConfig { | 37 | impl 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 | 44 | pub 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 { | |||
95 | pub(crate) fn hover( | 76 | pub(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 | ||
504 | fn hover_for_keyword( | 483 | fn 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 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 3798f32cc..b978e36af 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -75,7 +75,7 @@ pub use crate::{ | |||
75 | expand_macro::ExpandedMacro, | 75 | expand_macro::ExpandedMacro, |
76 | file_structure::{StructureNode, StructureNodeKind}, | 76 | file_structure::{StructureNode, StructureNodeKind}, |
77 | folding_ranges::{Fold, FoldKind}, | 77 | folding_ranges::{Fold, FoldKind}, |
78 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, | 78 | hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, |
79 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, | 79 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
80 | markup::Markup, | 80 | markup::Markup, |
81 | move_item::Direction, | 81 | move_item::Direction, |
@@ -217,6 +217,7 @@ impl Analysis { | |||
217 | file_id, | 217 | file_id, |
218 | Edition::Edition2018, | 218 | Edition::Edition2018, |
219 | None, | 219 | None, |
220 | cfg_options.clone(), | ||
220 | cfg_options, | 221 | cfg_options, |
221 | Env::default(), | 222 | Env::default(), |
222 | Default::default(), | 223 | Default::default(), |
@@ -407,11 +408,9 @@ impl Analysis { | |||
407 | pub fn hover( | 408 | pub fn hover( |
408 | &self, | 409 | &self, |
409 | position: FilePosition, | 410 | position: FilePosition, |
410 | links_in_hover: bool, | 411 | config: &HoverConfig, |
411 | documentation: bool, | ||
412 | markdown: bool, | ||
413 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { | 412 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { |
414 | self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) | 413 | self.with_db(|db| hover::hover(db, position, config)) |
415 | } | 414 | } |
416 | 415 | ||
417 | /// Return URL(s) for the documentation of the symbol under the cursor. | 416 | /// Return URL(s) for the documentation of the symbol under the cursor. |