diff options
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 148 |
1 files changed, 93 insertions, 55 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 0da10a08e..34fc36a1f 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -146,7 +146,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
146 | } | 146 | } |
147 | } { | 147 | } { |
148 | let range = sema.original_range(&node).range; | 148 | let range = sema.original_range(&node).range; |
149 | let text = hover_text_from_name_kind(db, name_kind.clone()).map(|text| rewrite_links(db, &text, &name_kind).unwrap_or(text)); | 149 | let text = hover_text_from_name_kind(db, name_kind.clone()); |
150 | let text = text.map(|text| rewrite_links(db, &text, &name_kind).unwrap_or(text)); | ||
150 | res.extend(text); | 151 | res.extend(text); |
151 | 152 | ||
152 | if !res.is_empty() { | 153 | if !res.is_empty() { |
@@ -405,8 +406,8 @@ fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> | |||
405 | Err(_) => { | 406 | Err(_) => { |
406 | let link_str = String::from_utf8(link.url.clone()).unwrap(); | 407 | let link_str = String::from_utf8(link.url.clone()).unwrap(); |
407 | let link_text = String::from_utf8(link.title.clone()).unwrap(); | 408 | let link_text = String::from_utf8(link.title.clone()).unwrap(); |
408 | let resolved = try_resolve_path(db, definition, &link_str) | 409 | let resolved = try_resolve_intra(db, definition, &link_text, &link_str) |
409 | .or_else(|| try_resolve_intra(db, definition, &link_text, &link_str)); | 410 | .or_else(|| try_resolve_path(db, definition, &link_str)); |
410 | 411 | ||
411 | if let Some(resolved) = resolved { | 412 | if let Some(resolved) = resolved { |
412 | link.url = resolved.as_bytes().to_vec(); | 413 | link.url = resolved.as_bytes().to_vec(); |
@@ -420,7 +421,7 @@ fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> | |||
420 | }); | 421 | }); |
421 | let mut out = Vec::new(); | 422 | let mut out = Vec::new(); |
422 | format_commonmark(doc, &ComrakOptions::default(), &mut out).ok()?; | 423 | format_commonmark(doc, &ComrakOptions::default(), &mut out).ok()?; |
423 | Some(String::from_utf8(out).unwrap()) | 424 | Some(String::from_utf8(out).unwrap().trim().to_string()) |
424 | } | 425 | } |
425 | 426 | ||
426 | #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] | 427 | #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] |
@@ -470,32 +471,7 @@ fn try_resolve_intra(db: &RootDatabase, definition: &Definition, link_text: &str | |||
470 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); | 471 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); |
471 | 472 | ||
472 | // Resolve it relative to symbol's location (according to the RFC this should consider small scopes | 473 | // Resolve it relative to symbol's location (according to the RFC this should consider small scopes |
473 | let resolver = { | 474 | let resolver = definition.resolver(db)?; |
474 | use ra_hir_def::*; | ||
475 | use hir::*; | ||
476 | |||
477 | // TODO: This should be replaced by implementing HasResolver/TryHasResolver on ModuleDef and Definition. | ||
478 | match definition { | ||
479 | Definition::ModuleDef(def) => match def { | ||
480 | ModuleDef::Module(m) => Into::<ModuleId>::into(m.clone()).resolver(db), | ||
481 | ModuleDef::Function(f) => Into::<FunctionId>::into(f.clone()).resolver(db), | ||
482 | ModuleDef::Adt(adt) => Into::<AdtId>::into(adt.clone()).resolver(db), | ||
483 | ModuleDef::EnumVariant(ev) => Into::<GenericDefId>::into(Into::<GenericDef>::into(ev.clone())).resolver(db), | ||
484 | ModuleDef::Const(c) => Into::<GenericDefId>::into(Into::<GenericDef>::into(c.clone())).resolver(db), | ||
485 | ModuleDef::Static(s) => Into::<StaticId>::into(s.clone()).resolver(db), | ||
486 | ModuleDef::Trait(t) => Into::<TraitId>::into(t.clone()).resolver(db), | ||
487 | ModuleDef::TypeAlias(t) => Into::<ModuleId>::into(t.module(db)).resolver(db), | ||
488 | // TODO: This should be a resolver relative to `std` | ||
489 | ModuleDef::BuiltinType(_t) => Into::<ModuleId>::into(definition.module(db)?).resolver(db) | ||
490 | }, | ||
491 | Definition::Field(field) => Into::<VariantId>::into(Into::<VariantDef>::into(field.parent_def(db))).resolver(db), | ||
492 | Definition::Macro(m) => Into::<ModuleId>::into(m.module(db)?).resolver(db), | ||
493 | Definition::SelfType(imp) => Into::<ImplId>::into(imp.clone()).resolver(db), | ||
494 | // it's possible, read probable, that other arms of this are also unreachable | ||
495 | Definition::Local(_local) => unreachable!(), | ||
496 | Definition::TypeParam(tp) => Into::<ModuleId>::into(tp.module(db)).resolver(db) | ||
497 | } | ||
498 | }; | ||
499 | 475 | ||
500 | // Namespace disambiguation | 476 | // Namespace disambiguation |
501 | let namespace = Namespace::from_intra_spec(link_target); | 477 | let namespace = Namespace::from_intra_spec(link_target); |
@@ -527,7 +503,7 @@ fn try_resolve_intra(db: &RootDatabase, definition: &Definition, link_text: &str | |||
527 | get_doc_url(db, &krate)? | 503 | get_doc_url(db, &krate)? |
528 | .join(&format!("{}/", krate.display_name(db)?)).ok()? | 504 | .join(&format!("{}/", krate.display_name(db)?)).ok()? |
529 | .join(&path.segments.iter().map(|name| format!("{}", name)).join("/")).ok()? | 505 | .join(&path.segments.iter().map(|name| format!("{}", name)).join("/")).ok()? |
530 | .join(&get_symbol_filename(db, definition)?).ok()? | 506 | .join(&get_symbol_filename(db, &Definition::ModuleDef(def))?).ok()? |
531 | .into_string() | 507 | .into_string() |
532 | ) | 508 | ) |
533 | } | 509 | } |
@@ -637,11 +613,20 @@ mod tests { | |||
637 | 613 | ||
638 | use crate::mock_analysis::analysis_and_position; | 614 | use crate::mock_analysis::analysis_and_position; |
639 | 615 | ||
640 | fn trim_markup(s: &str) -> &str { | 616 | fn trim_markup(s: &str) -> String { |
641 | s.trim_start_matches("```rust\n").trim_end_matches("\n```") | 617 | s |
618 | .replace("``` rust", "```rust") | ||
619 | .replace("-----", "___") | ||
620 | .replace("\n\n___\n\n", "\n___\n\n") | ||
621 | .replace("\\<-", "<-") | ||
622 | .trim_start_matches("test\n```\n\n") | ||
623 | .trim_start_matches("```rust\n") | ||
624 | .trim_start_matches("test\n```\n\n```rust\n") | ||
625 | .trim_end_matches("\n```") | ||
626 | .to_string() | ||
642 | } | 627 | } |
643 | 628 | ||
644 | fn trim_markup_opt(s: Option<&str>) -> Option<&str> { | 629 | fn trim_markup_opt(s: Option<&str>) -> Option<String> { |
645 | s.map(trim_markup) | 630 | s.map(trim_markup) |
646 | } | 631 | } |
647 | 632 | ||
@@ -689,7 +674,7 @@ fn main() { | |||
689 | ); | 674 | ); |
690 | let hover = analysis.hover(position).unwrap().unwrap(); | 675 | let hover = analysis.hover(position).unwrap().unwrap(); |
691 | assert_eq!(hover.range, TextRange::new(58.into(), 63.into())); | 676 | assert_eq!(hover.range, TextRange::new(58.into(), 63.into())); |
692 | assert_eq!(trim_markup_opt(hover.info.first()), Some("u32")); | 677 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("u32")); |
693 | } | 678 | } |
694 | 679 | ||
695 | #[test] | 680 | #[test] |
@@ -818,7 +803,7 @@ fn main() { | |||
818 | }; | 803 | }; |
819 | } | 804 | } |
820 | "#, | 805 | "#, |
821 | &["Foo\n```\n\n```rust\nfield_a: u32"], | 806 | &["test::Foo\n```\n\n```rust\nfield_a: u32"], |
822 | ); | 807 | ); |
823 | 808 | ||
824 | // Hovering over the field in the definition | 809 | // Hovering over the field in the definition |
@@ -835,7 +820,7 @@ fn main() { | |||
835 | }; | 820 | }; |
836 | } | 821 | } |
837 | "#, | 822 | "#, |
838 | &["Foo\n```\n\n```rust\nfield_a: u32"], | 823 | &["test::Foo\n```\n\n```rust\nfield_a: u32"], |
839 | ); | 824 | ); |
840 | } | 825 | } |
841 | 826 | ||
@@ -888,7 +873,7 @@ fn main() { | |||
888 | ", | 873 | ", |
889 | ); | 874 | ); |
890 | let hover = analysis.hover(position).unwrap().unwrap(); | 875 | let hover = analysis.hover(position).unwrap().unwrap(); |
891 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n```\n\n```rust\nSome")); | 876 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("test::Option\n```\n\n```rust\nSome")); |
892 | 877 | ||
893 | let (analysis, position) = analysis_and_position( | 878 | let (analysis, position) = analysis_and_position( |
894 | " | 879 | " |
@@ -901,7 +886,7 @@ fn main() { | |||
901 | ", | 886 | ", |
902 | ); | 887 | ); |
903 | let hover = analysis.hover(position).unwrap().unwrap(); | 888 | let hover = analysis.hover(position).unwrap().unwrap(); |
904 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option<i32>")); | 889 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("Option<i32>")); |
905 | } | 890 | } |
906 | 891 | ||
907 | #[test] | 892 | #[test] |
@@ -915,7 +900,7 @@ fn main() { | |||
915 | } | 900 | } |
916 | "#, | 901 | "#, |
917 | &[" | 902 | &[" |
918 | Option | 903 | test::Option |
919 | ``` | 904 | ``` |
920 | 905 | ||
921 | ```rust | 906 | ```rust |
@@ -940,7 +925,7 @@ The None variant | |||
940 | } | 925 | } |
941 | "#, | 926 | "#, |
942 | &[" | 927 | &[" |
943 | Option | 928 | test::Option |
944 | ``` | 929 | ``` |
945 | 930 | ||
946 | ```rust | 931 | ```rust |
@@ -958,14 +943,14 @@ The Some variant | |||
958 | fn hover_for_local_variable() { | 943 | fn hover_for_local_variable() { |
959 | let (analysis, position) = analysis_and_position("fn func(foo: i32) { fo<|>o; }"); | 944 | let (analysis, position) = analysis_and_position("fn func(foo: i32) { fo<|>o; }"); |
960 | let hover = analysis.hover(position).unwrap().unwrap(); | 945 | let hover = analysis.hover(position).unwrap().unwrap(); |
961 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 946 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); |
962 | } | 947 | } |
963 | 948 | ||
964 | #[test] | 949 | #[test] |
965 | fn hover_for_local_variable_pat() { | 950 | fn hover_for_local_variable_pat() { |
966 | let (analysis, position) = analysis_and_position("fn func(fo<|>o: i32) {}"); | 951 | let (analysis, position) = analysis_and_position("fn func(fo<|>o: i32) {}"); |
967 | let hover = analysis.hover(position).unwrap().unwrap(); | 952 | let hover = analysis.hover(position).unwrap().unwrap(); |
968 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 953 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); |
969 | } | 954 | } |
970 | 955 | ||
971 | #[test] | 956 | #[test] |
@@ -976,14 +961,14 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
976 | ", | 961 | ", |
977 | ); | 962 | ); |
978 | let hover = analysis.hover(position).unwrap().unwrap(); | 963 | let hover = analysis.hover(position).unwrap().unwrap(); |
979 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 964 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); |
980 | } | 965 | } |
981 | 966 | ||
982 | #[test] | 967 | #[test] |
983 | fn hover_for_param_edge() { | 968 | fn hover_for_param_edge() { |
984 | let (analysis, position) = analysis_and_position("fn func(<|>foo: i32) {}"); | 969 | let (analysis, position) = analysis_and_position("fn func(<|>foo: i32) {}"); |
985 | let hover = analysis.hover(position).unwrap().unwrap(); | 970 | let hover = analysis.hover(position).unwrap().unwrap(); |
986 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 971 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); |
987 | } | 972 | } |
988 | 973 | ||
989 | #[test] | 974 | #[test] |
@@ -1004,7 +989,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1004 | ", | 989 | ", |
1005 | ); | 990 | ); |
1006 | let hover = analysis.hover(position).unwrap().unwrap(); | 991 | let hover = analysis.hover(position).unwrap().unwrap(); |
1007 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); | 992 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("Thing")); |
1008 | } | 993 | } |
1009 | 994 | ||
1010 | #[test] | 995 | #[test] |
@@ -1028,8 +1013,8 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1028 | ); | 1013 | ); |
1029 | let hover = analysis.hover(position).unwrap().unwrap(); | 1014 | let hover = analysis.hover(position).unwrap().unwrap(); |
1030 | assert_eq!( | 1015 | assert_eq!( |
1031 | trim_markup_opt(hover.info.first()), | 1016 | trim_markup_opt(hover.info.first()).as_deref(), |
1032 | Some("wrapper::Thing\n```\n\n```rust\nfn new() -> Thing") | 1017 | Some("test::wrapper::Thing\n```\n\n```rust\nfn new() -> Thing") |
1033 | ); | 1018 | ); |
1034 | } | 1019 | } |
1035 | 1020 | ||
@@ -1052,7 +1037,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1052 | ", | 1037 | ", |
1053 | ); | 1038 | ); |
1054 | let hover = analysis.hover(position).unwrap().unwrap(); | 1039 | let hover = analysis.hover(position).unwrap().unwrap(); |
1055 | assert_eq!(trim_markup_opt(hover.info.first()), Some("const C: u32")); | 1040 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("const C: u32")); |
1056 | } | 1041 | } |
1057 | 1042 | ||
1058 | #[test] | 1043 | #[test] |
@@ -1068,7 +1053,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1068 | ", | 1053 | ", |
1069 | ); | 1054 | ); |
1070 | let hover = analysis.hover(position).unwrap().unwrap(); | 1055 | let hover = analysis.hover(position).unwrap().unwrap(); |
1071 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); | 1056 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("Thing")); |
1072 | 1057 | ||
1073 | /* FIXME: revive these tests | 1058 | /* FIXME: revive these tests |
1074 | let (analysis, position) = analysis_and_position( | 1059 | let (analysis, position) = analysis_and_position( |
@@ -1125,7 +1110,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1125 | ", | 1110 | ", |
1126 | ); | 1111 | ); |
1127 | let hover = analysis.hover(position).unwrap().unwrap(); | 1112 | let hover = analysis.hover(position).unwrap().unwrap(); |
1128 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 1113 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); |
1129 | } | 1114 | } |
1130 | 1115 | ||
1131 | #[test] | 1116 | #[test] |
@@ -1142,7 +1127,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1142 | ", | 1127 | ", |
1143 | ); | 1128 | ); |
1144 | let hover = analysis.hover(position).unwrap().unwrap(); | 1129 | let hover = analysis.hover(position).unwrap().unwrap(); |
1145 | assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); | 1130 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("macro_rules! foo")); |
1146 | } | 1131 | } |
1147 | 1132 | ||
1148 | #[test] | 1133 | #[test] |
@@ -1153,7 +1138,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1153 | ", | 1138 | ", |
1154 | ); | 1139 | ); |
1155 | let hover = analysis.hover(position).unwrap().unwrap(); | 1140 | let hover = analysis.hover(position).unwrap().unwrap(); |
1156 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 1141 | assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); |
1157 | } | 1142 | } |
1158 | 1143 | ||
1159 | #[test] | 1144 | #[test] |
@@ -1415,6 +1400,59 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1415 | } | 1400 | } |
1416 | 1401 | ||
1417 | #[test] | 1402 | #[test] |
1403 | fn test_hover_path_link() { | ||
1404 | check_hover_result( | ||
1405 | r" | ||
1406 | //- /lib.rs | ||
1407 | pub struct Foo; | ||
1408 | /// [Foo](struct.Foo.html) | ||
1409 | pub struct B<|>ar | ||
1410 | ", | ||
1411 | &["pub struct Bar\n```\n___\n\n[Foo](https://docs.rs/test/*/test/struct.Foo.html)"] | ||
1412 | ); | ||
1413 | } | ||
1414 | |||
1415 | #[test] | ||
1416 | fn test_hover_intra_link() { | ||
1417 | check_hover_result( | ||
1418 | r" | ||
1419 | //- /lib.rs | ||
1420 | pub struct Foo; | ||
1421 | /// [Foo](Foo) | ||
1422 | pub struct B<|>ar | ||
1423 | ", | ||
1424 | &["pub struct Bar\n```\n___\n\n[Foo](https://docs.rs/test/*/test/struct.Foo.html)"] | ||
1425 | ); | ||
1426 | } | ||
1427 | |||
1428 | #[test] | ||
1429 | fn test_hover_intra_link_shortlink() { | ||
1430 | check_hover_result( | ||
1431 | r" | ||
1432 | //- /lib.rs | ||
1433 | pub struct Foo; | ||
1434 | /// [Foo] | ||
1435 | pub struct B<|>ar | ||
1436 | ", | ||
1437 | &["pub struct Bar\n```\n___\n\n[Foo](https://docs.rs/test/*/test/struct.Foo.html)"] | ||
1438 | ); | ||
1439 | } | ||
1440 | |||
1441 | #[test] | ||
1442 | fn test_hover_intra_link_namespaced() { | ||
1443 | check_hover_result( | ||
1444 | r" | ||
1445 | //- /lib.rs | ||
1446 | pub struct Foo; | ||
1447 | fn Foo() {} | ||
1448 | /// [Foo()] | ||
1449 | pub struct B<|>ar | ||
1450 | ", | ||
1451 | &["pub struct Bar\n```\n___\n\n[Foo](https://docs.rs/test/*/test/struct.Foo.html)"] | ||
1452 | ); | ||
1453 | } | ||
1454 | |||
1455 | #[test] | ||
1418 | fn test_hover_macro_generated_struct_fn_doc_comment() { | 1456 | fn test_hover_macro_generated_struct_fn_doc_comment() { |
1419 | mark::check!(hover_macro_generated_struct_fn_doc_comment); | 1457 | mark::check!(hover_macro_generated_struct_fn_doc_comment); |
1420 | 1458 | ||
@@ -1438,7 +1476,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1438 | bar.fo<|>o(); | 1476 | bar.fo<|>o(); |
1439 | } | 1477 | } |
1440 | "#, | 1478 | "#, |
1441 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\n Do the foo"], | 1479 | &["test::Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], |
1442 | ); | 1480 | ); |
1443 | } | 1481 | } |
1444 | 1482 | ||
@@ -1466,7 +1504,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1466 | bar.fo<|>o(); | 1504 | bar.fo<|>o(); |
1467 | } | 1505 | } |
1468 | "#, | 1506 | "#, |
1469 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], | 1507 | &["test::Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], |
1470 | ); | 1508 | ); |
1471 | } | 1509 | } |
1472 | 1510 | ||