Skip to content

Commit 6e7ab3e

Browse files
ehusstraviscross
authored andcommitted
Add the ability for rules to be specified in link definitions
This adds the ability to link to rules from a link definition. For example: ```markdown See [this rule]. [this rule]: expr.array ``` This will convert `[this rule]` to point to the link of the file for that rule. This is somewhat hacky, as parsing markdown with regex is unwise (and this is intentionally incomplete), and could maybe be done more efficiently.
1 parent 49a9c8c commit 6e7ab3e

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

mdbook-spec/src/lib.rs

+33
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ static ADMONITION_RE: Lazy<Regex> = Lazy::new(|| {
2424
Regex::new(r"(?m)^ *> \[!(?<admon>[^]]+)\]\n(?<blockquote>(?: *>.*\n)+)").unwrap()
2525
});
2626

27+
/// A primitive regex to find link reference definitions.
28+
static MD_LINK_REFERENCE_DEFINITION: Lazy<Regex> =
29+
Lazy::new(|| Regex::new(r"(?m)^\[(?<label>[^]]+)]: (?<dest>.*)").unwrap());
30+
2731
pub fn handle_preprocessing() -> Result<(), Error> {
2832
let pre = Spec::new(None)?;
2933
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
@@ -114,6 +118,34 @@ impl Spec {
114118
Ok(Spec { rust_root })
115119
}
116120

121+
/// Converts link reference definitions that point to a rule to the correct link.
122+
///
123+
/// For example:
124+
/// ```markdown
125+
/// See [this rule].
126+
///
127+
/// [this rule]: expr.array
128+
/// ```
129+
///
130+
/// This will convert the `[this rule]` definition to point to the actual link.
131+
fn rule_link_references(&self, chapter: &Chapter, rules: &Rules) -> String {
132+
let current_path = chapter.path.as_ref().unwrap().parent().unwrap();
133+
MD_LINK_REFERENCE_DEFINITION
134+
.replace_all(&chapter.content, |caps: &Captures<'_>| {
135+
let dest = &caps["dest"];
136+
if let Some((_source_path, path)) = rules.def_paths.get(dest) {
137+
let label = &caps["label"];
138+
let relative = pathdiff::diff_paths(path, current_path).unwrap();
139+
// Adjust paths for Windows.
140+
let relative = relative.display().to_string().replace('\\', "/");
141+
format!("[{label}]: {relative}#r-{dest}")
142+
} else {
143+
caps.get(0).unwrap().as_str().to_string()
144+
}
145+
})
146+
.to_string()
147+
}
148+
117149
/// Generates link references to all rules on all pages, so you can easily
118150
/// refer to rules anywhere in the book.
119151
fn auto_link_references(&self, chapter: &Chapter, rules: &Rules) -> String {
@@ -255,6 +287,7 @@ impl Preprocessor for Spec {
255287
return;
256288
}
257289
ch.content = self.admonitions(&ch, &mut diag);
290+
ch.content = self.rule_link_references(&ch, &rules);
258291
ch.content = self.auto_link_references(&ch, &rules);
259292
ch.content = self.render_rule_definitions(&ch.content, &tests, &git_ref);
260293
if ch.name == "Test summary" {

0 commit comments

Comments
 (0)