@@ -6,11 +6,11 @@ use once_cell::sync::Lazy;
6
6
use regex:: { Captures , Regex } ;
7
7
use semver:: { Version , VersionReq } ;
8
8
use std:: collections:: BTreeMap ;
9
- use std:: fmt:: Write as _;
10
- use std:: fs;
11
- use std:: io:: { self , Write as _} ;
9
+ use std:: io;
12
10
use std:: path:: PathBuf ;
13
- use std:: process:: { self , Command } ;
11
+ use std:: process;
12
+
13
+ mod std_links;
14
14
15
15
/// The Regex for rules like `r[foo]`.
16
16
static RULE_RE : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"(?m)^r\[([^]]+)]$" ) . unwrap ( ) ) ;
@@ -21,31 +21,6 @@ static ADMONITION_RE: Lazy<Regex> = Lazy::new(|| {
21
21
Regex :: new ( r"(?m)^ *> \[!(?<admon>[^]]+)\]\n(?<blockquote>(?: *> .*\n)+)" ) . unwrap ( )
22
22
} ) ;
23
23
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
-
49
24
fn main ( ) {
50
25
let mut args = std:: env:: args ( ) . skip ( 1 ) ;
51
26
match args. next ( ) . as_deref ( ) {
@@ -184,119 +159,6 @@ impl Spec {
184
159
} )
185
160
. to_string ( )
186
161
}
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
- }
300
162
}
301
163
302
164
impl Preprocessor for Spec {
@@ -315,7 +177,7 @@ impl Preprocessor for Spec {
315
177
}
316
178
ch. content = self . rule_definitions ( & ch, & mut found_rules) ;
317
179
ch. content = self . admonitions ( & ch) ;
318
- ch. content = self . std_links ( & ch) ;
180
+ ch. content = std_links :: std_links ( & ch) ;
319
181
}
320
182
for section in & mut book. sections {
321
183
let BookItem :: Chapter ( ch) = section else {
0 commit comments