aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/hover.rs111
-rw-r--r--crates/ide/src/lib.rs6
-rw-r--r--crates/rust-analyzer/src/config.rs50
-rw-r--r--crates/rust-analyzer/src/handlers.rs24
4 files changed, 110 insertions, 81 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
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index aac084012..e24a32218 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -408,11 +408,9 @@ impl Analysis {
408 pub fn hover( 408 pub fn hover(
409 &self, 409 &self,
410 position: FilePosition, 410 position: FilePosition,
411 links_in_hover: bool, 411 config: &HoverConfig,
412 documentation: bool,
413 markdown: bool,
414 ) -> Cancellable<Option<RangeInfo<HoverResult>>> { 412 ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
415 self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) 413 self.with_db(|db| hover::hover(db, position, config))
416 } 414 }
417 415
418 /// 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.
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3aeca8839..de70959a5 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -32,6 +32,9 @@ use crate::{
32// 32//
33// However, editor specific config, which the server doesn't know about, should 33// However, editor specific config, which the server doesn't know about, should
34// be specified directly in `package.json`. 34// be specified directly in `package.json`.
35//
36// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
37// parsing the old name.
35config_data! { 38config_data! {
36 struct ConfigData { 39 struct ConfigData {
37 /// How imports should be grouped into use statements. 40 /// How imports should be grouped into use statements.
@@ -309,6 +312,37 @@ impl LensConfig {
309 } 312 }
310} 313}
311 314
315#[derive(Clone, Debug, PartialEq, Eq)]
316pub struct HoverActionsConfig {
317 pub implementations: bool,
318 pub references: bool,
319 pub run: bool,
320 pub debug: bool,
321 pub goto_type_def: bool,
322}
323
324impl HoverActionsConfig {
325 pub const NO_ACTIONS: Self = Self {
326 implementations: false,
327 references: false,
328 run: false,
329 debug: false,
330 goto_type_def: false,
331 };
332
333 pub fn any(&self) -> bool {
334 self.implementations || self.references || self.runnable() || self.goto_type_def
335 }
336
337 pub fn none(&self) -> bool {
338 !self.any()
339 }
340
341 pub fn runnable(&self) -> bool {
342 self.run || self.debug
343 }
344}
345
312#[derive(Debug, Clone)] 346#[derive(Debug, Clone)]
313pub struct FilesConfig { 347pub struct FilesConfig {
314 pub watcher: FilesWatcher, 348 pub watcher: FilesWatcher,
@@ -527,7 +561,7 @@ impl Config {
527 pub fn code_action_group(&self) -> bool { 561 pub fn code_action_group(&self) -> bool {
528 self.experimental("codeActionGroup") 562 self.experimental("codeActionGroup")
529 } 563 }
530 pub fn hover_actions(&self) -> bool { 564 pub fn experimental_hover_actions(&self) -> bool {
531 self.experimental("hoverActions") 565 self.experimental("hoverActions")
532 } 566 }
533 pub fn server_status_notification(&self) -> bool { 567 pub fn server_status_notification(&self) -> bool {
@@ -727,17 +761,21 @@ impl Config {
727 refs: self.data.lens_enable && self.data.lens_references, 761 refs: self.data.lens_enable && self.data.lens_references,
728 } 762 }
729 } 763 }
730 pub fn highlighting_strings(&self) -> bool { 764 pub fn hover_actions(&self) -> HoverActionsConfig {
731 self.data.highlighting_strings 765 HoverActionsConfig {
732 }
733 pub fn hover(&self) -> HoverConfig {
734 HoverConfig {
735 implementations: self.data.hoverActions_enable 766 implementations: self.data.hoverActions_enable
736 && self.data.hoverActions_implementations, 767 && self.data.hoverActions_implementations,
737 references: self.data.hoverActions_enable && self.data.hoverActions_references, 768 references: self.data.hoverActions_enable && self.data.hoverActions_references,
738 run: self.data.hoverActions_enable && self.data.hoverActions_run, 769 run: self.data.hoverActions_enable && self.data.hoverActions_run,
739 debug: self.data.hoverActions_enable && self.data.hoverActions_debug, 770 debug: self.data.hoverActions_enable && self.data.hoverActions_debug,
740 goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, 771 goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef,
772 }
773 }
774 pub fn highlighting_strings(&self) -> bool {
775 self.data.highlighting_strings
776 }
777 pub fn hover(&self) -> HoverConfig {
778 HoverConfig {
741 links_in_hover: self.data.hover_linksInHover, 779 links_in_hover: self.data.hover_linksInHover,
742 markdown: try_or!( 780 markdown: try_or!(
743 self.caps 781 self.caps
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index eff1e6c93..dcead5f5c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -861,13 +861,7 @@ pub(crate) fn handle_hover(
861) -> Result<Option<lsp_ext::Hover>> { 861) -> Result<Option<lsp_ext::Hover>> {
862 let _p = profile::span("handle_hover"); 862 let _p = profile::span("handle_hover");
863 let position = from_proto::file_position(&snap, params.text_document_position_params)?; 863 let position = from_proto::file_position(&snap, params.text_document_position_params)?;
864 let hover_config = snap.config.hover(); 864 let info = match snap.analysis.hover(position, &snap.config.hover())? {
865 let info = match snap.analysis.hover(
866 position,
867 hover_config.links_in_hover,
868 hover_config.documentation,
869 hover_config.markdown,
870 )? {
871 None => return Ok(None), 865 None => return Ok(None),
872 Some(info) => info, 866 Some(info) => info,
873 }; 867 };
@@ -1487,7 +1481,7 @@ fn show_impl_command_link(
1487 snap: &GlobalStateSnapshot, 1481 snap: &GlobalStateSnapshot,
1488 position: &FilePosition, 1482 position: &FilePosition,
1489) -> Option<lsp_ext::CommandLinkGroup> { 1483) -> Option<lsp_ext::CommandLinkGroup> {
1490 if snap.config.hover().implementations { 1484 if snap.config.hover_actions().implementations {
1491 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { 1485 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
1492 let uri = to_proto::url(snap, position.file_id); 1486 let uri = to_proto::url(snap, position.file_id);
1493 let line_index = snap.file_line_index(position.file_id).ok()?; 1487 let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1513,7 +1507,7 @@ fn show_ref_command_link(
1513 snap: &GlobalStateSnapshot, 1507 snap: &GlobalStateSnapshot,
1514 position: &FilePosition, 1508 position: &FilePosition,
1515) -> Option<lsp_ext::CommandLinkGroup> { 1509) -> Option<lsp_ext::CommandLinkGroup> {
1516 if snap.config.hover().references { 1510 if snap.config.hover_actions().references {
1517 if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { 1511 if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
1518 let uri = to_proto::url(snap, position.file_id); 1512 let uri = to_proto::url(snap, position.file_id);
1519 let line_index = snap.file_line_index(position.file_id).ok()?; 1513 let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -1544,8 +1538,8 @@ fn runnable_action_links(
1544 runnable: Runnable, 1538 runnable: Runnable,
1545) -> Option<lsp_ext::CommandLinkGroup> { 1539) -> Option<lsp_ext::CommandLinkGroup> {
1546 let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?; 1540 let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
1547 let hover_config = snap.config.hover(); 1541 let hover_actions_config = snap.config.hover_actions();
1548 if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { 1542 if !hover_actions_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) {
1549 return None; 1543 return None;
1550 } 1544 }
1551 1545
@@ -1553,12 +1547,12 @@ fn runnable_action_links(
1553 to_proto::runnable(snap, runnable).ok().map(|r| { 1547 to_proto::runnable(snap, runnable).ok().map(|r| {
1554 let mut group = lsp_ext::CommandLinkGroup::default(); 1548 let mut group = lsp_ext::CommandLinkGroup::default();
1555 1549
1556 if hover_config.run { 1550 if hover_actions_config.run {
1557 let run_command = to_proto::command::run_single(&r, action.run_title); 1551 let run_command = to_proto::command::run_single(&r, action.run_title);
1558 group.commands.push(to_command_link(run_command, r.label.clone())); 1552 group.commands.push(to_command_link(run_command, r.label.clone()));
1559 } 1553 }
1560 1554
1561 if hover_config.debug { 1555 if hover_actions_config.debug {
1562 let dbg_command = to_proto::command::debug_single(&r); 1556 let dbg_command = to_proto::command::debug_single(&r);
1563 group.commands.push(to_command_link(dbg_command, r.label)); 1557 group.commands.push(to_command_link(dbg_command, r.label));
1564 } 1558 }
@@ -1571,7 +1565,7 @@ fn goto_type_action_links(
1571 snap: &GlobalStateSnapshot, 1565 snap: &GlobalStateSnapshot,
1572 nav_targets: &[HoverGotoTypeData], 1566 nav_targets: &[HoverGotoTypeData],
1573) -> Option<lsp_ext::CommandLinkGroup> { 1567) -> Option<lsp_ext::CommandLinkGroup> {
1574 if !snap.config.hover().goto_type_def || nav_targets.is_empty() { 1568 if !snap.config.hover_actions().goto_type_def || nav_targets.is_empty() {
1575 return None; 1569 return None;
1576 } 1570 }
1577 1571
@@ -1591,7 +1585,7 @@ fn prepare_hover_actions(
1591 snap: &GlobalStateSnapshot, 1585 snap: &GlobalStateSnapshot,
1592 actions: &[HoverAction], 1586 actions: &[HoverAction],
1593) -> Vec<lsp_ext::CommandLinkGroup> { 1587) -> Vec<lsp_ext::CommandLinkGroup> {
1594 if snap.config.hover().no_actions() || !snap.config.hover_actions() { 1588 if snap.config.hover_actions().none() || !snap.config.experimental_hover_actions() {
1595 return Vec::new(); 1589 return Vec::new();
1596 } 1590 }
1597 1591