aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/hover.rs597
-rw-r--r--crates/ide/src/lib.rs1
-rw-r--r--crates/ide/src/link_rewrite.rs81
-rw-r--r--crates/ide/src/mock_analysis.rs2
4 files changed, 625 insertions, 56 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c75b2a510..b012e4900 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -14,6 +14,7 @@ use test_utils::mark;
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, ShortLabel, ToNav, TryToNav}, 16 display::{macro_label, ShortLabel, ToNav, TryToNav},
17 link_rewrite::rewrite_links,
17 markup::Markup, 18 markup::Markup,
18 runnables::runnable, 19 runnables::runnable,
19 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 20 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
@@ -92,7 +93,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
92 }; 93 };
93 if let Some(definition) = definition { 94 if let Some(definition) = definition {
94 if let Some(markup) = hover_for_definition(db, definition) { 95 if let Some(markup) = hover_for_definition(db, definition) {
95 res.markup = markup; 96 let markup = rewrite_links(db, &markup.as_str(), &definition);
97 res.markup = Markup::from(markup);
96 if let Some(action) = show_implementations_action(db, definition) { 98 if let Some(action) = show_implementations_action(db, definition) {
97 res.actions.push(action); 99 res.actions.push(action);
98 } 100 }
@@ -425,6 +427,7 @@ fn main() {
425"#, 427"#,
426 expect![[r#" 428 expect![[r#"
427 *iter* 429 *iter*
430
428 ```rust 431 ```rust
429 Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>> 432 Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
430 ``` 433 ```
@@ -443,6 +446,11 @@ fn main() { let foo_test = fo<|>o(); }
443"#, 446"#,
444 expect![[r#" 447 expect![[r#"
445 *foo* 448 *foo*
449
450 ```rust
451 test
452 ```
453
446 ```rust 454 ```rust
447 pub fn foo() -> u32 455 pub fn foo() -> u32
448 ``` 456 ```
@@ -487,6 +495,11 @@ fn main() { let foo_test = fo<|>o(); }
487 "#, 495 "#,
488 expect![[r#" 496 expect![[r#"
489 *foo* 497 *foo*
498
499 ```rust
500 test
501 ```
502
490 ```rust 503 ```rust
491 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str 504 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
492 ``` 505 ```
@@ -504,6 +517,11 @@ fn main() { }
504"#, 517"#,
505 expect![[r#" 518 expect![[r#"
506 *foo* 519 *foo*
520
521 ```rust
522 test
523 ```
524
507 ```rust 525 ```rust
508 pub fn foo(a: u32, b: u32) -> u32 526 pub fn foo(a: u32, b: u32) -> u32
509 ``` 527 ```
@@ -525,20 +543,27 @@ pub fn foo<|>(_: &Path) {}
525 543
526fn main() { } 544fn main() { }
527"#, 545"#,
528 expect![[r#" 546 expect![[r##"
529 *foo* 547 *foo*
548
549 ```rust
550 test
551 ```
552
530 ```rust 553 ```rust
531 pub fn foo(_: &Path) 554 pub fn foo(_: &Path)
532 ``` 555 ```
533 ___ 556
557 ---
534 558
535 # Example 559 # Example
560
536 ``` 561 ```
537 # use std::path::Path; 562 # use std::path::Path;
538 # 563 #
539 foo(Path::new("hello, world!")) 564 foo(Path::new("hello, world!"))
540 ``` 565 ```
541 "#]], 566 "##]],
542 ); 567 );
543 } 568 }
544 569
@@ -555,8 +580,9 @@ fn main() {
555"#, 580"#,
556 expect![[r#" 581 expect![[r#"
557 *field_a* 582 *field_a*
583
558 ```rust 584 ```rust
559 Foo 585 test::Foo
560 ``` 586 ```
561 587
562 ```rust 588 ```rust
@@ -576,8 +602,9 @@ fn main() {
576"#, 602"#,
577 expect![[r#" 603 expect![[r#"
578 *field_a* 604 *field_a*
605
579 ```rust 606 ```rust
580 Foo 607 test::Foo
581 ``` 608 ```
582 609
583 ```rust 610 ```rust
@@ -593,6 +620,11 @@ fn main() {
593 r#"const foo<|>: u32 = 123;"#, 620 r#"const foo<|>: u32 = 123;"#,
594 expect![[r#" 621 expect![[r#"
595 *foo* 622 *foo*
623
624 ```rust
625 test
626 ```
627
596 ```rust 628 ```rust
597 const foo: u32 = 123 629 const foo: u32 = 123
598 ``` 630 ```
@@ -602,6 +634,11 @@ fn main() {
602 r#"static foo<|>: u32 = 456;"#, 634 r#"static foo<|>: u32 = 456;"#,
603 expect![[r#" 635 expect![[r#"
604 *foo* 636 *foo*
637
638 ```rust
639 test
640 ```
641
605 ```rust 642 ```rust
606 static foo: u32 643 static foo: u32
607 ``` 644 ```
@@ -620,6 +657,7 @@ fn main() {
620}"#, 657}"#,
621 expect![[r#" 658 expect![[r#"
622 *zz* 659 *zz*
660
623 ```rust 661 ```rust
624 Test<i32, u8> 662 Test<i32, u8>
625 ``` 663 ```
@@ -638,8 +676,9 @@ fn main() { So<|>me(12); }
638"#, 676"#,
639 expect![[r#" 677 expect![[r#"
640 *Some* 678 *Some*
679
641 ```rust 680 ```rust
642 Option 681 test::Option
643 ``` 682 ```
644 683
645 ```rust 684 ```rust
@@ -657,6 +696,7 @@ fn main() { let b<|>ar = Some(12); }
657"#, 696"#,
658 expect![[r#" 697 expect![[r#"
659 *bar* 698 *bar*
699
660 ```rust 700 ```rust
661 Option<i32> 701 Option<i32>
662 ``` 702 ```
@@ -675,14 +715,16 @@ enum Option<T> {
675"#, 715"#,
676 expect![[r#" 716 expect![[r#"
677 *None* 717 *None*
718
678 ```rust 719 ```rust
679 Option 720 test::Option
680 ``` 721 ```
681 722
682 ```rust 723 ```rust
683 None 724 None
684 ``` 725 ```
685 ___ 726
727 ---
686 728
687 The None variant 729 The None variant
688 "#]], 730 "#]],
@@ -700,14 +742,16 @@ fn main() {
700"#, 742"#,
701 expect![[r#" 743 expect![[r#"
702 *Some* 744 *Some*
745
703 ```rust 746 ```rust
704 Option 747 test::Option
705 ``` 748 ```
706 749
707 ```rust 750 ```rust
708 Some 751 Some
709 ``` 752 ```
710 ___ 753
754 ---
711 755
712 The Some variant 756 The Some variant
713 "#]], 757 "#]],
@@ -720,6 +764,7 @@ fn main() {
720 r#"fn func(foo: i32) { fo<|>o; }"#, 764 r#"fn func(foo: i32) { fo<|>o; }"#,
721 expect![[r#" 765 expect![[r#"
722 *foo* 766 *foo*
767
723 ```rust 768 ```rust
724 i32 769 i32
725 ``` 770 ```
@@ -733,6 +778,7 @@ fn main() {
733 r#"fn func(fo<|>o: i32) {}"#, 778 r#"fn func(fo<|>o: i32) {}"#,
734 expect![[r#" 779 expect![[r#"
735 *foo* 780 *foo*
781
736 ```rust 782 ```rust
737 i32 783 i32
738 ``` 784 ```
@@ -746,6 +792,7 @@ fn main() {
746 r#"fn func(foo: i32) { if true { <|>foo; }; }"#, 792 r#"fn func(foo: i32) { if true { <|>foo; }; }"#,
747 expect![[r#" 793 expect![[r#"
748 *foo* 794 *foo*
795
749 ```rust 796 ```rust
750 i32 797 i32
751 ``` 798 ```
@@ -759,6 +806,7 @@ fn main() {
759 r#"fn func(<|>foo: i32) {}"#, 806 r#"fn func(<|>foo: i32) {}"#,
760 expect![[r#" 807 expect![[r#"
761 *foo* 808 *foo*
809
762 ```rust 810 ```rust
763 i32 811 i32
764 ``` 812 ```
@@ -778,6 +826,7 @@ fn main() {
778 fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, 826 fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
779 expect![[r#" 827 expect![[r#"
780 *_x* 828 *_x*
829
781 ```rust 830 ```rust
782 impl Deref<Target = u8> + DerefMut<Target = u8> 831 impl Deref<Target = u8> + DerefMut<Target = u8>
783 ``` 832 ```
@@ -799,6 +848,7 @@ fn main() { let foo_<|>test = Thing::new(); }
799 "#, 848 "#,
800 expect![[r#" 849 expect![[r#"
801 *foo_test* 850 *foo_test*
851
802 ```rust 852 ```rust
803 Thing 853 Thing
804 ``` 854 ```
@@ -822,8 +872,9 @@ fn main() { let foo_test = wrapper::Thing::new<|>(); }
822"#, 872"#,
823 expect![[r#" 873 expect![[r#"
824 *new* 874 *new*
875
825 ```rust 876 ```rust
826 wrapper::Thing 877 test::wrapper::Thing
827 ``` 878 ```
828 879
829 ```rust 880 ```rust
@@ -852,6 +903,11 @@ fn main() {
852"#, 903"#,
853 expect![[r#" 904 expect![[r#"
854 *C* 905 *C*
906
907 ```rust
908 test
909 ```
910
855 ```rust 911 ```rust
856 const C: u32 = 1 912 const C: u32 = 1
857 ``` 913 ```
@@ -929,6 +985,7 @@ fn y() {
929"#, 985"#,
930 expect![[r#" 986 expect![[r#"
931 *x* 987 *x*
988
932 ```rust 989 ```rust
933 i32 990 i32
934 ``` 991 ```
@@ -946,6 +1003,11 @@ fn f() { fo<|>o!(); }
946"#, 1003"#,
947 expect![[r#" 1004 expect![[r#"
948 *foo* 1005 *foo*
1006
1007 ```rust
1008 test
1009 ```
1010
949 ```rust 1011 ```rust
950 macro_rules! foo 1012 macro_rules! foo
951 ``` 1013 ```
@@ -976,6 +1038,11 @@ id! {
976"#, 1038"#,
977 expect![[r#" 1039 expect![[r#"
978 *foo* 1040 *foo*
1041
1042 ```rust
1043 test
1044 ```
1045
979 ```rust 1046 ```rust
980 fn foo() 1047 fn foo()
981 ``` 1048 ```
@@ -992,6 +1059,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); }
992"#, 1059"#,
993 expect![[r#" 1060 expect![[r#"
994 *bar* 1061 *bar*
1062
995 ```rust 1063 ```rust
996 u32 1064 u32
997 ``` 1065 ```
@@ -1009,6 +1077,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); }
1009"#, 1077"#,
1010 expect![[r#" 1078 expect![[r#"
1011 *bar* 1079 *bar*
1080
1012 ```rust 1081 ```rust
1013 u32 1082 u32
1014 ``` 1083 ```
@@ -1067,6 +1136,11 @@ fn foo() {
1067"#, 1136"#,
1068 expect![[r#" 1137 expect![[r#"
1069 *bar* 1138 *bar*
1139
1140 ```rust
1141 test
1142 ```
1143
1070 ```rust 1144 ```rust
1071 fn bar() -> bool 1145 fn bar() -> bool
1072 ``` 1146 ```
@@ -1099,12 +1173,18 @@ fn bar() { fo<|>o(); }
1099", 1173",
1100 expect![[r#" 1174 expect![[r#"
1101 *foo* 1175 *foo*
1176
1177 ```rust
1178 test
1179 ```
1180
1102 ```rust 1181 ```rust
1103 fn foo() 1182 fn foo()
1104 ``` 1183 ```
1105 ___
1106 1184
1107 <- ` ` here 1185 ---
1186
1187 \<- ` ` here
1108 "#]], 1188 "#]],
1109 ); 1189 );
1110 } 1190 }
@@ -1115,6 +1195,11 @@ fn bar() { fo<|>o(); }
1115 r#"async fn foo<|>() {}"#, 1195 r#"async fn foo<|>() {}"#,
1116 expect![[r#" 1196 expect![[r#"
1117 *foo* 1197 *foo*
1198
1199 ```rust
1200 test
1201 ```
1202
1118 ```rust 1203 ```rust
1119 async fn foo() 1204 async fn foo()
1120 ``` 1205 ```
@@ -1124,6 +1209,11 @@ fn bar() { fo<|>o(); }
1124 r#"pub const unsafe fn foo<|>() {}"#, 1209 r#"pub const unsafe fn foo<|>() {}"#,
1125 expect![[r#" 1210 expect![[r#"
1126 *foo* 1211 *foo*
1212
1213 ```rust
1214 test
1215 ```
1216
1127 ```rust 1217 ```rust
1128 pub const unsafe fn foo() 1218 pub const unsafe fn foo()
1129 ``` 1219 ```
@@ -1133,6 +1223,11 @@ fn bar() { fo<|>o(); }
1133 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, 1223 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#,
1134 expect![[r#" 1224 expect![[r#"
1135 *foo* 1225 *foo*
1226
1227 ```rust
1228 test
1229 ```
1230
1136 ```rust 1231 ```rust
1137 pub(crate) async unsafe extern "C" fn foo() 1232 pub(crate) async unsafe extern "C" fn foo()
1138 ``` 1233 ```
@@ -1210,6 +1305,11 @@ fn my() {}
1210"#, 1305"#,
1211 expect![[r#" 1306 expect![[r#"
1212 *my* 1307 *my*
1308
1309 ```rust
1310 test
1311 ```
1312
1213 ```rust 1313 ```rust
1214 mod my 1314 mod my
1215 ``` 1315 ```
@@ -1228,10 +1328,16 @@ fn foo() { let bar = Ba<|>r; }
1228"#, 1328"#,
1229 expect![[r#" 1329 expect![[r#"
1230 *Bar* 1330 *Bar*
1331
1332 ```rust
1333 test
1334 ```
1335
1231 ```rust 1336 ```rust
1232 struct Bar 1337 struct Bar
1233 ``` 1338 ```
1234 ___ 1339
1340 ---
1235 1341
1236 bar docs 1342 bar docs
1237 "#]], 1343 "#]],
@@ -1249,10 +1355,16 @@ fn foo() { let bar = Ba<|>r; }
1249"#, 1355"#,
1250 expect![[r#" 1356 expect![[r#"
1251 *Bar* 1357 *Bar*
1358
1359 ```rust
1360 test
1361 ```
1362
1252 ```rust 1363 ```rust
1253 struct Bar 1364 struct Bar
1254 ``` 1365 ```
1255 ___ 1366
1367 ---
1256 1368
1257 bar docs 1369 bar docs
1258 "#]], 1370 "#]],
@@ -1272,10 +1384,16 @@ fn foo() { let bar = Ba<|>r; }
1272"#, 1384"#,
1273 expect![[r#" 1385 expect![[r#"
1274 *Bar* 1386 *Bar*
1387
1388 ```rust
1389 test
1390 ```
1391
1275 ```rust 1392 ```rust
1276 struct Bar 1393 struct Bar
1277 ``` 1394 ```
1278 ___ 1395
1396 ---
1279 1397
1280 bar docs 0 1398 bar docs 0
1281 1399
@@ -1287,6 +1405,371 @@ fn foo() { let bar = Ba<|>r; }
1287 } 1405 }
1288 1406
1289 #[test] 1407 #[test]
1408 fn test_hover_path_link() {
1409 check(
1410 r"
1411 //- /lib.rs
1412 pub struct Foo;
1413 /// [Foo](struct.Foo.html)
1414 pub struct B<|>ar
1415 ",
1416 expect![[r#"
1417 *Bar*
1418
1419 ```rust
1420 test
1421 ```
1422
1423 ```rust
1424 pub struct Bar
1425 ```
1426
1427 ---
1428
1429 [Foo](https://docs.rs/test/*/test/struct.Foo.html)
1430 "#]],
1431 );
1432 }
1433
1434 #[test]
1435 fn test_hover_path_link_no_strip() {
1436 check(
1437 r"
1438 //- /lib.rs
1439 pub struct Foo;
1440 /// [struct Foo](struct.Foo.html)
1441 pub struct B<|>ar
1442 ",
1443 expect![[r#"
1444 *Bar*
1445
1446 ```rust
1447 test
1448 ```
1449
1450 ```rust
1451 pub struct Bar
1452 ```
1453
1454 ---
1455
1456 [struct Foo](https://docs.rs/test/*/test/struct.Foo.html)
1457 "#]],
1458 );
1459 }
1460
1461 #[ignore = "path based links currently only support documentation on ModuleDef items"]
1462 #[test]
1463 fn test_hover_path_link_field() {
1464 check(
1465 r"
1466 //- /lib.rs
1467 pub struct Foo;
1468 pub struct Bar {
1469 /// [Foo](struct.Foo.html)
1470 fie<|>ld: ()
1471 }
1472 ",
1473 expect![[r#"
1474 *field*
1475
1476 ```rust
1477 test::Bar
1478 ```
1479
1480 ```rust
1481 field: ()
1482 ```
1483
1484 ---
1485
1486 [Foo](https://docs.rs/test/*/test/struct.Foo.html)
1487 "#]],
1488 );
1489 }
1490
1491 #[test]
1492 fn test_hover_intra_link() {
1493 check(
1494 r"
1495 //- /lib.rs
1496 pub mod foo {
1497 pub struct Foo;
1498 }
1499 /// [Foo](foo::Foo)
1500 pub struct B<|>ar
1501 ",
1502 expect![[r#"
1503 *Bar*
1504
1505 ```rust
1506 test
1507 ```
1508
1509 ```rust
1510 pub struct Bar
1511 ```
1512
1513 ---
1514
1515 [Foo](https://docs.rs/test/*/test/foo/struct.Foo.html)
1516 "#]],
1517 );
1518 }
1519
1520 #[test]
1521 fn test_hover_intra_link_html_root_url() {
1522 check(
1523 r#"
1524 //- /lib.rs
1525
1526 #![doc(arbitrary_attribute = "test", html_root_url = "https:/example.com", arbitrary_attribute2)]
1527
1528 pub mod foo {
1529 pub struct Foo;
1530 }
1531 /// [Foo](foo::Foo)
1532 pub struct B<|>ar
1533 "#,
1534 expect![[r#"
1535 *Bar*
1536
1537 ```rust
1538 test
1539 ```
1540
1541 ```rust
1542 pub struct Bar
1543 ```
1544
1545 ---
1546
1547 [Foo](https://example.com/test/foo/struct.Foo.html)
1548 "#]],
1549 );
1550 }
1551
1552 #[test]
1553 fn test_hover_intra_link_shortlink() {
1554 check(
1555 r"
1556 //- /lib.rs
1557 pub struct Foo;
1558 /// [Foo]
1559 pub struct B<|>ar
1560 ",
1561 expect![[r#"
1562 *Bar*
1563
1564 ```rust
1565 test
1566 ```
1567
1568 ```rust
1569 pub struct Bar
1570 ```
1571
1572 ---
1573
1574 [Foo](https://docs.rs/test/*/test/struct.Foo.html)
1575 "#]],
1576 );
1577 }
1578
1579 #[test]
1580 fn test_hover_intra_link_shortlink_code() {
1581 check(
1582 r"
1583 //- /lib.rs
1584 pub struct Foo;
1585 /// [`Foo`]
1586 pub struct B<|>ar
1587 ",
1588 expect![[r#"
1589 *Bar*
1590
1591 ```rust
1592 test
1593 ```
1594
1595 ```rust
1596 pub struct Bar
1597 ```
1598
1599 ---
1600
1601 [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
1602 "#]],
1603 );
1604 }
1605
1606 #[test]
1607 fn test_hover_intra_link_namespaced() {
1608 check(
1609 r"
1610 //- /lib.rs
1611 pub struct Foo;
1612 fn Foo() {}
1613 /// [Foo()]
1614 pub struct B<|>ar
1615 ",
1616 expect![[r#"
1617 *Bar*
1618
1619 ```rust
1620 test
1621 ```
1622
1623 ```rust
1624 pub struct Bar
1625 ```
1626
1627 ---
1628
1629 [Foo](https://docs.rs/test/*/test/struct.Foo.html)
1630 "#]],
1631 );
1632 }
1633
1634 #[test]
1635 fn test_hover_intra_link_shortlink_namspaced_code() {
1636 check(
1637 r"
1638 //- /lib.rs
1639 pub struct Foo;
1640 /// [`struct Foo`]
1641 pub struct B<|>ar
1642 ",
1643 expect![[r#"
1644 *Bar*
1645
1646 ```rust
1647 test
1648 ```
1649
1650 ```rust
1651 pub struct Bar
1652 ```
1653
1654 ---
1655
1656 [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
1657 "#]],
1658 );
1659 }
1660
1661 #[test]
1662 fn test_hover_intra_link_shortlink_namspaced_code_with_at() {
1663 check(
1664 r"
1665 //- /lib.rs
1666 pub struct Foo;
1667 /// [`struct@Foo`]
1668 pub struct B<|>ar
1669 ",
1670 expect![[r#"
1671 *Bar*
1672
1673 ```rust
1674 test
1675 ```
1676
1677 ```rust
1678 pub struct Bar
1679 ```
1680
1681 ---
1682
1683 [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
1684 "#]],
1685 );
1686 }
1687
1688 #[test]
1689 fn test_hover_intra_link_reference() {
1690 check(
1691 r"
1692 //- /lib.rs
1693 pub struct Foo;
1694 /// [my Foo][foo]
1695 ///
1696 /// [foo]: Foo
1697 pub struct B<|>ar
1698 ",
1699 expect![[r#"
1700 *Bar*
1701
1702 ```rust
1703 test
1704 ```
1705
1706 ```rust
1707 pub struct Bar
1708 ```
1709
1710 ---
1711
1712 [my Foo](https://docs.rs/test/*/test/struct.Foo.html)
1713 "#]],
1714 );
1715 }
1716
1717 #[test]
1718 fn test_hover_external_url() {
1719 check(
1720 r"
1721 //- /lib.rs
1722 pub struct Foo;
1723 /// [external](https://www.google.com)
1724 pub struct B<|>ar
1725 ",
1726 expect![[r#"
1727 *Bar*
1728
1729 ```rust
1730 test
1731 ```
1732
1733 ```rust
1734 pub struct Bar
1735 ```
1736
1737 ---
1738
1739 [external](https://www.google.com)
1740 "#]],
1741 );
1742 }
1743
1744 // Check that we don't rewrite links which we can't identify
1745 #[test]
1746 fn test_hover_unknown_target() {
1747 check(
1748 r"
1749 //- /lib.rs
1750 pub struct Foo;
1751 /// [baz](Baz)
1752 pub struct B<|>ar
1753 ",
1754 expect![[r#"
1755 *Bar*
1756
1757 ```rust
1758 test
1759 ```
1760
1761 ```rust
1762 pub struct Bar
1763 ```
1764
1765 ---
1766
1767 [baz](Baz)
1768 "#]],
1769 );
1770 }
1771
1772 #[test]
1290 fn test_hover_macro_generated_struct_fn_doc_comment() { 1773 fn test_hover_macro_generated_struct_fn_doc_comment() {
1291 mark::check!(hover_macro_generated_struct_fn_doc_comment); 1774 mark::check!(hover_macro_generated_struct_fn_doc_comment);
1292 1775
@@ -1308,16 +1791,18 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
1308"#, 1791"#,
1309 expect![[r#" 1792 expect![[r#"
1310 *foo* 1793 *foo*
1794
1311 ```rust 1795 ```rust
1312 Bar 1796 test::Bar
1313 ``` 1797 ```
1314 1798
1315 ```rust 1799 ```rust
1316 fn foo(&self) 1800 fn foo(&self)
1317 ``` 1801 ```
1318 ___
1319 1802
1320 Do the foo 1803 ---
1804
1805 Do the foo
1321 "#]], 1806 "#]],
1322 ); 1807 );
1323 } 1808 }
@@ -1344,14 +1829,16 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
1344"#, 1829"#,
1345 expect![[r#" 1830 expect![[r#"
1346 *foo* 1831 *foo*
1832
1347 ```rust 1833 ```rust
1348 Bar 1834 test::Bar
1349 ``` 1835 ```
1350 1836
1351 ```rust 1837 ```rust
1352 fn foo(&self) 1838 fn foo(&self)
1353 ``` 1839 ```
1354 ___ 1840
1841 ---
1355 1842
1356 Do the foo 1843 Do the foo
1357 "#]], 1844 "#]],
@@ -1526,7 +2013,7 @@ fn main() { let s<|>t = S{ f1:0 }; }
1526 GoToType( 2013 GoToType(
1527 [ 2014 [
1528 HoverGotoTypeData { 2015 HoverGotoTypeData {
1529 mod_path: "S", 2016 mod_path: "test::S",
1530 nav: NavigationTarget { 2017 nav: NavigationTarget {
1531 file_id: FileId( 2018 file_id: FileId(
1532 1, 2019 1,
@@ -1565,7 +2052,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; }
1565 GoToType( 2052 GoToType(
1566 [ 2053 [
1567 HoverGotoTypeData { 2054 HoverGotoTypeData {
1568 mod_path: "S", 2055 mod_path: "test::S",
1569 nav: NavigationTarget { 2056 nav: NavigationTarget {
1570 file_id: FileId( 2057 file_id: FileId(
1571 1, 2058 1,
@@ -1584,7 +2071,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; }
1584 }, 2071 },
1585 }, 2072 },
1586 HoverGotoTypeData { 2073 HoverGotoTypeData {
1587 mod_path: "Arg", 2074 mod_path: "test::Arg",
1588 nav: NavigationTarget { 2075 nav: NavigationTarget {
1589 file_id: FileId( 2076 file_id: FileId(
1590 1, 2077 1,
@@ -1623,7 +2110,7 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
1623 GoToType( 2110 GoToType(
1624 [ 2111 [
1625 HoverGotoTypeData { 2112 HoverGotoTypeData {
1626 mod_path: "S", 2113 mod_path: "test::S",
1627 nav: NavigationTarget { 2114 nav: NavigationTarget {
1628 file_id: FileId( 2115 file_id: FileId(
1629 1, 2116 1,
@@ -1642,7 +2129,7 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
1642 }, 2129 },
1643 }, 2130 },
1644 HoverGotoTypeData { 2131 HoverGotoTypeData {
1645 mod_path: "Arg", 2132 mod_path: "test::Arg",
1646 nav: NavigationTarget { 2133 nav: NavigationTarget {
1647 file_id: FileId( 2134 file_id: FileId(
1648 1, 2135 1,
@@ -1684,7 +2171,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
1684 GoToType( 2171 GoToType(
1685 [ 2172 [
1686 HoverGotoTypeData { 2173 HoverGotoTypeData {
1687 mod_path: "A", 2174 mod_path: "test::A",
1688 nav: NavigationTarget { 2175 nav: NavigationTarget {
1689 file_id: FileId( 2176 file_id: FileId(
1690 1, 2177 1,
@@ -1703,7 +2190,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
1703 }, 2190 },
1704 }, 2191 },
1705 HoverGotoTypeData { 2192 HoverGotoTypeData {
1706 mod_path: "B", 2193 mod_path: "test::B",
1707 nav: NavigationTarget { 2194 nav: NavigationTarget {
1708 file_id: FileId( 2195 file_id: FileId(
1709 1, 2196 1,
@@ -1722,7 +2209,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
1722 }, 2209 },
1723 }, 2210 },
1724 HoverGotoTypeData { 2211 HoverGotoTypeData {
1725 mod_path: "M::C", 2212 mod_path: "test::M::C",
1726 nav: NavigationTarget { 2213 nav: NavigationTarget {
1727 file_id: FileId( 2214 file_id: FileId(
1728 1, 2215 1,
@@ -1761,7 +2248,7 @@ fn main() { let s<|>t = foo(); }
1761 GoToType( 2248 GoToType(
1762 [ 2249 [
1763 HoverGotoTypeData { 2250 HoverGotoTypeData {
1764 mod_path: "Foo", 2251 mod_path: "test::Foo",
1765 nav: NavigationTarget { 2252 nav: NavigationTarget {
1766 file_id: FileId( 2253 file_id: FileId(
1767 1, 2254 1,
@@ -1801,7 +2288,7 @@ fn main() { let s<|>t = foo(); }
1801 GoToType( 2288 GoToType(
1802 [ 2289 [
1803 HoverGotoTypeData { 2290 HoverGotoTypeData {
1804 mod_path: "Foo", 2291 mod_path: "test::Foo",
1805 nav: NavigationTarget { 2292 nav: NavigationTarget {
1806 file_id: FileId( 2293 file_id: FileId(
1807 1, 2294 1,
@@ -1820,7 +2307,7 @@ fn main() { let s<|>t = foo(); }
1820 }, 2307 },
1821 }, 2308 },
1822 HoverGotoTypeData { 2309 HoverGotoTypeData {
1823 mod_path: "S", 2310 mod_path: "test::S",
1824 nav: NavigationTarget { 2311 nav: NavigationTarget {
1825 file_id: FileId( 2312 file_id: FileId(
1826 1, 2313 1,
@@ -1860,7 +2347,7 @@ fn main() { let s<|>t = foo(); }
1860 GoToType( 2347 GoToType(
1861 [ 2348 [
1862 HoverGotoTypeData { 2349 HoverGotoTypeData {
1863 mod_path: "Foo", 2350 mod_path: "test::Foo",
1864 nav: NavigationTarget { 2351 nav: NavigationTarget {
1865 file_id: FileId( 2352 file_id: FileId(
1866 1, 2353 1,
@@ -1879,7 +2366,7 @@ fn main() { let s<|>t = foo(); }
1879 }, 2366 },
1880 }, 2367 },
1881 HoverGotoTypeData { 2368 HoverGotoTypeData {
1882 mod_path: "Bar", 2369 mod_path: "test::Bar",
1883 nav: NavigationTarget { 2370 nav: NavigationTarget {
1884 file_id: FileId( 2371 file_id: FileId(
1885 1, 2372 1,
@@ -1922,7 +2409,7 @@ fn main() { let s<|>t = foo(); }
1922 GoToType( 2409 GoToType(
1923 [ 2410 [
1924 HoverGotoTypeData { 2411 HoverGotoTypeData {
1925 mod_path: "Foo", 2412 mod_path: "test::Foo",
1926 nav: NavigationTarget { 2413 nav: NavigationTarget {
1927 file_id: FileId( 2414 file_id: FileId(
1928 1, 2415 1,
@@ -1941,7 +2428,7 @@ fn main() { let s<|>t = foo(); }
1941 }, 2428 },
1942 }, 2429 },
1943 HoverGotoTypeData { 2430 HoverGotoTypeData {
1944 mod_path: "Bar", 2431 mod_path: "test::Bar",
1945 nav: NavigationTarget { 2432 nav: NavigationTarget {
1946 file_id: FileId( 2433 file_id: FileId(
1947 1, 2434 1,
@@ -1960,7 +2447,7 @@ fn main() { let s<|>t = foo(); }
1960 }, 2447 },
1961 }, 2448 },
1962 HoverGotoTypeData { 2449 HoverGotoTypeData {
1963 mod_path: "S1", 2450 mod_path: "test::S1",
1964 nav: NavigationTarget { 2451 nav: NavigationTarget {
1965 file_id: FileId( 2452 file_id: FileId(
1966 1, 2453 1,
@@ -1979,7 +2466,7 @@ fn main() { let s<|>t = foo(); }
1979 }, 2466 },
1980 }, 2467 },
1981 HoverGotoTypeData { 2468 HoverGotoTypeData {
1982 mod_path: "S2", 2469 mod_path: "test::S2",
1983 nav: NavigationTarget { 2470 nav: NavigationTarget {
1984 file_id: FileId( 2471 file_id: FileId(
1985 1, 2472 1,
@@ -2016,7 +2503,7 @@ fn foo(ar<|>g: &impl Foo) {}
2016 GoToType( 2503 GoToType(
2017 [ 2504 [
2018 HoverGotoTypeData { 2505 HoverGotoTypeData {
2019 mod_path: "Foo", 2506 mod_path: "test::Foo",
2020 nav: NavigationTarget { 2507 nav: NavigationTarget {
2021 file_id: FileId( 2508 file_id: FileId(
2022 1, 2509 1,
@@ -2056,7 +2543,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2056 GoToType( 2543 GoToType(
2057 [ 2544 [
2058 HoverGotoTypeData { 2545 HoverGotoTypeData {
2059 mod_path: "Foo", 2546 mod_path: "test::Foo",
2060 nav: NavigationTarget { 2547 nav: NavigationTarget {
2061 file_id: FileId( 2548 file_id: FileId(
2062 1, 2549 1,
@@ -2075,7 +2562,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2075 }, 2562 },
2076 }, 2563 },
2077 HoverGotoTypeData { 2564 HoverGotoTypeData {
2078 mod_path: "Bar", 2565 mod_path: "test::Bar",
2079 nav: NavigationTarget { 2566 nav: NavigationTarget {
2080 file_id: FileId( 2567 file_id: FileId(
2081 1, 2568 1,
@@ -2094,7 +2581,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2094 }, 2581 },
2095 }, 2582 },
2096 HoverGotoTypeData { 2583 HoverGotoTypeData {
2097 mod_path: "S", 2584 mod_path: "test::S",
2098 nav: NavigationTarget { 2585 nav: NavigationTarget {
2099 file_id: FileId( 2586 file_id: FileId(
2100 1, 2587 1,
@@ -2132,7 +2619,7 @@ fn foo(ar<|>g: &impl Foo<S>) {}
2132 GoToType( 2619 GoToType(
2133 [ 2620 [
2134 HoverGotoTypeData { 2621 HoverGotoTypeData {
2135 mod_path: "Foo", 2622 mod_path: "test::Foo",
2136 nav: NavigationTarget { 2623 nav: NavigationTarget {
2137 file_id: FileId( 2624 file_id: FileId(
2138 1, 2625 1,
@@ -2151,7 +2638,7 @@ fn foo(ar<|>g: &impl Foo<S>) {}
2151 }, 2638 },
2152 }, 2639 },
2153 HoverGotoTypeData { 2640 HoverGotoTypeData {
2154 mod_path: "S", 2641 mod_path: "test::S",
2155 nav: NavigationTarget { 2642 nav: NavigationTarget {
2156 file_id: FileId( 2643 file_id: FileId(
2157 1, 2644 1,
@@ -2194,7 +2681,7 @@ fn main() { let s<|>t = foo(); }
2194 GoToType( 2681 GoToType(
2195 [ 2682 [
2196 HoverGotoTypeData { 2683 HoverGotoTypeData {
2197 mod_path: "B", 2684 mod_path: "test::B",
2198 nav: NavigationTarget { 2685 nav: NavigationTarget {
2199 file_id: FileId( 2686 file_id: FileId(
2200 1, 2687 1,
@@ -2213,7 +2700,7 @@ fn main() { let s<|>t = foo(); }
2213 }, 2700 },
2214 }, 2701 },
2215 HoverGotoTypeData { 2702 HoverGotoTypeData {
2216 mod_path: "Foo", 2703 mod_path: "test::Foo",
2217 nav: NavigationTarget { 2704 nav: NavigationTarget {
2218 file_id: FileId( 2705 file_id: FileId(
2219 1, 2706 1,
@@ -2250,7 +2737,7 @@ fn foo(ar<|>g: &dyn Foo) {}
2250 GoToType( 2737 GoToType(
2251 [ 2738 [
2252 HoverGotoTypeData { 2739 HoverGotoTypeData {
2253 mod_path: "Foo", 2740 mod_path: "test::Foo",
2254 nav: NavigationTarget { 2741 nav: NavigationTarget {
2255 file_id: FileId( 2742 file_id: FileId(
2256 1, 2743 1,
@@ -2288,7 +2775,7 @@ fn foo(ar<|>g: &dyn Foo<S>) {}
2288 GoToType( 2775 GoToType(
2289 [ 2776 [
2290 HoverGotoTypeData { 2777 HoverGotoTypeData {
2291 mod_path: "Foo", 2778 mod_path: "test::Foo",
2292 nav: NavigationTarget { 2779 nav: NavigationTarget {
2293 file_id: FileId( 2780 file_id: FileId(
2294 1, 2781 1,
@@ -2307,7 +2794,7 @@ fn foo(ar<|>g: &dyn Foo<S>) {}
2307 }, 2794 },
2308 }, 2795 },
2309 HoverGotoTypeData { 2796 HoverGotoTypeData {
2310 mod_path: "S", 2797 mod_path: "test::S",
2311 nav: NavigationTarget { 2798 nav: NavigationTarget {
2312 file_id: FileId( 2799 file_id: FileId(
2313 1, 2800 1,
@@ -2348,7 +2835,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2348 GoToType( 2835 GoToType(
2349 [ 2836 [
2350 HoverGotoTypeData { 2837 HoverGotoTypeData {
2351 mod_path: "ImplTrait", 2838 mod_path: "test::ImplTrait",
2352 nav: NavigationTarget { 2839 nav: NavigationTarget {
2353 file_id: FileId( 2840 file_id: FileId(
2354 1, 2841 1,
@@ -2367,7 +2854,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2367 }, 2854 },
2368 }, 2855 },
2369 HoverGotoTypeData { 2856 HoverGotoTypeData {
2370 mod_path: "B", 2857 mod_path: "test::B",
2371 nav: NavigationTarget { 2858 nav: NavigationTarget {
2372 file_id: FileId( 2859 file_id: FileId(
2373 1, 2860 1,
@@ -2386,7 +2873,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2386 }, 2873 },
2387 }, 2874 },
2388 HoverGotoTypeData { 2875 HoverGotoTypeData {
2389 mod_path: "DynTrait", 2876 mod_path: "test::DynTrait",
2390 nav: NavigationTarget { 2877 nav: NavigationTarget {
2391 file_id: FileId( 2878 file_id: FileId(
2392 1, 2879 1,
@@ -2405,7 +2892,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2405 }, 2892 },
2406 }, 2893 },
2407 HoverGotoTypeData { 2894 HoverGotoTypeData {
2408 mod_path: "S", 2895 mod_path: "test::S",
2409 nav: NavigationTarget { 2896 nav: NavigationTarget {
2410 file_id: FileId( 2897 file_id: FileId(
2411 1, 2898 1,
@@ -2453,7 +2940,7 @@ fn main() { let s<|>t = test().get(); }
2453 GoToType( 2940 GoToType(
2454 [ 2941 [
2455 HoverGotoTypeData { 2942 HoverGotoTypeData {
2456 mod_path: "Foo", 2943 mod_path: "test::Foo",
2457 nav: NavigationTarget { 2944 nav: NavigationTarget {
2458 file_id: FileId( 2945 file_id: FileId(
2459 1, 2946 1,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index e3af6d5bc..570790384 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -43,6 +43,7 @@ mod status;
43mod syntax_highlighting; 43mod syntax_highlighting;
44mod syntax_tree; 44mod syntax_tree;
45mod typing; 45mod typing;
46mod link_rewrite;
46 47
47use std::sync::Arc; 48use std::sync::Arc;
48 49
diff --git a/crates/ide/src/link_rewrite.rs b/crates/ide/src/link_rewrite.rs
new file mode 100644
index 000000000..ff3200eef
--- /dev/null
+++ b/crates/ide/src/link_rewrite.rs
@@ -0,0 +1,81 @@
1//! Resolves and rewrites links in markdown documentation.
2//!
3//! Most of the implementation can be found in [`hir::doc_links`].
4
5use pulldown_cmark::{CowStr, Event, Options, Parser, Tag};
6use pulldown_cmark_to_cmark::{cmark_with_options, Options as CmarkOptions};
7
8use hir::resolve_doc_link;
9use ide_db::{defs::Definition, RootDatabase};
10
11/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
12pub fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
13 let doc = Parser::new_with_broken_link_callback(
14 markdown,
15 Options::empty(),
16 Some(&|label, _| Some((/*url*/ label.to_string(), /*title*/ label.to_string()))),
17 );
18
19 let doc = map_links(doc, |target, title: &str| {
20 // This check is imperfect, there's some overlap between valid intra-doc links
21 // and valid URLs so we choose to be too eager to try to resolve what might be
22 // a URL.
23 if target.contains("://") {
24 (target.to_string(), title.to_string())
25 } else {
26 // Two posibilities:
27 // * path-based links: `../../module/struct.MyStruct.html`
28 // * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
29 let resolved = match definition {
30 Definition::ModuleDef(t) => resolve_doc_link(db, t, title, target),
31 Definition::Macro(t) => resolve_doc_link(db, t, title, target),
32 Definition::Field(t) => resolve_doc_link(db, t, title, target),
33 Definition::SelfType(t) => resolve_doc_link(db, t, title, target),
34 Definition::Local(t) => resolve_doc_link(db, t, title, target),
35 Definition::TypeParam(t) => resolve_doc_link(db, t, title, target),
36 };
37
38 match resolved {
39 Some((target, title)) => (target, title),
40 None => (target.to_string(), title.to_string()),
41 }
42 }
43 });
44 let mut out = String::new();
45 let mut options = CmarkOptions::default();
46 options.code_block_backticks = 3;
47 cmark_with_options(doc, &mut out, None, options).ok();
48 out
49}
50
51// Rewrites a markdown document, resolving links using `callback` and additionally striping prefixes/suffixes on link titles.
52fn map_links<'e>(
53 events: impl Iterator<Item = Event<'e>>,
54 callback: impl Fn(&str, &str) -> (String, String),
55) -> impl Iterator<Item = Event<'e>> {
56 let mut in_link = false;
57 let mut link_target: Option<CowStr> = None;
58
59 events.map(move |evt| match evt {
60 Event::Start(Tag::Link(_link_type, ref target, _)) => {
61 in_link = true;
62 link_target = Some(target.clone());
63 evt
64 }
65 Event::End(Tag::Link(link_type, _target, _)) => {
66 in_link = false;
67 Event::End(Tag::Link(link_type, link_target.take().unwrap(), CowStr::Borrowed("")))
68 }
69 Event::Text(s) if in_link => {
70 let (link_target_s, link_name) = callback(&link_target.take().unwrap(), &s);
71 link_target = Some(CowStr::Boxed(link_target_s.into()));
72 Event::Text(CowStr::Boxed(link_name.into()))
73 }
74 Event::Code(s) if in_link => {
75 let (link_target_s, link_name) = callback(&link_target.take().unwrap(), &s);
76 link_target = Some(CowStr::Boxed(link_target_s.into()));
77 Event::Code(CowStr::Boxed(link_name.into()))
78 }
79 _ => evt,
80 })
81}
diff --git a/crates/ide/src/mock_analysis.rs b/crates/ide/src/mock_analysis.rs
index 363e6d27e..235796dbc 100644
--- a/crates/ide/src/mock_analysis.rs
+++ b/crates/ide/src/mock_analysis.rs
@@ -115,7 +115,7 @@ impl MockAnalysis {
115 root_crate = Some(crate_graph.add_crate_root( 115 root_crate = Some(crate_graph.add_crate_root(
116 file_id, 116 file_id,
117 edition, 117 edition,
118 None, 118 Some("test".to_string()),
119 cfg, 119 cfg,
120 env, 120 env,
121 Default::default(), 121 Default::default(),