Make documentation on hover configurable

This commit is contained in:
Lukas Wirth 2021-06-14 15:25:10 +02:00
parent 388a91c8a8
commit a93d166f0f
6 changed files with 125 additions and 113 deletions

View File

@ -1,8 +1,5 @@
use either::Either; use either::Either;
use hir::{ use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay};
AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module,
ModuleDef, Semantics,
};
use ide_db::{ use ide_db::{
base_db::SourceDatabase, base_db::SourceDatabase,
defs::{Definition, NameClass, NameRefClass}, defs::{Definition, NameClass, NameRefClass},
@ -40,6 +37,7 @@ pub struct HoverConfig {
pub goto_type_def: bool, pub goto_type_def: bool,
pub links_in_hover: bool, pub links_in_hover: bool,
pub markdown: bool, pub markdown: bool,
pub documentation: bool,
} }
impl HoverConfig { impl HoverConfig {
@ -51,14 +49,15 @@ impl HoverConfig {
goto_type_def: false, goto_type_def: false,
links_in_hover: true, links_in_hover: true,
markdown: true, markdown: true,
documentation: true,
}; };
pub fn any(&self) -> bool { pub fn any_actions(&self) -> bool {
self.implementations || self.references || self.runnable() || self.goto_type_def self.implementations || self.references || self.runnable() || self.goto_type_def
} }
pub fn none(&self) -> bool { pub fn no_actions(&self) -> bool {
!self.any() !self.any_actions()
} }
pub fn runnable(&self) -> bool { pub fn runnable(&self) -> bool {
@ -97,9 +96,10 @@ pub(crate) fn hover(
db: &RootDatabase, db: &RootDatabase,
position: FilePosition, position: FilePosition,
links_in_hover: bool, links_in_hover: bool,
documentation: bool,
markdown: bool, markdown: bool,
) -> Option<RangeInfo<HoverResult>> { ) -> Option<RangeInfo<HoverResult>> {
let sema = Semantics::new(db); let sema = hir::Semantics::new(db);
let file = sema.parse(position.file_id).syntax().clone(); let file = sema.parse(position.file_id).syntax().clone();
let token = pick_best(file.token_at_offset(position.offset))?; let token = pick_best(file.token_at_offset(position.offset))?;
let token = sema.descend_into_macros(token); let token = sema.descend_into_macros(token);
@ -131,7 +131,7 @@ pub(crate) fn hover(
let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
let (idl_range, link, ns) = let (idl_range, link, ns) =
extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| {
let InFile { file_id, value: range } = doc_mapping.map(range)?; let hir::InFile { file_id, value: range } = doc_mapping.map(range)?;
if file_id == position.file_id.into() && range.contains(position.offset) { if file_id == position.file_id.into() && range.contains(position.offset) {
Some((range, link, ns)) Some((range, link, ns))
} else { } else {
@ -151,12 +151,14 @@ pub(crate) fn hover(
if let Some(definition) = definition { if let Some(definition) = definition {
let famous_defs = match &definition { let famous_defs = match &definition {
Definition::ModuleDef(ModuleDef::BuiltinType(_)) => { Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => {
Some(FamousDefs(&sema, sema.scope(&node).krate())) Some(FamousDefs(&sema, sema.scope(&node).krate()))
} }
_ => None, _ => None,
}; };
if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref()) { 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); res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown);
if let Some(action) = show_implementations_action(db, definition) { if let Some(action) = show_implementations_action(db, definition) {
res.actions.push(action); res.actions.push(action);
@ -261,8 +263,10 @@ fn to_action(nav_target: NavigationTarget) -> HoverAction {
} }
let adt = match def { let adt = match def {
Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), Definition::ModuleDef(hir::ModuleDef::Trait(it)) => {
Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), return it.try_to_nav(db).map(to_action)
}
Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it),
Definition::SelfType(it) => it.self_ty(db).as_adt(), Definition::SelfType(it) => it.self_ty(db).as_adt(),
_ => None, _ => None,
}?; }?;
@ -271,25 +275,27 @@ fn to_action(nav_target: NavigationTarget) -> HoverAction {
fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
match def { match def {
Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| { Definition::ModuleDef(hir::ModuleDef::Function(it)) => {
it.try_to_nav(db).map(|nav_target| {
HoverAction::Reference(FilePosition { HoverAction::Reference(FilePosition {
file_id: nav_target.file_id, file_id: nav_target.file_id,
offset: nav_target.focus_or_full_range().start(), offset: nav_target.focus_or_full_range().start(),
}) })
}), })
}
_ => None, _ => None,
} }
} }
fn runnable_action( fn runnable_action(
sema: &Semantics<RootDatabase>, sema: &hir::Semantics<RootDatabase>,
def: Definition, def: Definition,
file_id: FileId, file_id: FileId,
) -> Option<HoverAction> { ) -> Option<HoverAction> {
match def { match def {
Definition::ModuleDef(it) => match it { Definition::ModuleDef(it) => match it {
ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
ModuleDef::Function(func) => { hir::ModuleDef::Function(func) => {
let src = func.source(sema.db)?; let src = func.source(sema.db)?;
if src.file_id != file_id.into() { if src.file_id != file_id.into() {
cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
@ -306,19 +312,19 @@ fn runnable_action(
} }
fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
let mut targets: Vec<ModuleDef> = Vec::new(); let mut targets: Vec<hir::ModuleDef> = Vec::new();
let mut push_new_def = |item: ModuleDef| { let mut push_new_def = |item: hir::ModuleDef| {
if !targets.contains(&item) { if !targets.contains(&item) {
targets.push(item); targets.push(item);
} }
}; };
if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def {
it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
} else { } else {
let ty = match def { let ty = match def {
Definition::Local(it) => it.ty(db), Definition::Local(it) => it.ty(db),
Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
_ => return None, _ => return None,
}; };
@ -348,13 +354,7 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
Some(HoverAction::GoToType(targets)) Some(HoverAction::GoToType(targets))
} }
fn hover_markup( fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
docs: Option<String>,
desc: Option<String>,
mod_path: Option<String>,
) -> Option<Markup> {
match desc {
Some(desc) => {
let mut buf = String::new(); let mut buf = String::new();
if let Some(mod_path) = mod_path { if let Some(mod_path) = mod_path {
@ -368,9 +368,6 @@ fn hover_markup(
format_to!(buf, "\n___\n\n{}", doc); format_to!(buf, "\n___\n\n{}", doc);
} }
Some(buf.into()) Some(buf.into())
}
None => docs.map(Markup::from),
}
} }
fn process_markup( fn process_markup(
@ -396,11 +393,11 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
Definition::Field(f) => Some(f.parent_def(db).name(db)), Definition::Field(f) => Some(f.parent_def(db).name(db)),
Definition::Local(l) => l.parent(db).name(db), Definition::Local(l) => l.parent(db).name(db),
Definition::ModuleDef(md) => match md { Definition::ModuleDef(md) => match md {
ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
AssocItemContainer::Trait(t) => Some(t.name(db)), hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
}, },
ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
_ => None, _ => None,
}, },
_ => None, _ => None,
@ -408,7 +405,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
.map(|name| name.to_string()) .map(|name| name.to_string())
} }
fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String { fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
let crate_name = let crate_name =
db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
let module_path = module let module_path = module
@ -420,6 +417,9 @@ fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) ->
} }
fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
if let Definition::GenericParam(_) = def {
return None;
}
def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
} }
@ -427,60 +427,53 @@ fn hover_for_definition(
db: &RootDatabase, db: &RootDatabase,
def: Definition, def: Definition,
famous_defs: Option<&FamousDefs>, famous_defs: Option<&FamousDefs>,
documentation: bool,
) -> Option<Markup> { ) -> Option<Markup> {
let mod_path = definition_mod_path(db, &def); let mod_path = definition_mod_path(db, &def);
return match def { let (label, docs) = match def {
Definition::Macro(it) => match &it.source(db)?.value { Definition::Macro(it) => match &it.source(db)?.value {
Either::Left(mac) => { Either::Left(mac) => {
let label = macro_label(mac); let label = macro_label(mac);
from_def_source_labeled(db, it, Some(label), mod_path) (label, it.attrs(db).docs())
} }
Either::Right(_) => { Either::Right(_) => {
// FIXME // FIXME
None return None;
} }
}, },
Definition::Field(def) => from_hir_fmt(db, def, mod_path), Definition::Field(def) => label_and_docs(db, def),
Definition::ModuleDef(it) => match it { Definition::ModuleDef(it) => match it {
ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Module(it) => label_and_docs(db, it),
ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Function(it) => label_and_docs(db, it),
ModuleDef::Adt(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Adt(it) => label_and_docs(db, it),
ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Variant(it) => label_and_docs(db, it),
ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Const(it) => label_and_docs(db, it),
ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Static(it) => label_and_docs(db, it),
ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::Trait(it) => label_and_docs(db, it),
ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it),
ModuleDef::BuiltinType(it) => famous_defs hir::ModuleDef::BuiltinType(it) => {
return famous_defs
.and_then(|fd| hover_for_builtin(fd, it)) .and_then(|fd| hover_for_builtin(fd, it))
.or_else(|| Some(Markup::fenced_block(&it.name()))), .or_else(|| Some(Markup::fenced_block(&it.name())))
},
Definition::Local(it) => hover_for_local(it, db),
Definition::SelfType(impl_def) => {
impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path))
} }
Definition::GenericParam(it) => from_hir_fmt(db, it, None), },
Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), Definition::Local(it) => return hover_for_local(it, db),
Definition::SelfType(impl_def) => {
impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
}
Definition::GenericParam(it) => label_and_docs(db, it),
Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
}; };
fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path);
fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
where where
D: HasAttrs + HirDisplay, D: HasAttrs + HirDisplay,
{ {
let label = def.display(db).to_string(); let label = def.display(db).to_string();
from_def_source_labeled(db, def, Some(label), mod_path) let docs = def.attrs(db).docs();
} (label, docs)
fn from_def_source_labeled<D>(
db: &RootDatabase,
def: D,
short_label: Option<String>,
mod_path: Option<String>,
) -> Option<Markup>
where
D: HasAttrs,
{
let docs = def.attrs(db).docs().map(Into::into);
hover_markup(docs, short_label, mod_path)
} }
} }
@ -504,11 +497,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
} }
Either::Right(_) => format!("{}self: {}", is_mut, ty), Either::Right(_) => format!("{}self: {}", is_mut, ty),
}; };
hover_markup(None, Some(desc), None) hover_markup(None, desc, None)
} }
fn hover_for_keyword( fn hover_for_keyword(
sema: &Semantics<RootDatabase>, sema: &hir::Semantics<RootDatabase>,
links_in_hover: bool, links_in_hover: bool,
markdown: bool, markdown: bool,
token: &SyntaxToken, token: &SyntaxToken,
@ -524,7 +517,7 @@ fn hover_for_keyword(
let markup = process_markup( let markup = process_markup(
sema.db, sema.db,
Definition::ModuleDef(doc_owner.into()), Definition::ModuleDef(doc_owner.into()),
&hover_markup(Some(docs.into()), Some(token.text().into()), None)?, &hover_markup(Some(docs.into()), token.text().into(), None)?,
links_in_hover, links_in_hover,
markdown, markdown,
); );
@ -536,7 +529,7 @@ fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Opt
let primitive_mod = format!("prim_{}", builtin.name()); let primitive_mod = format!("prim_{}", builtin.name());
let doc_owner = find_std_module(famous_defs, &primitive_mod)?; let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
let docs = doc_owner.attrs(famous_defs.0.db).docs()?; let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
hover_markup(Some(docs.into()), Some(builtin.name().to_string()), None) hover_markup(Some(docs.into()), builtin.name().to_string(), None)
} }
fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> {
@ -572,12 +565,12 @@ mod tests {
fn check_hover_no_result(ra_fixture: &str) { fn check_hover_no_result(ra_fixture: &str) {
let (analysis, position) = fixture::position(ra_fixture); let (analysis, position) = fixture::position(ra_fixture);
assert!(analysis.hover(position, true, true).unwrap().is_none()); assert!(analysis.hover(position, true, true, true).unwrap().is_none());
} }
fn check(ra_fixture: &str, expect: Expect) { fn check(ra_fixture: &str, expect: Expect) {
let (analysis, position) = fixture::position(ra_fixture); let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, true, true).unwrap().unwrap(); let hover = analysis.hover(position, true, true, true).unwrap().unwrap();
let content = analysis.db.file_text(position.file_id); let content = analysis.db.file_text(position.file_id);
let hovered_element = &content[hover.range]; let hovered_element = &content[hover.range];
@ -588,7 +581,7 @@ fn check(ra_fixture: &str, expect: Expect) {
fn check_hover_no_links(ra_fixture: &str, expect: Expect) { fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
let (analysis, position) = fixture::position(ra_fixture); let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, false, true).unwrap().unwrap(); let hover = analysis.hover(position, false, true, true).unwrap().unwrap();
let content = analysis.db.file_text(position.file_id); let content = analysis.db.file_text(position.file_id);
let hovered_element = &content[hover.range]; let hovered_element = &content[hover.range];
@ -599,7 +592,7 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
let (analysis, position) = fixture::position(ra_fixture); let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, true, false).unwrap().unwrap(); let hover = analysis.hover(position, true, true, false).unwrap().unwrap();
let content = analysis.db.file_text(position.file_id); let content = analysis.db.file_text(position.file_id);
let hovered_element = &content[hover.range]; let hovered_element = &content[hover.range];
@ -610,7 +603,7 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
fn check_actions(ra_fixture: &str, expect: Expect) { fn check_actions(ra_fixture: &str, expect: Expect) {
let (analysis, position) = fixture::position(ra_fixture); let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, true, true).unwrap().unwrap(); let hover = analysis.hover(position, true, true, true).unwrap().unwrap();
expect.assert_debug_eq(&hover.info.actions) expect.assert_debug_eq(&hover.info.actions)
} }

View File

@ -407,9 +407,10 @@ pub fn hover(
&self, &self,
position: FilePosition, position: FilePosition,
links_in_hover: bool, links_in_hover: bool,
documentation: bool,
markdown: bool, markdown: bool,
) -> Cancellable<Option<RangeInfo<HoverResult>>> { ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
self.with_db(|db| hover::hover(db, position, links_in_hover, markdown)) self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown))
} }
/// Return URL(s) for the documentation of the symbol under the cursor. /// Return URL(s) for the documentation of the symbol under the cursor.

View File

@ -141,6 +141,11 @@ struct ConfigData {
/// their contents. /// their contents.
highlighting_strings: bool = "true", highlighting_strings: bool = "true",
/// Whether to show documentation on hover.
hover_documentation: bool = "true",
/// Use markdown syntax for links in hover.
hover_linksInHover: bool = "true",
/// Whether to show `Debug` action. Only applies when /// Whether to show `Debug` action. Only applies when
/// `#rust-analyzer.hoverActions.enable#` is set. /// `#rust-analyzer.hoverActions.enable#` is set.
hoverActions_debug: bool = "true", hoverActions_debug: bool = "true",
@ -158,8 +163,6 @@ struct ConfigData {
/// Whether to show `Run` action. Only applies when /// Whether to show `Run` action. Only applies when
/// `#rust-analyzer.hoverActions.enable#` is set. /// `#rust-analyzer.hoverActions.enable#` is set.
hoverActions_run: bool = "true", hoverActions_run: bool = "true",
/// Use markdown syntax for links in hover.
hoverActions_linksInHover: bool = "true",
/// Whether to show inlay type hints for method chains. /// Whether to show inlay type hints for method chains.
inlayHints_chainingHints: bool = "true", inlayHints_chainingHints: bool = "true",
@ -726,7 +729,7 @@ pub fn hover(&self) -> HoverConfig {
run: self.data.hoverActions_enable && self.data.hoverActions_run, run: self.data.hoverActions_enable && self.data.hoverActions_run,
debug: self.data.hoverActions_enable && self.data.hoverActions_debug, debug: self.data.hoverActions_enable && self.data.hoverActions_debug,
goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef,
links_in_hover: self.data.hoverActions_linksInHover, links_in_hover: self.data.hover_linksInHover,
markdown: try_or!( markdown: try_or!(
self.caps self.caps
.text_document .text_document
@ -739,6 +742,7 @@ pub fn hover(&self) -> HoverConfig {
&[] &[]
) )
.contains(&MarkupKind::Markdown), .contains(&MarkupKind::Markdown),
documentation: self.data.hover_documentation,
} }
} }

View File

@ -862,8 +862,12 @@ pub(crate) fn handle_hover(
let _p = profile::span("handle_hover"); let _p = profile::span("handle_hover");
let position = from_proto::file_position(&snap, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let hover_config = snap.config.hover(); let hover_config = snap.config.hover();
let info = let info = match snap.analysis.hover(
match snap.analysis.hover(position, hover_config.links_in_hover, hover_config.markdown)? { position,
hover_config.links_in_hover,
hover_config.documentation,
hover_config.markdown,
)? {
None => return Ok(None), None => return Ok(None),
Some(info) => info, Some(info) => info,
}; };
@ -1587,7 +1591,7 @@ fn prepare_hover_actions(
snap: &GlobalStateSnapshot, snap: &GlobalStateSnapshot,
actions: &[HoverAction], actions: &[HoverAction],
) -> Vec<lsp_ext::CommandLinkGroup> { ) -> Vec<lsp_ext::CommandLinkGroup> {
if snap.config.hover().none() || !snap.config.hover_actions() { if snap.config.hover().no_actions() || !snap.config.hover_actions() {
return Vec::new(); return Vec::new();
} }

View File

@ -205,6 +205,16 @@ In some editors (e.g. vscode) semantic tokens override other highlighting gramma
By disabling semantic tokens for strings, other grammars can be used to highlight By disabling semantic tokens for strings, other grammars can be used to highlight
their contents. their contents.
-- --
[[rust-analyzer.hover.documentation]]rust-analyzer.hover.documentation (default: `true`)::
+
--
Whether to show documentation on hover.
--
[[rust-analyzer.hover.linksInHover]]rust-analyzer.hover.linksInHover (default: `true`)::
+
--
Use markdown syntax for links in hover.
--
[[rust-analyzer.hoverActions.debug]]rust-analyzer.hoverActions.debug (default: `true`):: [[rust-analyzer.hoverActions.debug]]rust-analyzer.hoverActions.debug (default: `true`)::
+ +
-- --
@ -240,11 +250,6 @@ Whether to show `References` action. Only applies when
Whether to show `Run` action. Only applies when Whether to show `Run` action. Only applies when
`#rust-analyzer.hoverActions.enable#` is set. `#rust-analyzer.hoverActions.enable#` is set.
-- --
[[rust-analyzer.hoverActions.linksInHover]]rust-analyzer.hoverActions.linksInHover (default: `true`)::
+
--
Use markdown syntax for links in hover.
--
[[rust-analyzer.inlayHints.chainingHints]]rust-analyzer.inlayHints.chainingHints (default: `true`):: [[rust-analyzer.inlayHints.chainingHints]]rust-analyzer.inlayHints.chainingHints (default: `true`)::
+ +
-- --

View File

@ -640,6 +640,16 @@
"default": true, "default": true,
"type": "boolean" "type": "boolean"
}, },
"rust-analyzer.hover.documentation": {
"markdownDescription": "Whether to show documentation on hover.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hover.linksInHover": {
"markdownDescription": "Use markdown syntax for links in hover.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hoverActions.debug": { "rust-analyzer.hoverActions.debug": {
"markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.", "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": true, "default": true,
@ -670,11 +680,6 @@
"default": true, "default": true,
"type": "boolean" "type": "boolean"
}, },
"rust-analyzer.hoverActions.linksInHover": {
"markdownDescription": "Use markdown syntax for links in hover.",
"default": true,
"type": "boolean"
},
"rust-analyzer.inlayHints.chainingHints": { "rust-analyzer.inlayHints.chainingHints": {
"markdownDescription": "Whether to show inlay type hints for method chains.", "markdownDescription": "Whether to show inlay type hints for method chains.",
"default": true, "default": true,