@@ -6,11 +6,11 @@ use once_cell::sync::Lazy;
66use regex:: { Captures , Regex } ;
77use semver:: { Version , VersionReq } ;
88use std:: collections:: BTreeMap ;
9- use std:: fmt:: Write as _;
10- use std:: fs;
11- use std:: io:: { self , Write as _} ;
9+ use std:: io;
1210use std:: path:: PathBuf ;
13- use std:: process:: { self , Command } ;
11+ use std:: process;
12+
13+ mod std_links;
1414
1515/// The Regex for rules like `r[foo]`.
1616static RULE_RE : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"(?m)^r\[([^]]+)]$" ) . unwrap ( ) ) ;
@@ -21,31 +21,6 @@ static ADMONITION_RE: Lazy<Regex> = Lazy::new(|| {
2121 Regex :: new ( r"(?m)^ *> \[!(?<admon>[^]]+)\]\n(?<blockquote>(?: *> .*\n)+)" ) . unwrap ( )
2222} ) ;
2323
24- /// A markdown link (without the brackets) that might possibly be a link to
25- /// the standard library using rustdoc's intra-doc notation.
26- const STD_LINK : & str = r"(?: [a-z]+@ )?
27- (?: std|core|alloc|proc_macro|test )
28- (?: ::[A-Za-z0-9_!:<>{}()\[\]]+ )?" ;
29-
30- /// The Regex for a markdown link that might be a link to the standard library.
31- static STD_LINK_RE : Lazy < Regex > = Lazy :: new ( || {
32- Regex :: new ( & format ! (
33- r"(?x)
34- (?:
35- ( \[`[^`]+`\] ) \( ({STD_LINK}) \)
36- )
37- | (?:
38- ( \[`{STD_LINK}`\] )
39- )
40- "
41- ) )
42- . unwrap ( )
43- } ) ;
44-
45- /// The Regex used to extract the std links from the HTML generated by rustdoc.
46- static STD_LINK_EXTRACT_RE : Lazy < Regex > =
47- Lazy :: new ( || Regex :: new ( r#"<li><a [^>]*href="(https://doc.rust-lang.org/[^"]+)""# ) . unwrap ( ) ) ;
48-
4924fn main ( ) {
5025 let mut args = std:: env:: args ( ) . skip ( 1 ) ;
5126 match args. next ( ) . as_deref ( ) {
@@ -184,119 +159,6 @@ impl Spec {
184159 } )
185160 . to_string ( )
186161 }
187-
188- /// Converts links to the standard library to the online documentation in
189- /// a fashion similar to rustdoc intra-doc links.
190- fn std_links ( & self , chapter : & Chapter ) -> String {
191- // This is very hacky, but should work well enough.
192- //
193- // Collect all standard library links.
194- //
195- // links are tuples of ("[`std::foo`]", None) for links without dest,
196- // or ("[`foo`]", "std::foo") with a dest.
197- let mut links: Vec < _ > = STD_LINK_RE
198- . captures_iter ( & chapter. content )
199- . map ( |cap| {
200- if let Some ( no_dest) = cap. get ( 3 ) {
201- ( no_dest. as_str ( ) , None )
202- } else {
203- (
204- cap. get ( 1 ) . unwrap ( ) . as_str ( ) ,
205- Some ( cap. get ( 2 ) . unwrap ( ) . as_str ( ) ) ,
206- )
207- }
208- } )
209- . collect ( ) ;
210- if links. is_empty ( ) {
211- return chapter. content . clone ( ) ;
212- }
213- links. sort ( ) ;
214- links. dedup ( ) ;
215-
216- // Write a Rust source file to use with rustdoc to generate intra-doc links.
217- let tmp = tempfile:: TempDir :: with_prefix ( "mdbook-spec-" ) . unwrap ( ) ;
218- let src_path = tmp. path ( ) . join ( "a.rs" ) ;
219- // Allow redundant since there could some in-scope things that are
220- // technically not necessary, but we don't care about (like
221- // [`Option`](std::option::Option)).
222- let mut src = format ! (
223- "#![deny(rustdoc::broken_intra_doc_links)]\n \
224- #![allow(rustdoc::redundant_explicit_links)]\n "
225- ) ;
226- for ( link, dest) in & links {
227- write ! ( src, "//! - {link}" ) . unwrap ( ) ;
228- if let Some ( dest) = dest {
229- write ! ( src, "({})" , dest) . unwrap ( ) ;
230- }
231- src. push ( '\n' ) ;
232- }
233- writeln ! (
234- src,
235- "extern crate alloc;\n \
236- extern crate proc_macro;\n \
237- extern crate test;\n "
238- )
239- . unwrap ( ) ;
240- fs:: write ( & src_path, & src) . unwrap ( ) ;
241- let output = Command :: new ( "rustdoc" )
242- . arg ( "--edition=2021" )
243- . arg ( & src_path)
244- . current_dir ( tmp. path ( ) )
245- . output ( )
246- . expect ( "rustdoc installed" ) ;
247- if !output. status . success ( ) {
248- eprintln ! (
249- "error: failed to extract std links ({:?}) in chapter {} ({:?})\n " ,
250- output. status,
251- chapter. name,
252- chapter. source_path. as_ref( ) . unwrap( )
253- ) ;
254- io:: stderr ( ) . write_all ( & output. stderr ) . unwrap ( ) ;
255- process:: exit ( 1 ) ;
256- }
257-
258- // Extract the links from the generated html.
259- let generated =
260- fs:: read_to_string ( tmp. path ( ) . join ( "doc/a/index.html" ) ) . expect ( "index.html generated" ) ;
261- let urls: Vec < _ > = STD_LINK_EXTRACT_RE
262- . captures_iter ( & generated)
263- . map ( |cap| cap. get ( 1 ) . unwrap ( ) . as_str ( ) )
264- . collect ( ) ;
265- if urls. len ( ) != links. len ( ) {
266- eprintln ! (
267- "error: expected rustdoc to generate {} links, but found {} in chapter {} ({:?})" ,
268- links. len( ) ,
269- urls. len( ) ,
270- chapter. name,
271- chapter. source_path. as_ref( ) . unwrap( )
272- ) ;
273- process:: exit ( 1 ) ;
274- }
275-
276- // Replace any disambiguated links with just the disambiguation.
277- let mut output = STD_LINK_RE
278- . replace_all ( & chapter. content , |caps : & Captures | {
279- if let Some ( dest) = caps. get ( 2 ) {
280- // Replace destination parenthesis with a link definition (square brackets).
281- format ! ( "{}[{}]" , & caps[ 1 ] , dest. as_str( ) )
282- } else {
283- caps[ 0 ] . to_string ( )
284- }
285- } )
286- . to_string ( ) ;
287-
288- // Append the link definitions to the bottom of the chapter.
289- write ! ( output, "\n " ) . unwrap ( ) ;
290- for ( ( link, dest) , url) in links. iter ( ) . zip ( urls) {
291- if let Some ( dest) = dest {
292- write ! ( output, "[{dest}]: {url}\n " ) . unwrap ( ) ;
293- } else {
294- write ! ( output, "{link}: {url}\n " ) . unwrap ( ) ;
295- }
296- }
297-
298- output
299- }
300162}
301163
302164impl Preprocessor for Spec {
@@ -315,7 +177,7 @@ impl Preprocessor for Spec {
315177 }
316178 ch. content = self . rule_definitions ( & ch, & mut found_rules) ;
317179 ch. content = self . admonitions ( & ch) ;
318- ch. content = self . std_links ( & ch) ;
180+ ch. content = std_links :: std_links ( & ch) ;
319181 }
320182 for section in & mut book. sections {
321183 let BookItem :: Chapter ( ch) = section else {
0 commit comments