From 99c95b8fa15f2d9239625c19463f552c84ad99a2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 21 Jun 2021 21:41:06 +0200 Subject: Split hover actions config into its own config struct --- crates/ide/src/hover.rs | 111 +++++++++++++++++------------------ crates/ide/src/lib.rs | 6 +- crates/rust-analyzer/src/config.rs | 50 ++++++++++++++-- crates/rust-analyzer/src/handlers.rs | 24 +++----- 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 @@ use either::Either; -use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay}; +use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics}; use ide_db::{ base_db::SourceDatabase, defs::{Definition, NameClass, NameRefClass}, @@ -30,41 +30,11 @@ use crate::{ #[derive(Clone, Debug, PartialEq, Eq)] pub struct HoverConfig { - pub implementations: bool, - pub references: bool, - pub run: bool, - pub debug: bool, - pub goto_type_def: bool, pub links_in_hover: bool, pub markdown: bool, pub documentation: bool, } -impl HoverConfig { - pub const NO_ACTIONS: Self = Self { - implementations: false, - references: false, - run: false, - debug: false, - goto_type_def: false, - links_in_hover: true, - markdown: true, - documentation: true, - }; - - pub fn any_actions(&self) -> bool { - self.implementations || self.references || self.runnable() || self.goto_type_def - } - - pub fn no_actions(&self) -> bool { - !self.any_actions() - } - - pub fn runnable(&self) -> bool { - self.run || self.debug - } -} - #[derive(Debug, Clone)] pub enum HoverAction { Runnable(Runnable), @@ -95,9 +65,7 @@ pub struct HoverResult { pub(crate) fn hover( db: &RootDatabase, position: FilePosition, - links_in_hover: bool, - documentation: bool, - markdown: bool, + config: &HoverConfig, ) -> Option> { let sema = hir::Semantics::new(db); let file = sema.parse(position.file_id).syntax().clone(); @@ -156,10 +124,14 @@ pub(crate) fn hover( } _ => None, }; - if let Some(markup) = - hover_for_definition(db, definition, famous_defs.as_ref(), documentation) - { - res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); + if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) { + res.markup = process_markup( + sema.db, + definition, + &markup, + config.links_in_hover, + config.markdown, + ); if let Some(action) = show_implementations_action(db, definition) { res.actions.push(action); } @@ -181,8 +153,7 @@ pub(crate) fn hover( } } - if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token) - { + if let res @ Some(_) = hover_for_keyword(&sema, config, &token) { return res; } @@ -201,7 +172,7 @@ pub(crate) fn hover( } }; - res.markup = if markdown { + res.markup = if config.markdown { Markup::fenced_block(&ty.display(db)) } else { ty.display(db).to_string().into() @@ -428,7 +399,7 @@ fn hover_for_definition( db: &RootDatabase, def: Definition, famous_defs: Option<&FamousDefs>, - documentation: bool, + config: &HoverConfig, ) -> Option { let mod_path = definition_mod_path(db, &def); let (label, docs) = match def { @@ -466,7 +437,7 @@ fn hover_for_definition( Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), }; - return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); + return hover_markup(docs.filter(|_| config.documentation).map(Into::into), label, mod_path); fn label_and_docs(db: &RootDatabase, def: D) -> (String, Option) where @@ -502,13 +473,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option { } fn hover_for_keyword( - sema: &hir::Semantics, - links_in_hover: bool, - markdown: bool, - documentation: bool, + sema: &Semantics, + config: &HoverConfig, token: &SyntaxToken, ) -> Option> { - if !token.kind().is_keyword() || !documentation { + if !token.kind().is_keyword() || !config.documentation { return None; } let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); @@ -520,8 +489,8 @@ fn hover_for_keyword( sema.db, Definition::ModuleDef(doc_owner.into()), &hover_markup(Some(docs.into()), token.text().into(), None)?, - links_in_hover, - markdown, + config.links_in_hover, + config.markdown, ); Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() })) } @@ -561,16 +530,28 @@ mod tests { use expect_test::{expect, Expect}; use ide_db::base_db::FileLoader; - use crate::fixture; + use crate::{fixture, HoverConfig}; fn check_hover_no_result(ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); - assert!(analysis.hover(position, true, true, true).unwrap().is_none()); + assert!(analysis + .hover( + position, + &HoverConfig { links_in_hover: true, markdown: true, documentation: true } + ) + .unwrap() + .is_none()); } fn check(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); + let hover = analysis + .hover( + position, + &HoverConfig { links_in_hover: true, markdown: true, documentation: true }, + ) + .unwrap() + .unwrap(); let content = analysis.db.file_text(position.file_id); let hovered_element = &content[hover.range]; @@ -581,7 +562,13 @@ mod tests { fn check_hover_no_links(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); + let hover = analysis + .hover( + position, + &HoverConfig { links_in_hover: false, markdown: true, documentation: true }, + ) + .unwrap() + .unwrap(); let content = analysis.db.file_text(position.file_id); let hovered_element = &content[hover.range]; @@ -592,7 +579,13 @@ mod tests { fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); + let hover = analysis + .hover( + position, + &HoverConfig { links_in_hover: true, markdown: false, documentation: true }, + ) + .unwrap() + .unwrap(); let content = analysis.db.file_text(position.file_id); let hovered_element = &content[hover.range]; @@ -603,7 +596,13 @@ mod tests { fn check_actions(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); + let hover = analysis + .hover( + position, + &HoverConfig { links_in_hover: true, markdown: true, documentation: true }, + ) + .unwrap() + .unwrap(); expect.assert_debug_eq(&hover.info.actions) } 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 { pub fn hover( &self, position: FilePosition, - links_in_hover: bool, - documentation: bool, - markdown: bool, + config: &HoverConfig, ) -> Cancellable>> { - self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) + self.with_db(|db| hover::hover(db, position, config)) } /// 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::{ // // However, editor specific config, which the server doesn't know about, should // be specified directly in `package.json`. +// +// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep +// parsing the old name. config_data! { struct ConfigData { /// How imports should be grouped into use statements. @@ -309,6 +312,37 @@ impl LensConfig { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct HoverActionsConfig { + pub implementations: bool, + pub references: bool, + pub run: bool, + pub debug: bool, + pub goto_type_def: bool, +} + +impl HoverActionsConfig { + pub const NO_ACTIONS: Self = Self { + implementations: false, + references: false, + run: false, + debug: false, + goto_type_def: false, + }; + + pub fn any(&self) -> bool { + self.implementations || self.references || self.runnable() || self.goto_type_def + } + + pub fn none(&self) -> bool { + !self.any() + } + + pub fn runnable(&self) -> bool { + self.run || self.debug + } +} + #[derive(Debug, Clone)] pub struct FilesConfig { pub watcher: FilesWatcher, @@ -527,7 +561,7 @@ impl Config { pub fn code_action_group(&self) -> bool { self.experimental("codeActionGroup") } - pub fn hover_actions(&self) -> bool { + pub fn experimental_hover_actions(&self) -> bool { self.experimental("hoverActions") } pub fn server_status_notification(&self) -> bool { @@ -727,17 +761,21 @@ impl Config { refs: self.data.lens_enable && self.data.lens_references, } } - pub fn highlighting_strings(&self) -> bool { - self.data.highlighting_strings - } - pub fn hover(&self) -> HoverConfig { - HoverConfig { + pub fn hover_actions(&self) -> HoverActionsConfig { + HoverActionsConfig { implementations: self.data.hoverActions_enable && self.data.hoverActions_implementations, references: self.data.hoverActions_enable && self.data.hoverActions_references, run: self.data.hoverActions_enable && self.data.hoverActions_run, debug: self.data.hoverActions_enable && self.data.hoverActions_debug, goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, + } + } + pub fn highlighting_strings(&self) -> bool { + self.data.highlighting_strings + } + pub fn hover(&self) -> HoverConfig { + HoverConfig { links_in_hover: self.data.hover_linksInHover, markdown: try_or!( 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( ) -> Result> { let _p = profile::span("handle_hover"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let hover_config = snap.config.hover(); - let info = match snap.analysis.hover( - position, - hover_config.links_in_hover, - hover_config.documentation, - hover_config.markdown, - )? { + let info = match snap.analysis.hover(position, &snap.config.hover())? { None => return Ok(None), Some(info) => info, }; @@ -1487,7 +1481,7 @@ fn show_impl_command_link( snap: &GlobalStateSnapshot, position: &FilePosition, ) -> Option { - if snap.config.hover().implementations { + if snap.config.hover_actions().implementations { if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { let uri = to_proto::url(snap, position.file_id); let line_index = snap.file_line_index(position.file_id).ok()?; @@ -1513,7 +1507,7 @@ fn show_ref_command_link( snap: &GlobalStateSnapshot, position: &FilePosition, ) -> Option { - if snap.config.hover().references { + if snap.config.hover_actions().references { if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { let uri = to_proto::url(snap, position.file_id); let line_index = snap.file_line_index(position.file_id).ok()?; @@ -1544,8 +1538,8 @@ fn runnable_action_links( runnable: Runnable, ) -> Option { let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?; - let hover_config = snap.config.hover(); - if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { + let hover_actions_config = snap.config.hover_actions(); + if !hover_actions_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { return None; } @@ -1553,12 +1547,12 @@ fn runnable_action_links( to_proto::runnable(snap, runnable).ok().map(|r| { let mut group = lsp_ext::CommandLinkGroup::default(); - if hover_config.run { + if hover_actions_config.run { let run_command = to_proto::command::run_single(&r, action.run_title); group.commands.push(to_command_link(run_command, r.label.clone())); } - if hover_config.debug { + if hover_actions_config.debug { let dbg_command = to_proto::command::debug_single(&r); group.commands.push(to_command_link(dbg_command, r.label)); } @@ -1571,7 +1565,7 @@ fn goto_type_action_links( snap: &GlobalStateSnapshot, nav_targets: &[HoverGotoTypeData], ) -> Option { - if !snap.config.hover().goto_type_def || nav_targets.is_empty() { + if !snap.config.hover_actions().goto_type_def || nav_targets.is_empty() { return None; } @@ -1591,7 +1585,7 @@ fn prepare_hover_actions( snap: &GlobalStateSnapshot, actions: &[HoverAction], ) -> Vec { - if snap.config.hover().no_actions() || !snap.config.hover_actions() { + if snap.config.hover_actions().none() || !snap.config.experimental_hover_actions() { return Vec::new(); } -- cgit v1.2.3 From 65d683df367ac1d2b8c421c61b76c9e2c26b8704 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 21 Jun 2021 21:57:01 +0200 Subject: Collapse documentation and markdown config settings into an enum --- crates/ide/src/hover.rs | 70 +++++++++++++++++++++++++------------- crates/ide/src/lib.rs | 2 +- crates/rust-analyzer/src/config.rs | 37 ++++++++++++-------- 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 35050899d..c6d6bb74a 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -31,8 +31,19 @@ use crate::{ #[derive(Clone, Debug, PartialEq, Eq)] pub struct HoverConfig { pub links_in_hover: bool, - pub markdown: bool, - pub documentation: bool, + pub documentation: Option, +} + +impl HoverConfig { + fn markdown(&self) -> bool { + matches!(self.documentation, Some(HoverDocFormat::Markdown)) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum HoverDocFormat { + Markdown, + PlainText, } #[derive(Debug, Clone)] @@ -125,13 +136,7 @@ pub(crate) fn hover( _ => None, }; if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) { - res.markup = process_markup( - sema.db, - definition, - &markup, - config.links_in_hover, - config.markdown, - ); + res.markup = process_markup(sema.db, definition, &markup, config); if let Some(action) = show_implementations_action(db, definition) { res.actions.push(action); } @@ -172,7 +177,7 @@ pub(crate) fn hover( } }; - res.markup = if config.markdown { + res.markup = if config.markdown() { Markup::fenced_block(&ty.display(db)) } else { ty.display(db).to_string().into() @@ -346,13 +351,12 @@ fn process_markup( db: &RootDatabase, def: Definition, markup: &Markup, - links_in_hover: bool, - markdown: bool, + config: &HoverConfig, ) -> Markup { let markup = markup.as_str(); - let markup = if !markdown { + let markup = if !config.markdown() { remove_markdown(markup) - } else if links_in_hover { + } else if config.links_in_hover { rewrite_links(db, markup, &def) } else { remove_links(markup) @@ -437,7 +441,11 @@ fn hover_for_definition( Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), }; - return hover_markup(docs.filter(|_| config.documentation).map(Into::into), label, mod_path); + return hover_markup( + docs.filter(|_| config.documentation.is_some()).map(Into::into), + label, + mod_path, + ); fn label_and_docs(db: &RootDatabase, def: D) -> (String, Option) where @@ -477,7 +485,7 @@ fn hover_for_keyword( config: &HoverConfig, token: &SyntaxToken, ) -> Option> { - if !token.kind().is_keyword() || !config.documentation { + if !token.kind().is_keyword() || !config.documentation.is_some() { return None; } let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); @@ -489,8 +497,7 @@ fn hover_for_keyword( sema.db, Definition::ModuleDef(doc_owner.into()), &hover_markup(Some(docs.into()), token.text().into(), None)?, - config.links_in_hover, - config.markdown, + config, ); Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() })) } @@ -530,14 +537,17 @@ mod tests { use expect_test::{expect, Expect}; use ide_db::base_db::FileLoader; - use crate::{fixture, HoverConfig}; + use crate::{fixture, hover::HoverDocFormat, HoverConfig}; fn check_hover_no_result(ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); assert!(analysis .hover( position, - &HoverConfig { links_in_hover: true, markdown: true, documentation: true } + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown) + } ) .unwrap() .is_none()); @@ -548,7 +558,10 @@ mod tests { let hover = analysis .hover( position, - &HoverConfig { links_in_hover: true, markdown: true, documentation: true }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + }, ) .unwrap() .unwrap(); @@ -565,7 +578,10 @@ mod tests { let hover = analysis .hover( position, - &HoverConfig { links_in_hover: false, markdown: true, documentation: true }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + }, ) .unwrap() .unwrap(); @@ -582,7 +598,10 @@ mod tests { let hover = analysis .hover( position, - &HoverConfig { links_in_hover: true, markdown: false, documentation: true }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::PlainText), + }, ) .unwrap() .unwrap(); @@ -599,7 +618,10 @@ mod tests { let hover = analysis .hover( position, - &HoverConfig { links_in_hover: true, markdown: true, documentation: true }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + }, ) .unwrap() .unwrap(); diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index e24a32218..b978e36af 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -75,7 +75,7 @@ pub use crate::{ expand_macro::ExpandedMacro, file_structure::{StructureNode, StructureNodeKind}, folding_ranges::{Fold, FoldKind}, - hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, + hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, markup::Markup, move_item::Direction, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index de70959a5..b9aa6f0aa 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -10,7 +10,10 @@ use std::{ffi::OsString, iter, path::PathBuf}; use flycheck::FlycheckConfig; -use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; +use ide::{ + AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, HoverDocFormat, + InlayHintsConfig, +}; use ide_db::helpers::{ insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, SnippetCap, @@ -777,19 +780,25 @@ impl Config { pub fn hover(&self) -> HoverConfig { HoverConfig { links_in_hover: self.data.hover_linksInHover, - markdown: try_or!( - self.caps - .text_document - .as_ref()? - .hover - .as_ref()? - .content_format - .as_ref()? - .as_slice(), - &[] - ) - .contains(&MarkupKind::Markdown), - documentation: self.data.hover_documentation, + documentation: self.data.hover_documentation.then(|| { + let is_markdown = try_or!( + self.caps + .text_document + .as_ref()? + .hover + .as_ref()? + .content_format + .as_ref()? + .as_slice(), + &[] + ) + .contains(&MarkupKind::Markdown); + if is_markdown { + HoverDocFormat::Markdown + } else { + HoverDocFormat::PlainText + } + }), } } -- cgit v1.2.3