1
1
//! Handling for rule identifiers.
2
2
3
3
use crate :: Spec ;
4
- use mdbook:: book:: Chapter ;
4
+ use mdbook:: book:: Book ;
5
+ use mdbook:: BookItem ;
5
6
use once_cell:: sync:: Lazy ;
6
7
use regex:: { Captures , Regex } ;
7
8
use std:: collections:: BTreeMap ;
@@ -10,33 +11,65 @@ use std::path::PathBuf;
10
11
/// The Regex for rules like `r[foo]`.
11
12
static RULE_RE : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"(?m)^r\[([^]]+)]$" ) . unwrap ( ) ) ;
12
13
14
+ /// The set of rules defined in the reference.
15
+ #[ derive( Default ) ]
16
+ pub struct Rules {
17
+ /// A mapping from a rule identifier to a tuple of `(source_path, path)`.
18
+ ///
19
+ /// `source_path` is the path to the markdown source file relative to the
20
+ /// `SUMMARY.md`.
21
+ ///
22
+ /// `path` is the same as `source_path`, except filenames like `README.md`
23
+ /// are translated to `index.md`. Which to use depends on if you are
24
+ /// trying to access the source files (`source_path`), or creating links
25
+ /// in the output (`path`).
26
+ pub def_paths : BTreeMap < String , ( PathBuf , PathBuf ) > ,
27
+ }
28
+
13
29
impl Spec {
30
+ /// Collects all rule definitions in the book.
31
+ pub fn collect_rules ( & self , book : & Book ) -> Rules {
32
+ let mut rules = Rules :: default ( ) ;
33
+ for item in book. iter ( ) {
34
+ let BookItem :: Chapter ( ch) = item else {
35
+ continue ;
36
+ } ;
37
+ if ch. is_draft_chapter ( ) {
38
+ continue ;
39
+ }
40
+ RULE_RE
41
+ . captures_iter ( & ch. content )
42
+ . for_each ( |caps : Captures < ' _ > | {
43
+ let rule_id = & caps[ 1 ] ;
44
+ let source_path = ch. source_path . clone ( ) . unwrap_or_default ( ) ;
45
+ let path = ch. path . clone ( ) . unwrap_or_default ( ) ;
46
+ if let Some ( ( old, _) ) = rules
47
+ . def_paths
48
+ . insert ( rule_id. to_string ( ) , ( source_path. clone ( ) , path. clone ( ) ) )
49
+ {
50
+ let message = format ! (
51
+ "rule `{rule_id}` defined multiple times\n \
52
+ First location: {old:?}\n \
53
+ Second location: {source_path:?}"
54
+ ) ;
55
+ if self . deny_warnings {
56
+ panic ! ( "error: {message}" ) ;
57
+ } else {
58
+ eprintln ! ( "warning: {message}" ) ;
59
+ }
60
+ }
61
+ } ) ;
62
+ }
63
+
64
+ rules
65
+ }
66
+
14
67
/// Converts lines that start with `r[…]` into a "rule" which has special
15
68
/// styling and can be linked to.
16
- pub fn rule_definitions (
17
- & self ,
18
- chapter : & Chapter ,
19
- found_rules : & mut BTreeMap < String , ( PathBuf , PathBuf ) > ,
20
- ) -> String {
21
- let source_path = chapter. source_path . clone ( ) . unwrap_or_default ( ) ;
22
- let path = chapter. path . clone ( ) . unwrap_or_default ( ) ;
69
+ pub fn render_rule_definitions ( & self , content : & str ) -> String {
23
70
RULE_RE
24
- . replace_all ( & chapter . content , |caps : & Captures < ' _ > | {
71
+ . replace_all ( content, |caps : & Captures < ' _ > | {
25
72
let rule_id = & caps[ 1 ] ;
26
- if let Some ( ( old, _) ) =
27
- found_rules. insert ( rule_id. to_string ( ) , ( source_path. clone ( ) , path. clone ( ) ) )
28
- {
29
- let message = format ! (
30
- "rule `{rule_id}` defined multiple times\n \
31
- First location: {old:?}\n \
32
- Second location: {source_path:?}"
33
- ) ;
34
- if self . deny_warnings {
35
- panic ! ( "error: {message}" ) ;
36
- } else {
37
- eprintln ! ( "warning: {message}" ) ;
38
- }
39
- }
40
73
format ! (
41
74
"<div class=\" rule\" id=\" r-{rule_id}\" >\
42
75
<a class=\" rule-link\" href=\" #r-{rule_id}\" >[{rule_id}]</a>\
0 commit comments