diff options
Diffstat (limited to 'crates/ide/src/doc_links.rs')
-rw-r--r-- | crates/ide/src/doc_links.rs | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 367fac05e..de10406bc 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Resolves and rewrites links in markdown documentation. | 1 | //! Resolves and rewrites links in markdown documentation. |
2 | 2 | ||
3 | use std::{convert::TryFrom, iter::once}; | 3 | use std::{convert::TryFrom, iter::once, ops::Range}; |
4 | 4 | ||
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; | 6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; |
@@ -39,7 +39,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi | |||
39 | if target.contains("://") { | 39 | if target.contains("://") { |
40 | (target.to_string(), title.to_string()) | 40 | (target.to_string(), title.to_string()) |
41 | } else { | 41 | } else { |
42 | // Two posibilities: | 42 | // Two possibilities: |
43 | // * path-based links: `../../module/struct.MyStruct.html` | 43 | // * path-based links: `../../module/struct.MyStruct.html` |
44 | // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` | 44 | // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` |
45 | if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { | 45 | if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { |
@@ -61,6 +61,30 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi | |||
61 | out | 61 | out |
62 | } | 62 | } |
63 | 63 | ||
64 | pub(crate) fn extract_definitions_from_markdown( | ||
65 | markdown: &str, | ||
66 | ) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> { | ||
67 | let mut res = vec![]; | ||
68 | let mut cb = |link: BrokenLink| { | ||
69 | Some(( | ||
70 | /*url*/ link.reference.to_owned().into(), | ||
71 | /*title*/ link.reference.to_owned().into(), | ||
72 | )) | ||
73 | }; | ||
74 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); | ||
75 | for (event, range) in doc.into_offset_iter() { | ||
76 | match event { | ||
77 | Event::Start(Tag::Link(_link_type, ref target, ref title)) => { | ||
78 | let link = if target.is_empty() { title } else { target }; | ||
79 | let (link, ns) = parse_link(link); | ||
80 | res.push((link.to_string(), ns, range)); | ||
81 | } | ||
82 | _ => {} | ||
83 | } | ||
84 | } | ||
85 | res | ||
86 | } | ||
87 | |||
64 | /// Remove all links in markdown documentation. | 88 | /// Remove all links in markdown documentation. |
65 | pub(crate) fn remove_links(markdown: &str) -> String { | 89 | pub(crate) fn remove_links(markdown: &str) -> String { |
66 | let mut drop_link = false; | 90 | let mut drop_link = false; |
@@ -192,9 +216,7 @@ fn rewrite_intra_doc_link( | |||
192 | Definition::Field(it) => it.resolve_doc_path(db, link, ns), | 216 | Definition::Field(it) => it.resolve_doc_path(db, link, ns), |
193 | Definition::SelfType(_) | 217 | Definition::SelfType(_) |
194 | | Definition::Local(_) | 218 | | Definition::Local(_) |
195 | | Definition::TypeParam(_) | 219 | | Definition::GenericParam(_) |
196 | | Definition::ConstParam(_) | ||
197 | | Definition::LifetimeParam(_) | ||
198 | | Definition::Label(_) => return None, | 220 | | Definition::Label(_) => return None, |
199 | }?; | 221 | }?; |
200 | let krate = resolved.module(db)?.krate(); | 222 | let krate = resolved.module(db)?.krate(); |
@@ -420,7 +442,7 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem) | |||
420 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), | 442 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), |
421 | Some(AssocItemContainer::Trait(..)) | 443 | Some(AssocItemContainer::Trait(..)) |
422 | ); | 444 | ); |
423 | // This distinction may get more complicated when specialisation is available. | 445 | // This distinction may get more complicated when specialization is available. |
424 | // Rustdoc makes this decision based on whether a method 'has defaultness'. | 446 | // Rustdoc makes this decision based on whether a method 'has defaultness'. |
425 | // Currently this is only the case for provided trait methods. | 447 | // Currently this is only the case for provided trait methods. |
426 | if is_trait_method && !function.has_body(db) { | 448 | if is_trait_method && !function.has_body(db) { |
@@ -464,7 +486,7 @@ mod tests { | |||
464 | fn test_doc_url_struct() { | 486 | fn test_doc_url_struct() { |
465 | check( | 487 | check( |
466 | r#" | 488 | r#" |
467 | pub struct Fo<|>o; | 489 | pub struct Fo$0o; |
468 | "#, | 490 | "#, |
469 | expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], | 491 | expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], |
470 | ); | 492 | ); |
@@ -474,7 +496,7 @@ pub struct Fo<|>o; | |||
474 | fn test_doc_url_fn() { | 496 | fn test_doc_url_fn() { |
475 | check( | 497 | check( |
476 | r#" | 498 | r#" |
477 | pub fn fo<|>o() {} | 499 | pub fn fo$0o() {} |
478 | "#, | 500 | "#, |
479 | expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], | 501 | expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], |
480 | ); | 502 | ); |
@@ -487,7 +509,7 @@ pub fn fo<|>o() {} | |||
487 | pub struct Foo; | 509 | pub struct Foo; |
488 | 510 | ||
489 | impl Foo { | 511 | impl Foo { |
490 | pub fn met<|>hod() {} | 512 | pub fn met$0hod() {} |
491 | } | 513 | } |
492 | 514 | ||
493 | "#, | 515 | "#, |
@@ -500,7 +522,7 @@ impl Foo { | |||
500 | check( | 522 | check( |
501 | r#" | 523 | r#" |
502 | pub trait Bar { | 524 | pub trait Bar { |
503 | fn met<|>hod() {} | 525 | fn met$0hod() {} |
504 | } | 526 | } |
505 | 527 | ||
506 | "#, | 528 | "#, |
@@ -513,7 +535,7 @@ pub trait Bar { | |||
513 | check( | 535 | check( |
514 | r#" | 536 | r#" |
515 | pub trait Foo { | 537 | pub trait Foo { |
516 | fn met<|>hod(); | 538 | fn met$0hod(); |
517 | } | 539 | } |
518 | 540 | ||
519 | "#, | 541 | "#, |
@@ -526,7 +548,7 @@ pub trait Foo { | |||
526 | check( | 548 | check( |
527 | r#" | 549 | r#" |
528 | pub struct Foo { | 550 | pub struct Foo { |
529 | pub fie<|>ld: () | 551 | pub fie$0ld: () |
530 | } | 552 | } |
531 | 553 | ||
532 | "#, | 554 | "#, |
@@ -539,7 +561,7 @@ pub struct Foo { | |||
539 | check( | 561 | check( |
540 | r#" | 562 | r#" |
541 | pub mod foo { | 563 | pub mod foo { |
542 | pub mod ba<|>r {} | 564 | pub mod ba$0r {} |
543 | } | 565 | } |
544 | "#, | 566 | "#, |
545 | expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], | 567 | expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], |
@@ -564,7 +586,7 @@ pub mod wrapper { | |||
564 | } | 586 | } |
565 | 587 | ||
566 | fn foo() { | 588 | fn foo() { |
567 | let bar: wrapper::It<|>em; | 589 | let bar: wrapper::It$0em; |
568 | } | 590 | } |
569 | "#, | 591 | "#, |
570 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], | 592 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], |