Skip to content

Commit cbe568e

Browse files
committed
Split std_links into multiple functions.
The std_links function was getting a little long, this should help organize a little.
1 parent f01512d commit cbe568e

File tree

1 file changed

+72
-52
lines changed

1 file changed

+72
-52
lines changed

mdbook-spec/src/std_links.rs

Lines changed: 72 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::fmt::Write as _;
55
use std::fs;
66
use std::io::{self, Write as _};
77
use std::process::{self, Command};
8+
use tempfile::TempDir;
89

910
/// A markdown link (without the brackets) that might possibly be a link to
1011
/// the standard library using rustdoc's intra-doc notation.
@@ -34,12 +35,65 @@ static STD_LINK_EXTRACT_RE: Lazy<Regex> =
3435
/// Converts links to the standard library to the online documentation in a
3536
/// fashion similar to rustdoc intra-doc links.
3637
pub fn std_links(chapter: &Chapter) -> String {
37-
// This is very hacky, but should work well enough.
38-
//
39-
// Collect all standard library links.
40-
//
41-
// links are tuples of ("[`std::foo`]", None) for links without dest,
42-
// or ("[`foo`]", "std::foo") with a dest.
38+
let links = collect_markdown_links(chapter);
39+
if links.is_empty() {
40+
return chapter.content.clone();
41+
}
42+
43+
// Write a Rust source file to use with rustdoc to generate intra-doc links.
44+
let tmp = TempDir::with_prefix("mdbook-spec-").unwrap();
45+
run_rustdoc(&tmp, &links, &chapter);
46+
47+
// Extract the links from the generated html.
48+
let generated =
49+
fs::read_to_string(tmp.path().join("doc/a/index.html")).expect("index.html generated");
50+
let urls: Vec<_> = STD_LINK_EXTRACT_RE
51+
.captures_iter(&generated)
52+
.map(|cap| cap.get(1).unwrap().as_str())
53+
.collect();
54+
if urls.len() != links.len() {
55+
eprintln!(
56+
"error: expected rustdoc to generate {} links, but found {} in chapter {} ({:?})",
57+
links.len(),
58+
urls.len(),
59+
chapter.name,
60+
chapter.source_path.as_ref().unwrap()
61+
);
62+
process::exit(1);
63+
}
64+
65+
// Replace any disambiguated links with just the disambiguation.
66+
let mut output = STD_LINK_RE
67+
.replace_all(&chapter.content, |caps: &Captures| {
68+
if let Some(dest) = caps.get(2) {
69+
// Replace destination parenthesis with a link definition (square brackets).
70+
format!("{}[{}]", &caps[1], dest.as_str())
71+
} else {
72+
caps[0].to_string()
73+
}
74+
})
75+
.to_string();
76+
77+
// Append the link definitions to the bottom of the chapter.
78+
write!(output, "\n").unwrap();
79+
for ((link, dest), url) in links.iter().zip(urls) {
80+
if let Some(dest) = dest {
81+
write!(output, "[{dest}]: {url}\n").unwrap();
82+
} else {
83+
write!(output, "{link}: {url}\n").unwrap();
84+
}
85+
}
86+
87+
output
88+
}
89+
90+
/// Collects all markdown links.
91+
///
92+
/// Returns a `Vec` of `(link, Option<dest>)` where markdown text like
93+
/// ``[`std::fmt`]`` would return that as a link. The dest is optional, for
94+
/// example ``[`Option`](std::option::Option)`` would have the part in
95+
/// parentheses as the dest.
96+
fn collect_markdown_links(chapter: &Chapter) -> Vec<(&str, Option<&str>)> {
4397
let mut links: Vec<_> = STD_LINK_RE
4498
.captures_iter(&chapter.content)
4599
.map(|cap| {
@@ -54,13 +108,21 @@ pub fn std_links(chapter: &Chapter) -> String {
54108
})
55109
.collect();
56110
if links.is_empty() {
57-
return chapter.content.clone();
111+
return vec![];
58112
}
59113
links.sort();
60114
links.dedup();
115+
links
116+
}
61117

62-
// Write a Rust source file to use with rustdoc to generate intra-doc links.
63-
let tmp = tempfile::TempDir::with_prefix("mdbook-spec-").unwrap();
118+
/// Generates links using rustdoc.
119+
///
120+
/// This takes the given links and creates a temporary Rust source file
121+
/// containing those links within doc-comments, and then runs rustdoc to
122+
/// generate intra-doc links on them.
123+
///
124+
/// The output will be in the given `tmp` directory.
125+
fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) {
64126
let src_path = tmp.path().join("a.rs");
65127
// Allow redundant since there could some in-scope things that are
66128
// technically not necessary, but we don't care about (like
@@ -69,7 +131,7 @@ pub fn std_links(chapter: &Chapter) -> String {
69131
"#![deny(rustdoc::broken_intra_doc_links)]\n\
70132
#![allow(rustdoc::redundant_explicit_links)]\n"
71133
);
72-
for (link, dest) in &links {
134+
for (link, dest) in links {
73135
write!(src, "//! - {link}").unwrap();
74136
if let Some(dest) = dest {
75137
write!(src, "({})", dest).unwrap();
@@ -100,46 +162,4 @@ pub fn std_links(chapter: &Chapter) -> String {
100162
io::stderr().write_all(&output.stderr).unwrap();
101163
process::exit(1);
102164
}
103-
104-
// Extract the links from the generated html.
105-
let generated =
106-
fs::read_to_string(tmp.path().join("doc/a/index.html")).expect("index.html generated");
107-
let urls: Vec<_> = STD_LINK_EXTRACT_RE
108-
.captures_iter(&generated)
109-
.map(|cap| cap.get(1).unwrap().as_str())
110-
.collect();
111-
if urls.len() != links.len() {
112-
eprintln!(
113-
"error: expected rustdoc to generate {} links, but found {} in chapter {} ({:?})",
114-
links.len(),
115-
urls.len(),
116-
chapter.name,
117-
chapter.source_path.as_ref().unwrap()
118-
);
119-
process::exit(1);
120-
}
121-
122-
// Replace any disambiguated links with just the disambiguation.
123-
let mut output = STD_LINK_RE
124-
.replace_all(&chapter.content, |caps: &Captures| {
125-
if let Some(dest) = caps.get(2) {
126-
// Replace destination parenthesis with a link definition (square brackets).
127-
format!("{}[{}]", &caps[1], dest.as_str())
128-
} else {
129-
caps[0].to_string()
130-
}
131-
})
132-
.to_string();
133-
134-
// Append the link definitions to the bottom of the chapter.
135-
write!(output, "\n").unwrap();
136-
for ((link, dest), url) in links.iter().zip(urls) {
137-
if let Some(dest) = dest {
138-
write!(output, "[{dest}]: {url}\n").unwrap();
139-
} else {
140-
write!(output, "{link}: {url}\n").unwrap();
141-
}
142-
}
143-
144-
output
145165
}

0 commit comments

Comments
 (0)