Skip to content

Commit

Permalink
Rollup merge of rust-lang#86451 - notriddle:notriddle/rustdoc-intra-d…
Browse files Browse the repository at this point in the history
…oc-link-summary, r=CraftSpider

Resolve intra-doc links in summary desc

Before:

![rustdoc-intra-doc-link-summary-before](https://user-images.githubusercontent.com/1593513/122623069-9d995e80-d04f-11eb-8d46-ec2ec126bb5e.png)

After:

![rustdoc-intra-doc-link-summary](https://user-images.githubusercontent.com/1593513/122623076-a4c06c80-d04f-11eb-967a-f5916871c34b.png)
  • Loading branch information
JohnTitor authored Jun 22, 2021
2 parents fd96d55 + f67585d commit 555fbd7
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 15 deletions.
27 changes: 27 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,33 @@ impl Item {
.collect()
}

/// Find a list of all link names, without finding their href.
///
/// This is used for generating summary text, which does not include
/// the link text, but does need to know which `[]`-bracketed names
/// are actually links.
crate fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
cache
.intra_doc_links
.get(&self.def_id)
.map_or(&[][..], |v| v.as_slice())
.iter()
.filter_map(|ItemLink { link: s, link_text, did, fragment }| {
// FIXME(83083): using fragments as a side-channel for
// primitive names is very unfortunate
if did.is_some() || fragment.is_some() {
Some(RenderedLink {
original_text: s.clone(),
new_text: link_text.clone(),
href: String::new(),
})
} else {
None
}
})
.collect()
}

crate fn is_crate(&self) -> bool {
self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
}
Expand Down
7 changes: 4 additions & 3 deletions src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,14 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
// which should not be indexed. The crate-item itself is
// inserted later on when serializing the search-index.
if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
let desc = item.doc_value().map_or_else(String::new, |x| {
short_markdown_summary(&x.as_str(), &item.link_names(&self.cache))
});
self.cache.search_index.push(IndexItem {
ty: item.type_(),
name: s.to_string(),
path: path.join("::"),
desc: item
.doc_value()
.map_or_else(String::new, |x| short_markdown_summary(&x.as_str())),
desc,
parent,
parent_idx: None,
search_type: get_index_search_type(&item, &self.empty_cache, self.tcx),
Expand Down
25 changes: 21 additions & 4 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,11 @@ impl MarkdownSummaryLine<'_> {
///
/// Returns a tuple of the rendered HTML string and whether the output was shortened
/// due to the provided `length_limit`.
fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool) {
fn markdown_summary_with_limit(
md: &str,
link_names: &[RenderedLink],
length_limit: usize,
) -> (String, bool) {
if md.is_empty() {
return (String::new(), false);
}
Expand All @@ -1065,7 +1069,20 @@ fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool)
*text_length += text.len();
}

'outer: for event in Parser::new_ext(md, summary_opts()) {
let mut replacer = |broken_link: BrokenLink<'_>| {
if let Some(link) =
link_names.iter().find(|link| &*link.original_text == broken_link.reference)
{
Some((link.href.as_str().into(), link.new_text.as_str().into()))
} else {
None
}
};

let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
let p = LinkReplacer::new(p, link_names);

'outer: for event in p {
match &event {
Event::Text(text) => {
for word in text.split_inclusive(char::is_whitespace) {
Expand Down Expand Up @@ -1121,8 +1138,8 @@ fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool)
/// Will shorten to 59 or 60 characters, including an ellipsis (…) if it was shortened.
///
/// See [`markdown_summary_with_limit`] for details about what is rendered and what is not.
crate fn short_markdown_summary(markdown: &str) -> String {
let (mut s, was_shortened) = markdown_summary_with_limit(markdown, 59);
crate fn short_markdown_summary(markdown: &str, link_names: &[RenderedLink]) -> String {
let (mut s, was_shortened) = markdown_summary_with_limit(markdown, link_names, 59);

if was_shortened {
s.push('…');
Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/html/markdown/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ fn test_header_ids_multiple_blocks() {
#[test]
fn test_short_markdown_summary() {
fn t(input: &str, expect: &str) {
let output = short_markdown_summary(input);
let output = short_markdown_summary(input, &[][..]);
assert_eq!(output, expect, "original: {}", input);
}

Expand All @@ -232,6 +232,7 @@ fn test_short_markdown_summary() {
t("Hard-break \nsummary", "Hard-break summary");
t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
t("dud [link]", "dud [link]");
t("code `let x = i32;` ...", "code <code>let x = i32;</code> …");
t("type `Type<'static>` ...", "type <code>Type<'static></code> …");
t("# top header", "top header");
Expand Down Expand Up @@ -259,6 +260,7 @@ fn test_plain_text_summary() {
t("Hard-break \nsummary", "Hard-break summary");
t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
t("dud [link]", "dud [link]");
t("code `let x = i32;` ...", "code `let x = i32;` …");
t("type `Type<'static>` ...", "type `Type<'static>` …");
t("# top header", "top header");
Expand Down
13 changes: 9 additions & 4 deletions src/librustdoc/html/render/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
// has since been learned.
for &(did, ref item) in &cache.orphan_impl_items {
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
let desc = item
.doc_value()
.map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(&cache)));
cache.search_index.push(IndexItem {
ty: item.type_(),
name: item.name.unwrap().to_string(),
path: fqp[..fqp.len() - 1].join("::"),
desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
desc,
parent: Some(did.into()),
parent_idx: None,
search_type: get_index_search_type(&item, cache, tcx),
Expand All @@ -47,6 +50,11 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
}
}

let crate_doc = krate
.module
.doc_value()
.map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(&cache)));

let Cache { ref mut search_index, ref paths, .. } = *cache;

// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
Expand Down Expand Up @@ -100,9 +108,6 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
crate_items.push(&*item);
}

let crate_doc =
krate.module.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s));

struct CrateData<'a> {
doc: String,
items: Vec<&'a IndexItem>,
Expand Down
2 changes: 1 addition & 1 deletion src/test/rustdoc-js/summaries.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const QUERY = ['summaries', 'summaries::Sidebar', 'summaries::Sidebar2'];
const EXPECTED = [
{
'others': [
{ 'path': '', 'name': 'summaries', 'desc': 'This <em>summary</em> has a link and <code>code</code>.' },
{ 'path': '', 'name': 'summaries', 'desc': 'This <em>summary</em> has a link, [<code>code</code>], and <code>Sidebar2</code> intra-doc.' },
],
},
{
Expand Down
6 changes: 4 additions & 2 deletions src/test/rustdoc-js/summaries.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#![crate_type = "lib"]
#![crate_name = "summaries"]

//! This *summary* has a [link] and `code`.
//! This *summary* has a [link], [`code`], and [`Sidebar2`] intra-doc.
//!
//! This is the second paragraph.
//! This is the second paragraph. It should not be rendered.
//! To test that intra-doc links are resolved properly, [`code`] should render
//! the square brackets, and [`Sidebar2`] should not.
//!
//! [link]: https://example.com
Expand Down

0 comments on commit 555fbd7

Please sign in to comment.