1
- use mdbook:: book:: { Book , Chapter } ;
2
- use mdbook:: errors:: Error ;
3
- use mdbook:: preprocess:: { CmdPreprocessor , Preprocessor , PreprocessorContext } ;
4
- use mdbook:: BookItem ;
5
- use once_cell:: sync:: Lazy ;
6
- use regex:: { Captures , Regex } ;
7
- use semver:: { Version , VersionReq } ;
8
- use std:: collections:: BTreeMap ;
9
- use std:: io;
10
- use std:: path:: PathBuf ;
11
- use std:: process;
12
-
13
- mod std_links;
14
-
15
- /// The Regex for rules like `r[foo]`.
16
- static RULE_RE : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"(?m)^r\[([^]]+)]$" ) . unwrap ( ) ) ;
17
-
18
- /// The Regex for the syntax for blockquotes that have a specific CSS class,
19
- /// like `> [!WARNING]`.
20
- static ADMONITION_RE : Lazy < Regex > = Lazy :: new ( || {
21
- Regex :: new ( r"(?m)^ *> \[!(?<admon>[^]]+)\]\n(?<blockquote>(?: *> .*\n)+)" ) . unwrap ( )
22
- } ) ;
23
-
24
1
fn main ( ) {
25
2
let mut args = std:: env:: args ( ) . skip ( 1 ) ;
26
3
match args. next ( ) . as_deref ( ) {
@@ -35,161 +12,10 @@ fn main() {
35
12
None => { }
36
13
}
37
14
38
- let preprocessor = Spec :: new ( ) ;
15
+ let preprocessor = mdbook_spec :: Spec :: new ( ) ;
39
16
40
- if let Err ( e) = handle_preprocessing ( & preprocessor) {
17
+ if let Err ( e) = mdbook_spec :: handle_preprocessing ( & preprocessor) {
41
18
eprintln ! ( "{}" , e) ;
42
- process:: exit ( 1 ) ;
43
- }
44
- }
45
-
46
- fn handle_preprocessing ( pre : & dyn Preprocessor ) -> Result < ( ) , Error > {
47
- let ( ctx, book) = CmdPreprocessor :: parse_input ( io:: stdin ( ) ) ?;
48
-
49
- let book_version = Version :: parse ( & ctx. mdbook_version ) ?;
50
- let version_req = VersionReq :: parse ( mdbook:: MDBOOK_VERSION ) ?;
51
-
52
- if !version_req. matches ( & book_version) {
53
- eprintln ! (
54
- "warning: The {} plugin was built against version {} of mdbook, \
55
- but we're being called from version {}",
56
- pre. name( ) ,
57
- mdbook:: MDBOOK_VERSION ,
58
- ctx. mdbook_version
59
- ) ;
60
- }
61
-
62
- let processed_book = pre. run ( & ctx, book) ?;
63
- serde_json:: to_writer ( io:: stdout ( ) , & processed_book) ?;
64
-
65
- Ok ( ( ) )
66
- }
67
-
68
- struct Spec {
69
- /// Whether or not warnings should be errors (set by SPEC_DENY_WARNINGS
70
- /// environment variable).
71
- deny_warnings : bool ,
72
- }
73
-
74
- impl Spec {
75
- pub fn new ( ) -> Spec {
76
- Spec {
77
- deny_warnings : std:: env:: var ( "SPEC_DENY_WARNINGS" ) . as_deref ( ) == Ok ( "1" ) ,
78
- }
79
- }
80
-
81
- /// Converts lines that start with `r[…]` into a "rule" which has special
82
- /// styling and can be linked to.
83
- fn rule_definitions (
84
- & self ,
85
- chapter : & Chapter ,
86
- found_rules : & mut BTreeMap < String , ( PathBuf , PathBuf ) > ,
87
- ) -> String {
88
- let source_path = chapter. source_path . clone ( ) . unwrap_or_default ( ) ;
89
- let path = chapter. path . clone ( ) . unwrap_or_default ( ) ;
90
- RULE_RE
91
- . replace_all ( & chapter. content , |caps : & Captures | {
92
- let rule_id = & caps[ 1 ] ;
93
- if let Some ( ( old, _) ) =
94
- found_rules. insert ( rule_id. to_string ( ) , ( source_path. clone ( ) , path. clone ( ) ) )
95
- {
96
- let message = format ! (
97
- "rule `{rule_id}` defined multiple times\n \
98
- First location: {old:?}\n \
99
- Second location: {source_path:?}"
100
- ) ;
101
- if self . deny_warnings {
102
- panic ! ( "error: {message}" ) ;
103
- } else {
104
- eprintln ! ( "warning: {message}" ) ;
105
- }
106
- }
107
- format ! (
108
- "<div class=\" rule\" id=\" {rule_id}\" >\
109
- <a class=\" rule-link\" href=\" #{rule_id}\" >[{rule_id}]</a>\
110
- </div>\n "
111
- )
112
- } )
113
- . to_string ( )
114
- }
115
-
116
- /// Generates link references to all rules on all pages, so you can easily
117
- /// refer to rules anywhere in the book.
118
- fn auto_link_references (
119
- & self ,
120
- chapter : & Chapter ,
121
- found_rules : & BTreeMap < String , ( PathBuf , PathBuf ) > ,
122
- ) -> String {
123
- let current_path = chapter. path . as_ref ( ) . unwrap ( ) . parent ( ) . unwrap ( ) ;
124
- let definitions: String = found_rules
125
- . iter ( )
126
- . map ( |( rule_id, ( _, path) ) | {
127
- let relative = pathdiff:: diff_paths ( path, current_path) . unwrap ( ) ;
128
- format ! ( "[{rule_id}]: {}#{rule_id}\n " , relative. display( ) )
129
- } )
130
- . collect ( ) ;
131
- format ! (
132
- "{}\n \
133
- {definitions}",
134
- chapter. content
135
- )
136
- }
137
-
138
- /// Converts blockquotes with special headers into admonitions.
139
- ///
140
- /// The blockquote should look something like:
141
- ///
142
- /// ```
143
- /// > [!WARNING]
144
- /// > ...
145
- /// ```
146
- ///
147
- /// This will add a `<div class="warning">` around the blockquote so that
148
- /// it can be styled differently. Any text between the brackets that can
149
- /// be a CSS class is valid. The actual styling needs to be added in a CSS
150
- /// file.
151
- fn admonitions ( & self , chapter : & Chapter ) -> String {
152
- ADMONITION_RE
153
- . replace_all ( & chapter. content , |caps : & Captures | {
154
- let lower = caps[ "admon" ] . to_lowercase ( ) ;
155
- format ! (
156
- "<div class=\" {lower}\" >\n \n {}\n \n </div>\n " ,
157
- & caps[ "blockquote" ]
158
- )
159
- } )
160
- . to_string ( )
161
- }
162
- }
163
-
164
- impl Preprocessor for Spec {
165
- fn name ( & self ) -> & str {
166
- "nop-preprocessor"
167
- }
168
-
169
- fn run ( & self , _ctx : & PreprocessorContext , mut book : Book ) -> Result < Book , Error > {
170
- let mut found_rules = BTreeMap :: new ( ) ;
171
- book. for_each_mut ( |item| {
172
- let BookItem :: Chapter ( ch) = item else {
173
- return ;
174
- } ;
175
- if ch. is_draft_chapter ( ) {
176
- return ;
177
- }
178
- ch. content = self . rule_definitions ( & ch, & mut found_rules) ;
179
- ch. content = self . admonitions ( & ch) ;
180
- ch. content = std_links:: std_links ( & ch) ;
181
- } ) ;
182
- // This is a separate pass because it relies on the modifications of
183
- // the previous passes.
184
- book. for_each_mut ( |item| {
185
- let BookItem :: Chapter ( ch) = item else {
186
- return ;
187
- } ;
188
- if ch. is_draft_chapter ( ) {
189
- return ;
190
- }
191
- ch. content = self . auto_link_references ( & ch, & found_rules) ;
192
- } ) ;
193
- Ok ( book)
19
+ std:: process:: exit ( 1 ) ;
194
20
}
195
21
}
0 commit comments