diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-06-21 15:15:49 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-06-21 15:15:49 +0100 |
commit | 25bf451c8426a68ecfdc3a1d1be1db9702dd41d8 (patch) | |
tree | 1d9d6c49faca0c36178d2bf5a6e20de0f88df094 | |
parent | 5567b8a63214ce9bf2d4fdd6b4a8bd9c2c3eded7 (diff) | |
parent | 43098d99ae9ee3d102ce54510d7885bae58e5ac7 (diff) |
Merge #9264
9264: feat: Make documentation on hover configurable r=Veykril a=Veykril
This also implements deprecation support for config options as this renames `hoverActions_linksInHover` to `hover_linksInHover`.
Fixes #9232
Co-authored-by: Lukas Wirth <[email protected]>
-rw-r--r-- | crates/ide/src/hover.rs | 185 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 13 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 16 | ||||
-rw-r--r-- | docs/user/generated_config.adoc | 15 | ||||
-rw-r--r-- | editors/code/package.json | 15 |
6 files changed, 132 insertions, 115 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 2e1359eef..0c1da8774 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,8 +1,5 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{ | 2 | use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay}; |
3 | AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module, | ||
4 | ModuleDef, Semantics, | ||
5 | }; | ||
6 | use ide_db::{ | 3 | use ide_db::{ |
7 | base_db::SourceDatabase, | 4 | base_db::SourceDatabase, |
8 | defs::{Definition, NameClass, NameRefClass}, | 5 | defs::{Definition, NameClass, NameRefClass}, |
@@ -40,6 +37,7 @@ pub struct HoverConfig { | |||
40 | pub goto_type_def: bool, | 37 | pub goto_type_def: bool, |
41 | pub links_in_hover: bool, | 38 | pub links_in_hover: bool, |
42 | pub markdown: bool, | 39 | pub markdown: bool, |
40 | pub documentation: bool, | ||
43 | } | 41 | } |
44 | 42 | ||
45 | impl HoverConfig { | 43 | impl HoverConfig { |
@@ -51,14 +49,15 @@ impl HoverConfig { | |||
51 | goto_type_def: false, | 49 | goto_type_def: false, |
52 | links_in_hover: true, | 50 | links_in_hover: true, |
53 | markdown: true, | 51 | markdown: true, |
52 | documentation: true, | ||
54 | }; | 53 | }; |
55 | 54 | ||
56 | pub fn any(&self) -> bool { | 55 | pub fn any_actions(&self) -> bool { |
57 | self.implementations || self.references || self.runnable() || self.goto_type_def | 56 | self.implementations || self.references || self.runnable() || self.goto_type_def |
58 | } | 57 | } |
59 | 58 | ||
60 | pub fn none(&self) -> bool { | 59 | pub fn no_actions(&self) -> bool { |
61 | !self.any() | 60 | !self.any_actions() |
62 | } | 61 | } |
63 | 62 | ||
64 | pub fn runnable(&self) -> bool { | 63 | pub fn runnable(&self) -> bool { |
@@ -97,9 +96,10 @@ pub(crate) fn hover( | |||
97 | db: &RootDatabase, | 96 | db: &RootDatabase, |
98 | position: FilePosition, | 97 | position: FilePosition, |
99 | links_in_hover: bool, | 98 | links_in_hover: bool, |
99 | documentation: bool, | ||
100 | markdown: bool, | 100 | markdown: bool, |
101 | ) -> Option<RangeInfo<HoverResult>> { | 101 | ) -> Option<RangeInfo<HoverResult>> { |
102 | let sema = Semantics::new(db); | 102 | let sema = hir::Semantics::new(db); |
103 | let file = sema.parse(position.file_id).syntax().clone(); | 103 | let file = sema.parse(position.file_id).syntax().clone(); |
104 | let token = pick_best(file.token_at_offset(position.offset))?; | 104 | let token = pick_best(file.token_at_offset(position.offset))?; |
105 | let token = sema.descend_into_macros(token); | 105 | let token = sema.descend_into_macros(token); |
@@ -131,7 +131,7 @@ pub(crate) fn hover( | |||
131 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; | 131 | let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; |
132 | let (idl_range, link, ns) = | 132 | let (idl_range, link, ns) = |
133 | extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { | 133 | extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| { |
134 | let InFile { file_id, value: range } = doc_mapping.map(range)?; | 134 | let hir::InFile { file_id, value: range } = doc_mapping.map(range)?; |
135 | if file_id == position.file_id.into() && range.contains(position.offset) { | 135 | if file_id == position.file_id.into() && range.contains(position.offset) { |
136 | Some((range, link, ns)) | 136 | Some((range, link, ns)) |
137 | } else { | 137 | } else { |
@@ -151,12 +151,14 @@ pub(crate) fn hover( | |||
151 | 151 | ||
152 | if let Some(definition) = definition { | 152 | if let Some(definition) = definition { |
153 | let famous_defs = match &definition { | 153 | let famous_defs = match &definition { |
154 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => { | 154 | Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => { |
155 | Some(FamousDefs(&sema, sema.scope(&node).krate())) | 155 | Some(FamousDefs(&sema, sema.scope(&node).krate())) |
156 | } | 156 | } |
157 | _ => None, | 157 | _ => None, |
158 | }; | 158 | }; |
159 | if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref()) { | 159 | if let Some(markup) = |
160 | hover_for_definition(db, definition, famous_defs.as_ref(), documentation) | ||
161 | { | ||
160 | res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); | 162 | res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown); |
161 | if let Some(action) = show_implementations_action(db, definition) { | 163 | if let Some(action) = show_implementations_action(db, definition) { |
162 | res.actions.push(action); | 164 | res.actions.push(action); |
@@ -179,7 +181,8 @@ pub(crate) fn hover( | |||
179 | } | 181 | } |
180 | } | 182 | } |
181 | 183 | ||
182 | if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, &token) { | 184 | if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, documentation, &token) |
185 | { | ||
183 | return res; | 186 | return res; |
184 | } | 187 | } |
185 | 188 | ||
@@ -261,8 +264,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
261 | } | 264 | } |
262 | 265 | ||
263 | let adt = match def { | 266 | let adt = match def { |
264 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 267 | Definition::ModuleDef(hir::ModuleDef::Trait(it)) => { |
265 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 268 | return it.try_to_nav(db).map(to_action) |
269 | } | ||
270 | Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it), | ||
266 | Definition::SelfType(it) => it.self_ty(db).as_adt(), | 271 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
267 | _ => None, | 272 | _ => None, |
268 | }?; | 273 | }?; |
@@ -271,25 +276,27 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
271 | 276 | ||
272 | fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 277 | fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
273 | match def { | 278 | match def { |
274 | Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| { | 279 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => { |
275 | HoverAction::Reference(FilePosition { | 280 | it.try_to_nav(db).map(|nav_target| { |
276 | file_id: nav_target.file_id, | 281 | HoverAction::Reference(FilePosition { |
277 | offset: nav_target.focus_or_full_range().start(), | 282 | file_id: nav_target.file_id, |
283 | offset: nav_target.focus_or_full_range().start(), | ||
284 | }) | ||
278 | }) | 285 | }) |
279 | }), | 286 | } |
280 | _ => None, | 287 | _ => None, |
281 | } | 288 | } |
282 | } | 289 | } |
283 | 290 | ||
284 | fn runnable_action( | 291 | fn runnable_action( |
285 | sema: &Semantics<RootDatabase>, | 292 | sema: &hir::Semantics<RootDatabase>, |
286 | def: Definition, | 293 | def: Definition, |
287 | file_id: FileId, | 294 | file_id: FileId, |
288 | ) -> Option<HoverAction> { | 295 | ) -> Option<HoverAction> { |
289 | match def { | 296 | match def { |
290 | Definition::ModuleDef(it) => match it { | 297 | Definition::ModuleDef(it) => match it { |
291 | ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), | 298 | hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), |
292 | ModuleDef::Function(func) => { | 299 | hir::ModuleDef::Function(func) => { |
293 | let src = func.source(sema.db)?; | 300 | let src = func.source(sema.db)?; |
294 | if src.file_id != file_id.into() { | 301 | if src.file_id != file_id.into() { |
295 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 302 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
@@ -306,19 +313,19 @@ fn runnable_action( | |||
306 | } | 313 | } |
307 | 314 | ||
308 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 315 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
309 | let mut targets: Vec<ModuleDef> = Vec::new(); | 316 | let mut targets: Vec<hir::ModuleDef> = Vec::new(); |
310 | let mut push_new_def = |item: ModuleDef| { | 317 | let mut push_new_def = |item: hir::ModuleDef| { |
311 | if !targets.contains(&item) { | 318 | if !targets.contains(&item) { |
312 | targets.push(item); | 319 | targets.push(item); |
313 | } | 320 | } |
314 | }; | 321 | }; |
315 | 322 | ||
316 | if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { | 323 | if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def { |
317 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | 324 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); |
318 | } else { | 325 | } else { |
319 | let ty = match def { | 326 | let ty = match def { |
320 | Definition::Local(it) => it.ty(db), | 327 | Definition::Local(it) => it.ty(db), |
321 | Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), | 328 | Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), |
322 | _ => return None, | 329 | _ => return None, |
323 | }; | 330 | }; |
324 | 331 | ||
@@ -348,29 +355,20 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
348 | Some(HoverAction::GoToType(targets)) | 355 | Some(HoverAction::GoToType(targets)) |
349 | } | 356 | } |
350 | 357 | ||
351 | fn hover_markup( | 358 | fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> { |
352 | docs: Option<String>, | 359 | let mut buf = String::new(); |
353 | desc: Option<String>, | ||
354 | mod_path: Option<String>, | ||
355 | ) -> Option<Markup> { | ||
356 | match desc { | ||
357 | Some(desc) => { | ||
358 | let mut buf = String::new(); | ||
359 | |||
360 | if let Some(mod_path) = mod_path { | ||
361 | if !mod_path.is_empty() { | ||
362 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); | ||
363 | } | ||
364 | } | ||
365 | format_to!(buf, "```rust\n{}\n```", desc); | ||
366 | 360 | ||
367 | if let Some(doc) = docs { | 361 | if let Some(mod_path) = mod_path { |
368 | format_to!(buf, "\n___\n\n{}", doc); | 362 | if !mod_path.is_empty() { |
369 | } | 363 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); |
370 | Some(buf.into()) | ||
371 | } | 364 | } |
372 | None => docs.map(Markup::from), | ||
373 | } | 365 | } |
366 | format_to!(buf, "```rust\n{}\n```", desc); | ||
367 | |||
368 | if let Some(doc) = docs { | ||
369 | format_to!(buf, "\n___\n\n{}", doc); | ||
370 | } | ||
371 | Some(buf.into()) | ||
374 | } | 372 | } |
375 | 373 | ||
376 | fn process_markup( | 374 | fn process_markup( |
@@ -396,11 +394,11 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
396 | Definition::Field(f) => Some(f.parent_def(db).name(db)), | 394 | Definition::Field(f) => Some(f.parent_def(db).name(db)), |
397 | Definition::Local(l) => l.parent(db).name(db), | 395 | Definition::Local(l) => l.parent(db).name(db), |
398 | Definition::ModuleDef(md) => match md { | 396 | Definition::ModuleDef(md) => match md { |
399 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 397 | hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
400 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 398 | hir::AssocItemContainer::Trait(t) => Some(t.name(db)), |
401 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), | 399 | hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
402 | }, | 400 | }, |
403 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 401 | hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
404 | _ => None, | 402 | _ => None, |
405 | }, | 403 | }, |
406 | _ => None, | 404 | _ => None, |
@@ -408,7 +406,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
408 | .map(|name| name.to_string()) | 406 | .map(|name| name.to_string()) |
409 | } | 407 | } |
410 | 408 | ||
411 | fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String { | 409 | fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String { |
412 | let crate_name = | 410 | let crate_name = |
413 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); | 411 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); |
414 | let module_path = module | 412 | let module_path = module |
@@ -420,6 +418,9 @@ fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> | |||
420 | } | 418 | } |
421 | 419 | ||
422 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | 420 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { |
421 | if let Definition::GenericParam(_) = def { | ||
422 | return None; | ||
423 | } | ||
423 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) | 424 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) |
424 | } | 425 | } |
425 | 426 | ||
@@ -427,60 +428,53 @@ fn hover_for_definition( | |||
427 | db: &RootDatabase, | 428 | db: &RootDatabase, |
428 | def: Definition, | 429 | def: Definition, |
429 | famous_defs: Option<&FamousDefs>, | 430 | famous_defs: Option<&FamousDefs>, |
431 | documentation: bool, | ||
430 | ) -> Option<Markup> { | 432 | ) -> Option<Markup> { |
431 | let mod_path = definition_mod_path(db, &def); | 433 | let mod_path = definition_mod_path(db, &def); |
432 | return match def { | 434 | let (label, docs) = match def { |
433 | Definition::Macro(it) => match &it.source(db)?.value { | 435 | Definition::Macro(it) => match &it.source(db)?.value { |
434 | Either::Left(mac) => { | 436 | Either::Left(mac) => { |
435 | let label = macro_label(mac); | 437 | let label = macro_label(mac); |
436 | from_def_source_labeled(db, it, Some(label), mod_path) | 438 | (label, it.attrs(db).docs()) |
437 | } | 439 | } |
438 | Either::Right(_) => { | 440 | Either::Right(_) => { |
439 | // FIXME | 441 | // FIXME |
440 | None | 442 | return None; |
441 | } | 443 | } |
442 | }, | 444 | }, |
443 | Definition::Field(def) => from_hir_fmt(db, def, mod_path), | 445 | Definition::Field(def) => label_and_docs(db, def), |
444 | Definition::ModuleDef(it) => match it { | 446 | Definition::ModuleDef(it) => match it { |
445 | ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), | 447 | hir::ModuleDef::Module(it) => label_and_docs(db, it), |
446 | ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), | 448 | hir::ModuleDef::Function(it) => label_and_docs(db, it), |
447 | ModuleDef::Adt(it) => from_hir_fmt(db, it, mod_path), | 449 | hir::ModuleDef::Adt(it) => label_and_docs(db, it), |
448 | ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), | 450 | hir::ModuleDef::Variant(it) => label_and_docs(db, it), |
449 | ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), | 451 | hir::ModuleDef::Const(it) => label_and_docs(db, it), |
450 | ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), | 452 | hir::ModuleDef::Static(it) => label_and_docs(db, it), |
451 | ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), | 453 | hir::ModuleDef::Trait(it) => label_and_docs(db, it), |
452 | ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), | 454 | hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it), |
453 | ModuleDef::BuiltinType(it) => famous_defs | 455 | hir::ModuleDef::BuiltinType(it) => { |
454 | .and_then(|fd| hover_for_builtin(fd, it)) | 456 | return famous_defs |
455 | .or_else(|| Some(Markup::fenced_block(&it.name()))), | 457 | .and_then(|fd| hover_for_builtin(fd, it)) |
458 | .or_else(|| Some(Markup::fenced_block(&it.name()))) | ||
459 | } | ||
456 | }, | 460 | }, |
457 | Definition::Local(it) => hover_for_local(it, db), | 461 | Definition::Local(it) => return hover_for_local(it, db), |
458 | Definition::SelfType(impl_def) => { | 462 | Definition::SelfType(impl_def) => { |
459 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 463 | impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? |
460 | } | 464 | } |
461 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 465 | Definition::GenericParam(it) => label_and_docs(db, it), |
462 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 466 | Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), |
463 | }; | 467 | }; |
464 | 468 | ||
465 | fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 469 | return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); |
470 | |||
471 | fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>) | ||
466 | where | 472 | where |
467 | D: HasAttrs + HirDisplay, | 473 | D: HasAttrs + HirDisplay, |
468 | { | 474 | { |
469 | let label = def.display(db).to_string(); | 475 | let label = def.display(db).to_string(); |
470 | from_def_source_labeled(db, def, Some(label), mod_path) | 476 | let docs = def.attrs(db).docs(); |
471 | } | 477 | (label, docs) |
472 | |||
473 | fn from_def_source_labeled<D>( | ||
474 | db: &RootDatabase, | ||
475 | def: D, | ||
476 | short_label: Option<String>, | ||
477 | mod_path: Option<String>, | ||
478 | ) -> Option<Markup> | ||
479 | where | ||
480 | D: HasAttrs, | ||
481 | { | ||
482 | let docs = def.attrs(db).docs().map(Into::into); | ||
483 | hover_markup(docs, short_label, mod_path) | ||
484 | } | 478 | } |
485 | } | 479 | } |
486 | 480 | ||
@@ -504,16 +498,17 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> { | |||
504 | } | 498 | } |
505 | Either::Right(_) => format!("{}self: {}", is_mut, ty), | 499 | Either::Right(_) => format!("{}self: {}", is_mut, ty), |
506 | }; | 500 | }; |
507 | hover_markup(None, Some(desc), None) | 501 | hover_markup(None, desc, None) |
508 | } | 502 | } |
509 | 503 | ||
510 | fn hover_for_keyword( | 504 | fn hover_for_keyword( |
511 | sema: &Semantics<RootDatabase>, | 505 | sema: &hir::Semantics<RootDatabase>, |
512 | links_in_hover: bool, | 506 | links_in_hover: bool, |
513 | markdown: bool, | 507 | markdown: bool, |
508 | documentation: bool, | ||
514 | token: &SyntaxToken, | 509 | token: &SyntaxToken, |
515 | ) -> Option<RangeInfo<HoverResult>> { | 510 | ) -> Option<RangeInfo<HoverResult>> { |
516 | if !token.kind().is_keyword() { | 511 | if !token.kind().is_keyword() || !documentation { |
517 | return None; | 512 | return None; |
518 | } | 513 | } |
519 | let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); | 514 | let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate()); |
@@ -524,7 +519,7 @@ fn hover_for_keyword( | |||
524 | let markup = process_markup( | 519 | let markup = process_markup( |
525 | sema.db, | 520 | sema.db, |
526 | Definition::ModuleDef(doc_owner.into()), | 521 | Definition::ModuleDef(doc_owner.into()), |
527 | &hover_markup(Some(docs.into()), Some(token.text().into()), None)?, | 522 | &hover_markup(Some(docs.into()), token.text().into(), None)?, |
528 | links_in_hover, | 523 | links_in_hover, |
529 | markdown, | 524 | markdown, |
530 | ); | 525 | ); |
@@ -536,7 +531,7 @@ fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Opt | |||
536 | let primitive_mod = format!("prim_{}", builtin.name()); | 531 | let primitive_mod = format!("prim_{}", builtin.name()); |
537 | let doc_owner = find_std_module(famous_defs, &primitive_mod)?; | 532 | let doc_owner = find_std_module(famous_defs, &primitive_mod)?; |
538 | let docs = doc_owner.attrs(famous_defs.0.db).docs()?; | 533 | let docs = doc_owner.attrs(famous_defs.0.db).docs()?; |
539 | hover_markup(Some(docs.into()), Some(builtin.name().to_string()), None) | 534 | hover_markup(Some(docs.into()), builtin.name().to_string(), None) |
540 | } | 535 | } |
541 | 536 | ||
542 | fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { | 537 | fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { |
@@ -570,12 +565,12 @@ mod tests { | |||
570 | 565 | ||
571 | fn check_hover_no_result(ra_fixture: &str) { | 566 | fn check_hover_no_result(ra_fixture: &str) { |
572 | let (analysis, position) = fixture::position(ra_fixture); | 567 | let (analysis, position) = fixture::position(ra_fixture); |
573 | assert!(analysis.hover(position, true, true).unwrap().is_none()); | 568 | assert!(analysis.hover(position, true, true, true).unwrap().is_none()); |
574 | } | 569 | } |
575 | 570 | ||
576 | fn check(ra_fixture: &str, expect: Expect) { | 571 | fn check(ra_fixture: &str, expect: Expect) { |
577 | let (analysis, position) = fixture::position(ra_fixture); | 572 | let (analysis, position) = fixture::position(ra_fixture); |
578 | let hover = analysis.hover(position, true, true).unwrap().unwrap(); | 573 | let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); |
579 | 574 | ||
580 | let content = analysis.db.file_text(position.file_id); | 575 | let content = analysis.db.file_text(position.file_id); |
581 | let hovered_element = &content[hover.range]; | 576 | let hovered_element = &content[hover.range]; |
@@ -586,7 +581,7 @@ mod tests { | |||
586 | 581 | ||
587 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { | 582 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { |
588 | let (analysis, position) = fixture::position(ra_fixture); | 583 | let (analysis, position) = fixture::position(ra_fixture); |
589 | let hover = analysis.hover(position, false, true).unwrap().unwrap(); | 584 | let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); |
590 | 585 | ||
591 | let content = analysis.db.file_text(position.file_id); | 586 | let content = analysis.db.file_text(position.file_id); |
592 | let hovered_element = &content[hover.range]; | 587 | let hovered_element = &content[hover.range]; |
@@ -597,7 +592,7 @@ mod tests { | |||
597 | 592 | ||
598 | fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { | 593 | fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { |
599 | let (analysis, position) = fixture::position(ra_fixture); | 594 | let (analysis, position) = fixture::position(ra_fixture); |
600 | let hover = analysis.hover(position, true, false).unwrap().unwrap(); | 595 | let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); |
601 | 596 | ||
602 | let content = analysis.db.file_text(position.file_id); | 597 | let content = analysis.db.file_text(position.file_id); |
603 | let hovered_element = &content[hover.range]; | 598 | let hovered_element = &content[hover.range]; |
@@ -608,7 +603,7 @@ mod tests { | |||
608 | 603 | ||
609 | fn check_actions(ra_fixture: &str, expect: Expect) { | 604 | fn check_actions(ra_fixture: &str, expect: Expect) { |
610 | let (analysis, position) = fixture::position(ra_fixture); | 605 | let (analysis, position) = fixture::position(ra_fixture); |
611 | let hover = analysis.hover(position, true, true).unwrap().unwrap(); | 606 | let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); |
612 | expect.assert_debug_eq(&hover.info.actions) | 607 | expect.assert_debug_eq(&hover.info.actions) |
613 | } | 608 | } |
614 | 609 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 4bd073cc3..3798f32cc 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -408,9 +408,10 @@ impl Analysis { | |||
408 | &self, | 408 | &self, |
409 | position: FilePosition, | 409 | position: FilePosition, |
410 | links_in_hover: bool, | 410 | links_in_hover: bool, |
411 | documentation: bool, | ||
411 | markdown: bool, | 412 | markdown: bool, |
412 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { | 413 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { |
413 | self.with_db(|db| hover::hover(db, position, links_in_hover, markdown)) | 414 | self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) |
414 | } | 415 | } |
415 | 416 | ||
416 | /// Return URL(s) for the documentation of the symbol under the cursor. | 417 | /// 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 7e0276c10..3aeca8839 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -146,6 +146,12 @@ config_data! { | |||
146 | /// their contents. | 146 | /// their contents. |
147 | highlighting_strings: bool = "true", | 147 | highlighting_strings: bool = "true", |
148 | 148 | ||
149 | /// Whether to show documentation on hover. | ||
150 | hover_documentation: bool = "true", | ||
151 | /// Use markdown syntax for links in hover. | ||
152 | hover_linksInHover | | ||
153 | hoverActions_linksInHover: bool = "true", | ||
154 | |||
149 | /// Whether to show `Debug` action. Only applies when | 155 | /// Whether to show `Debug` action. Only applies when |
150 | /// `#rust-analyzer.hoverActions.enable#` is set. | 156 | /// `#rust-analyzer.hoverActions.enable#` is set. |
151 | hoverActions_debug: bool = "true", | 157 | hoverActions_debug: bool = "true", |
@@ -163,8 +169,6 @@ config_data! { | |||
163 | /// Whether to show `Run` action. Only applies when | 169 | /// Whether to show `Run` action. Only applies when |
164 | /// `#rust-analyzer.hoverActions.enable#` is set. | 170 | /// `#rust-analyzer.hoverActions.enable#` is set. |
165 | hoverActions_run: bool = "true", | 171 | hoverActions_run: bool = "true", |
166 | /// Use markdown syntax for links in hover. | ||
167 | hoverActions_linksInHover: bool = "true", | ||
168 | 172 | ||
169 | /// Whether to show inlay type hints for method chains. | 173 | /// Whether to show inlay type hints for method chains. |
170 | inlayHints_chainingHints: bool = "true", | 174 | inlayHints_chainingHints: bool = "true", |
@@ -734,7 +738,7 @@ impl Config { | |||
734 | run: self.data.hoverActions_enable && self.data.hoverActions_run, | 738 | run: self.data.hoverActions_enable && self.data.hoverActions_run, |
735 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, | 739 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, |
736 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, | 740 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, |
737 | links_in_hover: self.data.hoverActions_linksInHover, | 741 | links_in_hover: self.data.hover_linksInHover, |
738 | markdown: try_or!( | 742 | markdown: try_or!( |
739 | self.caps | 743 | self.caps |
740 | .text_document | 744 | .text_document |
@@ -747,6 +751,7 @@ impl Config { | |||
747 | &[] | 751 | &[] |
748 | ) | 752 | ) |
749 | .contains(&MarkupKind::Markdown), | 753 | .contains(&MarkupKind::Markdown), |
754 | documentation: self.data.hover_documentation, | ||
750 | } | 755 | } |
751 | } | 756 | } |
752 | 757 | ||
@@ -856,6 +861,7 @@ macro_rules! _config_data { | |||
856 | $({ | 861 | $({ |
857 | let field = stringify!($field); | 862 | let field = stringify!($field); |
858 | let ty = stringify!($ty); | 863 | let ty = stringify!($ty); |
864 | |||
859 | (field, ty, &[$($doc),*], $default) | 865 | (field, ty, &[$($doc),*], $default) |
860 | },)* | 866 | },)* |
861 | ]) | 867 | ]) |
@@ -867,6 +873,7 @@ macro_rules! _config_data { | |||
867 | $({ | 873 | $({ |
868 | let field = stringify!($field); | 874 | let field = stringify!($field); |
869 | let ty = stringify!($ty); | 875 | let ty = stringify!($ty); |
876 | |||
870 | (field, ty, &[$($doc),*], $default) | 877 | (field, ty, &[$($doc),*], $default) |
871 | },)* | 878 | },)* |
872 | ]) | 879 | ]) |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index ccf66294f..eff1e6c93 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -862,11 +862,15 @@ pub(crate) fn handle_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 hover_config = snap.config.hover(); |
865 | let info = | 865 | let info = match snap.analysis.hover( |
866 | match snap.analysis.hover(position, hover_config.links_in_hover, hover_config.markdown)? { | 866 | position, |
867 | None => return Ok(None), | 867 | hover_config.links_in_hover, |
868 | Some(info) => info, | 868 | hover_config.documentation, |
869 | }; | 869 | hover_config.markdown, |
870 | )? { | ||
871 | None => return Ok(None), | ||
872 | Some(info) => info, | ||
873 | }; | ||
870 | let line_index = snap.file_line_index(position.file_id)?; | 874 | let line_index = snap.file_line_index(position.file_id)?; |
871 | let range = to_proto::range(&line_index, info.range); | 875 | let range = to_proto::range(&line_index, info.range); |
872 | let hover = lsp_ext::Hover { | 876 | let hover = lsp_ext::Hover { |
@@ -1587,7 +1591,7 @@ fn prepare_hover_actions( | |||
1587 | snap: &GlobalStateSnapshot, | 1591 | snap: &GlobalStateSnapshot, |
1588 | actions: &[HoverAction], | 1592 | actions: &[HoverAction], |
1589 | ) -> Vec<lsp_ext::CommandLinkGroup> { | 1593 | ) -> Vec<lsp_ext::CommandLinkGroup> { |
1590 | if snap.config.hover().none() || !snap.config.hover_actions() { | 1594 | if snap.config.hover().no_actions() || !snap.config.hover_actions() { |
1591 | return Vec::new(); | 1595 | return Vec::new(); |
1592 | } | 1596 | } |
1593 | 1597 | ||
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 58cb46974..cc7fdd38f 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -215,6 +215,16 @@ In some editors (e.g. vscode) semantic tokens override other highlighting gramma | |||
215 | By disabling semantic tokens for strings, other grammars can be used to highlight | 215 | By disabling semantic tokens for strings, other grammars can be used to highlight |
216 | their contents. | 216 | their contents. |
217 | -- | 217 | -- |
218 | [[rust-analyzer.hover.documentation]]rust-analyzer.hover.documentation (default: `true`):: | ||
219 | + | ||
220 | -- | ||
221 | Whether to show documentation on hover. | ||
222 | -- | ||
223 | [[rust-analyzer.hover.linksInHover]]rust-analyzer.hover.linksInHover (default: `true`):: | ||
224 | + | ||
225 | -- | ||
226 | Use markdown syntax for links in hover. | ||
227 | -- | ||
218 | [[rust-analyzer.hoverActions.debug]]rust-analyzer.hoverActions.debug (default: `true`):: | 228 | [[rust-analyzer.hoverActions.debug]]rust-analyzer.hoverActions.debug (default: `true`):: |
219 | + | 229 | + |
220 | -- | 230 | -- |
@@ -250,11 +260,6 @@ Whether to show `References` action. Only applies when | |||
250 | Whether to show `Run` action. Only applies when | 260 | Whether to show `Run` action. Only applies when |
251 | `#rust-analyzer.hoverActions.enable#` is set. | 261 | `#rust-analyzer.hoverActions.enable#` is set. |
252 | -- | 262 | -- |
253 | [[rust-analyzer.hoverActions.linksInHover]]rust-analyzer.hoverActions.linksInHover (default: `true`):: | ||
254 | + | ||
255 | -- | ||
256 | Use markdown syntax for links in hover. | ||
257 | -- | ||
258 | [[rust-analyzer.inlayHints.chainingHints]]rust-analyzer.inlayHints.chainingHints (default: `true`):: | 263 | [[rust-analyzer.inlayHints.chainingHints]]rust-analyzer.inlayHints.chainingHints (default: `true`):: |
259 | + | 264 | + |
260 | -- | 265 | -- |
diff --git a/editors/code/package.json b/editors/code/package.json index b20a39a95..666016ae4 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -655,6 +655,16 @@ | |||
655 | "default": true, | 655 | "default": true, |
656 | "type": "boolean" | 656 | "type": "boolean" |
657 | }, | 657 | }, |
658 | "rust-analyzer.hover.documentation": { | ||
659 | "markdownDescription": "Whether to show documentation on hover.", | ||
660 | "default": true, | ||
661 | "type": "boolean" | ||
662 | }, | ||
663 | "rust-analyzer.hover.linksInHover": { | ||
664 | "markdownDescription": "Use markdown syntax for links in hover.", | ||
665 | "default": true, | ||
666 | "type": "boolean" | ||
667 | }, | ||
658 | "rust-analyzer.hoverActions.debug": { | 668 | "rust-analyzer.hoverActions.debug": { |
659 | "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.", | 669 | "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.", |
660 | "default": true, | 670 | "default": true, |
@@ -685,11 +695,6 @@ | |||
685 | "default": true, | 695 | "default": true, |
686 | "type": "boolean" | 696 | "type": "boolean" |
687 | }, | 697 | }, |
688 | "rust-analyzer.hoverActions.linksInHover": { | ||
689 | "markdownDescription": "Use markdown syntax for links in hover.", | ||
690 | "default": true, | ||
691 | "type": "boolean" | ||
692 | }, | ||
693 | "rust-analyzer.inlayHints.chainingHints": { | 698 | "rust-analyzer.inlayHints.chainingHints": { |
694 | "markdownDescription": "Whether to show inlay type hints for method chains.", | 699 | "markdownDescription": "Whether to show inlay type hints for method chains.", |
695 | "default": true, | 700 | "default": true, |