1
1
use mdbook:: book:: Chapter ;
2
2
use once_cell:: sync:: Lazy ;
3
3
use regex:: { Captures , Regex } ;
4
+ use std:: collections:: HashSet ;
4
5
use std:: fmt:: Write as _;
5
6
use std:: fs;
6
7
use std:: io:: { self , Write as _} ;
@@ -32,6 +33,15 @@ static STD_LINK_RE: Lazy<Regex> = Lazy::new(|| {
32
33
static STD_LINK_EXTRACT_RE : Lazy < Regex > =
33
34
Lazy :: new ( || Regex :: new ( r#"<li><a [^>]*href="(https://doc.rust-lang.org/[^"]+)""# ) . unwrap ( ) ) ;
34
35
36
+ /// The Regex for a markdown link definition.
37
+ static LINK_DEF_RE : Lazy < Regex > = Lazy :: new ( || {
38
+ // This is a pretty lousy regex for a link definition. It doesn't
39
+ // handle things like blockquotes, code blocks, etc. Using a
40
+ // markdown parser isn't really feasible here, it would be nice to
41
+ // improve this.
42
+ Regex :: new ( r#"(?m)^(?<label>\[[^]]+\]): *(?<dest>.*)"# ) . unwrap ( )
43
+ } ) ;
44
+
35
45
/// Converts links to the standard library to the online documentation in a
36
46
/// fashion similar to rustdoc intra-doc links.
37
47
pub fn std_links ( chapter : & Chapter ) -> String {
@@ -87,7 +97,7 @@ pub fn std_links(chapter: &Chapter) -> String {
87
97
output
88
98
}
89
99
90
- /// Collects all markdown links.
100
+ /// Collects all markdown links, excluding those that already have link definitions .
91
101
///
92
102
/// Returns a `Vec` of `(link, Option<dest>)` where markdown text like
93
103
/// ``[`std::fmt`]`` would return that as a link. The dest is optional, for
@@ -112,6 +122,21 @@ fn collect_markdown_links(chapter: &Chapter) -> Vec<(&str, Option<&str>)> {
112
122
}
113
123
links. sort ( ) ;
114
124
links. dedup ( ) ;
125
+ // Remove any links that already have a link definition. We don't want
126
+ // to override what the author explicitly specified.
127
+ let existing_labels: HashSet < _ > = LINK_DEF_RE
128
+ . captures_iter ( & chapter. content )
129
+ . map ( |cap| cap. get ( 1 ) . unwrap ( ) . as_str ( ) )
130
+ . collect ( ) ;
131
+ links. retain ( |( link, dest) | {
132
+ let mut tmp = None ;
133
+ let label: & str = dest. map_or ( link, |d| {
134
+ tmp = Some ( format ! ( "[`{d}`]" ) ) ;
135
+ tmp. as_deref ( ) . unwrap ( )
136
+ } ) ;
137
+ !existing_labels. contains ( label)
138
+ } ) ;
139
+
115
140
links
116
141
}
117
142
0 commit comments