diff options
author | Lukas Wirth <[email protected]> | 2021-06-14 14:25:10 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-06-14 14:25:10 +0100 |
commit | a93d166f0fecb748d8cb04aab7f5406bf6308c2d (patch) | |
tree | ceda7b8ea1bf1c2949c75191e4faa41693f8f19e /crates | |
parent | 388a91c8a8d542f7a8e0ddff879cce4d4c2b20ae (diff) |
Make documentation on hover configurable
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/hover.rs | 179 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 16 |
4 files changed, 105 insertions, 103 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c08516805..23f2b48b4 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); |
@@ -261,8 +263,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
261 | } | 263 | } |
262 | 264 | ||
263 | let adt = match def { | 265 | let adt = match def { |
264 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), | 266 | Definition::ModuleDef(hir::ModuleDef::Trait(it)) => { |
265 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), | 267 | return it.try_to_nav(db).map(to_action) |
268 | } | ||
269 | Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it), | ||
266 | Definition::SelfType(it) => it.self_ty(db).as_adt(), | 270 | Definition::SelfType(it) => it.self_ty(db).as_adt(), |
267 | _ => None, | 271 | _ => None, |
268 | }?; | 272 | }?; |
@@ -271,25 +275,27 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
271 | 275 | ||
272 | fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 276 | fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
273 | match def { | 277 | match def { |
274 | Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| { | 278 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => { |
275 | HoverAction::Reference(FilePosition { | 279 | it.try_to_nav(db).map(|nav_target| { |
276 | file_id: nav_target.file_id, | 280 | HoverAction::Reference(FilePosition { |
277 | offset: nav_target.focus_or_full_range().start(), | 281 | file_id: nav_target.file_id, |
282 | offset: nav_target.focus_or_full_range().start(), | ||
283 | }) | ||
278 | }) | 284 | }) |
279 | }), | 285 | } |
280 | _ => None, | 286 | _ => None, |
281 | } | 287 | } |
282 | } | 288 | } |
283 | 289 | ||
284 | fn runnable_action( | 290 | fn runnable_action( |
285 | sema: &Semantics<RootDatabase>, | 291 | sema: &hir::Semantics<RootDatabase>, |
286 | def: Definition, | 292 | def: Definition, |
287 | file_id: FileId, | 293 | file_id: FileId, |
288 | ) -> Option<HoverAction> { | 294 | ) -> Option<HoverAction> { |
289 | match def { | 295 | match def { |
290 | Definition::ModuleDef(it) => match it { | 296 | Definition::ModuleDef(it) => match it { |
291 | ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), | 297 | hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), |
292 | ModuleDef::Function(func) => { | 298 | hir::ModuleDef::Function(func) => { |
293 | let src = func.source(sema.db)?; | 299 | let src = func.source(sema.db)?; |
294 | if src.file_id != file_id.into() { | 300 | if src.file_id != file_id.into() { |
295 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 301 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
@@ -306,19 +312,19 @@ fn runnable_action( | |||
306 | } | 312 | } |
307 | 313 | ||
308 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 314 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
309 | let mut targets: Vec<ModuleDef> = Vec::new(); | 315 | let mut targets: Vec<hir::ModuleDef> = Vec::new(); |
310 | let mut push_new_def = |item: ModuleDef| { | 316 | let mut push_new_def = |item: hir::ModuleDef| { |
311 | if !targets.contains(&item) { | 317 | if !targets.contains(&item) { |
312 | targets.push(item); | 318 | targets.push(item); |
313 | } | 319 | } |
314 | }; | 320 | }; |
315 | 321 | ||
316 | if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { | 322 | if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def { |
317 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | 323 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); |
318 | } else { | 324 | } else { |
319 | let ty = match def { | 325 | let ty = match def { |
320 | Definition::Local(it) => it.ty(db), | 326 | Definition::Local(it) => it.ty(db), |
321 | Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), | 327 | Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), |
322 | _ => return None, | 328 | _ => return None, |
323 | }; | 329 | }; |
324 | 330 | ||
@@ -348,29 +354,20 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
348 | Some(HoverAction::GoToType(targets)) | 354 | Some(HoverAction::GoToType(targets)) |
349 | } | 355 | } |
350 | 356 | ||
351 | fn hover_markup( | 357 | fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> { |
352 | docs: Option<String>, | 358 | 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 | 359 | ||
367 | if let Some(doc) = docs { | 360 | if let Some(mod_path) = mod_path { |
368 | format_to!(buf, "\n___\n\n{}", doc); | 361 | if !mod_path.is_empty() { |
369 | } | 362 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); |
370 | Some(buf.into()) | ||
371 | } | 363 | } |
372 | None => docs.map(Markup::from), | ||
373 | } | 364 | } |
365 | format_to!(buf, "```rust\n{}\n```", desc); | ||
366 | |||
367 | if let Some(doc) = docs { | ||
368 | format_to!(buf, "\n___\n\n{}", doc); | ||
369 | } | ||
370 | Some(buf.into()) | ||
374 | } | 371 | } |
375 | 372 | ||
376 | fn process_markup( | 373 | fn process_markup( |
@@ -396,11 +393,11 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
396 | Definition::Field(f) => Some(f.parent_def(db).name(db)), | 393 | Definition::Field(f) => Some(f.parent_def(db).name(db)), |
397 | Definition::Local(l) => l.parent(db).name(db), | 394 | Definition::Local(l) => l.parent(db).name(db), |
398 | Definition::ModuleDef(md) => match md { | 395 | Definition::ModuleDef(md) => match md { |
399 | ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { | 396 | hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { |
400 | AssocItemContainer::Trait(t) => Some(t.name(db)), | 397 | hir::AssocItemContainer::Trait(t) => Some(t.name(db)), |
401 | AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), | 398 | hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), |
402 | }, | 399 | }, |
403 | ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), | 400 | hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), |
404 | _ => None, | 401 | _ => None, |
405 | }, | 402 | }, |
406 | _ => None, | 403 | _ => None, |
@@ -408,7 +405,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
408 | .map(|name| name.to_string()) | 405 | .map(|name| name.to_string()) |
409 | } | 406 | } |
410 | 407 | ||
411 | fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String { | 408 | fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String { |
412 | let crate_name = | 409 | let crate_name = |
413 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); | 410 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); |
414 | let module_path = module | 411 | let module_path = module |
@@ -420,6 +417,9 @@ fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> | |||
420 | } | 417 | } |
421 | 418 | ||
422 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | 419 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { |
420 | if let Definition::GenericParam(_) = def { | ||
421 | return None; | ||
422 | } | ||
423 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) | 423 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) |
424 | } | 424 | } |
425 | 425 | ||
@@ -427,60 +427,53 @@ fn hover_for_definition( | |||
427 | db: &RootDatabase, | 427 | db: &RootDatabase, |
428 | def: Definition, | 428 | def: Definition, |
429 | famous_defs: Option<&FamousDefs>, | 429 | famous_defs: Option<&FamousDefs>, |
430 | documentation: bool, | ||
430 | ) -> Option<Markup> { | 431 | ) -> Option<Markup> { |
431 | let mod_path = definition_mod_path(db, &def); | 432 | let mod_path = definition_mod_path(db, &def); |
432 | return match def { | 433 | let (label, docs) = match def { |
433 | Definition::Macro(it) => match &it.source(db)?.value { | 434 | Definition::Macro(it) => match &it.source(db)?.value { |
434 | Either::Left(mac) => { | 435 | Either::Left(mac) => { |
435 | let label = macro_label(mac); | 436 | let label = macro_label(mac); |
436 | from_def_source_labeled(db, it, Some(label), mod_path) | 437 | (label, it.attrs(db).docs()) |
437 | } | 438 | } |
438 | Either::Right(_) => { | 439 | Either::Right(_) => { |
439 | // FIXME | 440 | // FIXME |
440 | None | 441 | return None; |
441 | } | 442 | } |
442 | }, | 443 | }, |
443 | Definition::Field(def) => from_hir_fmt(db, def, mod_path), | 444 | Definition::Field(def) => label_and_docs(db, def), |
444 | Definition::ModuleDef(it) => match it { | 445 | Definition::ModuleDef(it) => match it { |
445 | ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), | 446 | hir::ModuleDef::Module(it) => label_and_docs(db, it), |
446 | ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), | 447 | hir::ModuleDef::Function(it) => label_and_docs(db, it), |
447 | ModuleDef::Adt(it) => from_hir_fmt(db, it, mod_path), | 448 | hir::ModuleDef::Adt(it) => label_and_docs(db, it), |
448 | ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), | 449 | hir::ModuleDef::Variant(it) => label_and_docs(db, it), |
449 | ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), | 450 | hir::ModuleDef::Const(it) => label_and_docs(db, it), |
450 | ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), | 451 | hir::ModuleDef::Static(it) => label_and_docs(db, it), |
451 | ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), | 452 | hir::ModuleDef::Trait(it) => label_and_docs(db, it), |
452 | ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), | 453 | hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it), |
453 | ModuleDef::BuiltinType(it) => famous_defs | 454 | hir::ModuleDef::BuiltinType(it) => { |
454 | .and_then(|fd| hover_for_builtin(fd, it)) | 455 | return famous_defs |
455 | .or_else(|| Some(Markup::fenced_block(&it.name()))), | 456 | .and_then(|fd| hover_for_builtin(fd, it)) |
457 | .or_else(|| Some(Markup::fenced_block(&it.name()))) | ||
458 | } | ||
456 | }, | 459 | }, |
457 | Definition::Local(it) => hover_for_local(it, db), | 460 | Definition::Local(it) => return hover_for_local(it, db), |
458 | Definition::SelfType(impl_def) => { | 461 | Definition::SelfType(impl_def) => { |
459 | impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) | 462 | impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? |
460 | } | 463 | } |
461 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | 464 | Definition::GenericParam(it) => label_and_docs(db, it), |
462 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 465 | Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), |
463 | }; | 466 | }; |
464 | 467 | ||
465 | fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 468 | return hover_markup(docs.filter(|_| documentation).map(Into::into), label, mod_path); |
469 | |||
470 | fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>) | ||
466 | where | 471 | where |
467 | D: HasAttrs + HirDisplay, | 472 | D: HasAttrs + HirDisplay, |
468 | { | 473 | { |
469 | let label = def.display(db).to_string(); | 474 | let label = def.display(db).to_string(); |
470 | from_def_source_labeled(db, def, Some(label), mod_path) | 475 | let docs = def.attrs(db).docs(); |
471 | } | 476 | (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 | } | 477 | } |
485 | } | 478 | } |
486 | 479 | ||
@@ -504,11 +497,11 @@ fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> { | |||
504 | } | 497 | } |
505 | Either::Right(_) => format!("{}self: {}", is_mut, ty), | 498 | Either::Right(_) => format!("{}self: {}", is_mut, ty), |
506 | }; | 499 | }; |
507 | hover_markup(None, Some(desc), None) | 500 | hover_markup(None, desc, None) |
508 | } | 501 | } |
509 | 502 | ||
510 | fn hover_for_keyword( | 503 | fn hover_for_keyword( |
511 | sema: &Semantics<RootDatabase>, | 504 | sema: &hir::Semantics<RootDatabase>, |
512 | links_in_hover: bool, | 505 | links_in_hover: bool, |
513 | markdown: bool, | 506 | markdown: bool, |
514 | token: &SyntaxToken, | 507 | token: &SyntaxToken, |
@@ -524,7 +517,7 @@ fn hover_for_keyword( | |||
524 | let markup = process_markup( | 517 | let markup = process_markup( |
525 | sema.db, | 518 | sema.db, |
526 | Definition::ModuleDef(doc_owner.into()), | 519 | Definition::ModuleDef(doc_owner.into()), |
527 | &hover_markup(Some(docs.into()), Some(token.text().into()), None)?, | 520 | &hover_markup(Some(docs.into()), token.text().into(), None)?, |
528 | links_in_hover, | 521 | links_in_hover, |
529 | markdown, | 522 | markdown, |
530 | ); | 523 | ); |
@@ -536,7 +529,7 @@ fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Opt | |||
536 | let primitive_mod = format!("prim_{}", builtin.name()); | 529 | let primitive_mod = format!("prim_{}", builtin.name()); |
537 | let doc_owner = find_std_module(famous_defs, &primitive_mod)?; | 530 | let doc_owner = find_std_module(famous_defs, &primitive_mod)?; |
538 | let docs = doc_owner.attrs(famous_defs.0.db).docs()?; | 531 | let docs = doc_owner.attrs(famous_defs.0.db).docs()?; |
539 | hover_markup(Some(docs.into()), Some(builtin.name().to_string()), None) | 532 | hover_markup(Some(docs.into()), builtin.name().to_string(), None) |
540 | } | 533 | } |
541 | 534 | ||
542 | fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { | 535 | fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> { |
@@ -572,12 +565,12 @@ mod tests { | |||
572 | 565 | ||
573 | fn check_hover_no_result(ra_fixture: &str) { | 566 | fn check_hover_no_result(ra_fixture: &str) { |
574 | let (analysis, position) = fixture::position(ra_fixture); | 567 | let (analysis, position) = fixture::position(ra_fixture); |
575 | assert!(analysis.hover(position, true, true).unwrap().is_none()); | 568 | assert!(analysis.hover(position, true, true, true).unwrap().is_none()); |
576 | } | 569 | } |
577 | 570 | ||
578 | fn check(ra_fixture: &str, expect: Expect) { | 571 | fn check(ra_fixture: &str, expect: Expect) { |
579 | let (analysis, position) = fixture::position(ra_fixture); | 572 | let (analysis, position) = fixture::position(ra_fixture); |
580 | let hover = analysis.hover(position, true, true).unwrap().unwrap(); | 573 | let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); |
581 | 574 | ||
582 | let content = analysis.db.file_text(position.file_id); | 575 | let content = analysis.db.file_text(position.file_id); |
583 | let hovered_element = &content[hover.range]; | 576 | let hovered_element = &content[hover.range]; |
@@ -588,7 +581,7 @@ mod tests { | |||
588 | 581 | ||
589 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { | 582 | fn check_hover_no_links(ra_fixture: &str, expect: Expect) { |
590 | let (analysis, position) = fixture::position(ra_fixture); | 583 | let (analysis, position) = fixture::position(ra_fixture); |
591 | let hover = analysis.hover(position, false, true).unwrap().unwrap(); | 584 | let hover = analysis.hover(position, false, true, true).unwrap().unwrap(); |
592 | 585 | ||
593 | let content = analysis.db.file_text(position.file_id); | 586 | let content = analysis.db.file_text(position.file_id); |
594 | let hovered_element = &content[hover.range]; | 587 | let hovered_element = &content[hover.range]; |
@@ -599,7 +592,7 @@ mod tests { | |||
599 | 592 | ||
600 | fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { | 593 | fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { |
601 | let (analysis, position) = fixture::position(ra_fixture); | 594 | let (analysis, position) = fixture::position(ra_fixture); |
602 | let hover = analysis.hover(position, true, false).unwrap().unwrap(); | 595 | let hover = analysis.hover(position, true, true, false).unwrap().unwrap(); |
603 | 596 | ||
604 | let content = analysis.db.file_text(position.file_id); | 597 | let content = analysis.db.file_text(position.file_id); |
605 | let hovered_element = &content[hover.range]; | 598 | let hovered_element = &content[hover.range]; |
@@ -610,7 +603,7 @@ mod tests { | |||
610 | 603 | ||
611 | fn check_actions(ra_fixture: &str, expect: Expect) { | 604 | fn check_actions(ra_fixture: &str, expect: Expect) { |
612 | let (analysis, position) = fixture::position(ra_fixture); | 605 | let (analysis, position) = fixture::position(ra_fixture); |
613 | let hover = analysis.hover(position, true, true).unwrap().unwrap(); | 606 | let hover = analysis.hover(position, true, true, true).unwrap().unwrap(); |
614 | expect.assert_debug_eq(&hover.info.actions) | 607 | expect.assert_debug_eq(&hover.info.actions) |
615 | } | 608 | } |
616 | 609 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 0511efae3..8d0270319 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -407,9 +407,10 @@ impl Analysis { | |||
407 | &self, | 407 | &self, |
408 | position: FilePosition, | 408 | position: FilePosition, |
409 | links_in_hover: bool, | 409 | links_in_hover: bool, |
410 | documentation: bool, | ||
410 | markdown: bool, | 411 | markdown: bool, |
411 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { | 412 | ) -> Cancellable<Option<RangeInfo<HoverResult>>> { |
412 | self.with_db(|db| hover::hover(db, position, links_in_hover, markdown)) | 413 | self.with_db(|db| hover::hover(db, position, links_in_hover, documentation, markdown)) |
413 | } | 414 | } |
414 | 415 | ||
415 | /// 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 3b20d741a..5d3deb232 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -141,6 +141,11 @@ config_data! { | |||
141 | /// their contents. | 141 | /// their contents. |
142 | highlighting_strings: bool = "true", | 142 | highlighting_strings: bool = "true", |
143 | 143 | ||
144 | /// Whether to show documentation on hover. | ||
145 | hover_documentation: bool = "true", | ||
146 | /// Use markdown syntax for links in hover. | ||
147 | hover_linksInHover: bool = "true", | ||
148 | |||
144 | /// Whether to show `Debug` action. Only applies when | 149 | /// Whether to show `Debug` action. Only applies when |
145 | /// `#rust-analyzer.hoverActions.enable#` is set. | 150 | /// `#rust-analyzer.hoverActions.enable#` is set. |
146 | hoverActions_debug: bool = "true", | 151 | hoverActions_debug: bool = "true", |
@@ -158,8 +163,6 @@ config_data! { | |||
158 | /// Whether to show `Run` action. Only applies when | 163 | /// Whether to show `Run` action. Only applies when |
159 | /// `#rust-analyzer.hoverActions.enable#` is set. | 164 | /// `#rust-analyzer.hoverActions.enable#` is set. |
160 | hoverActions_run: bool = "true", | 165 | hoverActions_run: bool = "true", |
161 | /// Use markdown syntax for links in hover. | ||
162 | hoverActions_linksInHover: bool = "true", | ||
163 | 166 | ||
164 | /// Whether to show inlay type hints for method chains. | 167 | /// Whether to show inlay type hints for method chains. |
165 | inlayHints_chainingHints: bool = "true", | 168 | inlayHints_chainingHints: bool = "true", |
@@ -726,7 +729,7 @@ impl Config { | |||
726 | run: self.data.hoverActions_enable && self.data.hoverActions_run, | 729 | run: self.data.hoverActions_enable && self.data.hoverActions_run, |
727 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, | 730 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, |
728 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, | 731 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, |
729 | links_in_hover: self.data.hoverActions_linksInHover, | 732 | links_in_hover: self.data.hover_linksInHover, |
730 | markdown: try_or!( | 733 | markdown: try_or!( |
731 | self.caps | 734 | self.caps |
732 | .text_document | 735 | .text_document |
@@ -739,6 +742,7 @@ impl Config { | |||
739 | &[] | 742 | &[] |
740 | ) | 743 | ) |
741 | .contains(&MarkupKind::Markdown), | 744 | .contains(&MarkupKind::Markdown), |
745 | documentation: self.data.hover_documentation, | ||
742 | } | 746 | } |
743 | } | 747 | } |
744 | 748 | ||
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 | ||