Skip to content

Commit 64bf0da

Browse files
authored
feat(mdbook): improve mdbook generics behaviour and fix broken links (#319)
1 parent 3f3d1b7 commit 64bf0da

File tree

17 files changed

+211
-233
lines changed

17 files changed

+211
-233
lines changed

crates/lad_backends/mdbook_lad_preprocessor/src/argument_visitor.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,18 @@ impl<'a> MarkdownArgumentVisitor<'a> {
2525

2626
impl ArgumentVisitor for MarkdownArgumentVisitor<'_> {
2727
fn visit_lad_type_id(&mut self, type_id: &ladfile::LadTypeId) {
28-
let mut buffer = String::new();
29-
3028
// Write identifier<Generic1TypeIdentifier, Generic2TypeIdentifier>
31-
buffer.push_str(&self.ladfile.get_type_identifier(type_id));
29+
self.buffer.text(self.ladfile.get_type_identifier(type_id));
3230
if let Some(generics) = self.ladfile.get_type_generics(type_id) {
33-
buffer.push('<');
31+
self.buffer.text('<');
3432
for (i, generic) in generics.iter().enumerate() {
33+
self.visit_lad_type_id(&generic.type_id);
3534
if i > 0 {
36-
buffer.push_str(", ");
35+
self.buffer.text(", ");
3736
}
38-
buffer.push_str(&self.ladfile.get_type_identifier(&generic.type_id));
3937
}
40-
buffer.push('>');
38+
self.buffer.text('>');
4139
}
42-
43-
self.buffer.text(buffer);
4440
}
4541

4642
fn walk_option(&mut self, inner: &ladfile::LadArgumentKind) {

crates/lad_backends/mdbook_lad_preprocessor/src/lib.rs

Lines changed: 89 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![allow(missing_docs)]
33

44
use mdbook::{errors::Error, preprocess::Preprocessor};
5+
use sections::Section;
56
mod argument_visitor;
67
mod markdown;
78
mod sections;
@@ -10,6 +11,46 @@ const LAD_EXTENSION: &str = "lad.json";
1011

1112
pub struct LADPreprocessor;
1213

14+
impl LADPreprocessor {
15+
/// Checks if a chapter is a LAD file.
16+
fn is_lad_file(chapter: &mdbook::book::Chapter) -> bool {
17+
chapter
18+
.source_path
19+
.as_ref()
20+
.and_then(|a| a.file_name())
21+
.map(|s| s.to_string_lossy().ends_with(LAD_EXTENSION))
22+
.unwrap_or(false)
23+
}
24+
25+
/// Process a chapter that is a LAD file.
26+
///
27+
/// `parent` is the optional parent chapter reference,
28+
/// and `chapter_index` is the index of the chapter among its siblings.
29+
fn process_lad_chapter(
30+
chapter: &mdbook::book::Chapter,
31+
parent: Option<&mdbook::book::Chapter>,
32+
chapter_index: usize,
33+
) -> Result<mdbook::book::Chapter, Error> {
34+
let chapter_title = chapter.name.trim_end_matches(".lad.json").to_owned();
35+
let ladfile = ladfile::parse_lad_file(&chapter.content)
36+
.map_err(|e| Error::new(e).context("Failed to parse LAD file"))?;
37+
log::debug!(
38+
"Parsed LAD file: {}",
39+
serde_json::to_string_pretty(&ladfile).unwrap_or_default()
40+
);
41+
let new_chapter = Section::Summary {
42+
ladfile: &ladfile,
43+
title: Some(chapter_title),
44+
}
45+
.into_chapter(parent, chapter_index);
46+
log::debug!(
47+
"New chapter: {}",
48+
serde_json::to_string_pretty(&new_chapter).unwrap_or_default()
49+
);
50+
Ok(new_chapter)
51+
}
52+
}
53+
1354
impl Preprocessor for LADPreprocessor {
1455
fn name(&self) -> &str {
1556
"lad-preprocessor"
@@ -20,62 +61,69 @@ impl Preprocessor for LADPreprocessor {
2061
_ctx: &mdbook::preprocess::PreprocessorContext,
2162
mut book: mdbook::book::Book,
2263
) -> mdbook::errors::Result<mdbook::book::Book> {
23-
let mut errors = Vec::default();
64+
let mut errors = Vec::new();
2465

66+
// first replace children in parents
2567
book.for_each_mut(|item| {
26-
if let mdbook::BookItem::Chapter(chapter) = item {
27-
let is_lad_chapter = chapter
28-
.source_path
29-
.as_ref()
30-
.and_then(|a| a.file_name())
31-
.is_some_and(|a| a.to_string_lossy().ends_with(LAD_EXTENSION));
68+
if let mdbook::BookItem::Chapter(parent) = item {
69+
// First, collect the indices and new chapters for LAD file chapters.
70+
let replacements: Vec<(usize, mdbook::book::Chapter)> = parent
71+
.sub_items
72+
.iter()
73+
.enumerate()
74+
.filter_map(|(idx, item)| {
75+
if let mdbook::BookItem::Chapter(chapter) = item {
76+
if LADPreprocessor::is_lad_file(chapter) {
77+
match LADPreprocessor::process_lad_chapter(
78+
chapter,
79+
Some(parent),
80+
idx,
81+
) {
82+
Ok(new_chapter) => return Some((idx, new_chapter)),
83+
Err(e) => {
84+
errors.push(e);
85+
return None;
86+
}
87+
}
88+
}
89+
}
90+
None
91+
})
92+
.collect();
93+
94+
// Then, apply the replacements.
95+
for (idx, new_chapter) in replacements {
96+
if let mdbook::BookItem::Chapter(chapter) = &mut parent.sub_items[idx] {
97+
*chapter = new_chapter;
98+
}
99+
}
100+
}
101+
});
32102

33-
if !is_lad_chapter {
34-
log::debug!("Skipping non-LAD chapter: {:?}", chapter.source_path);
35-
log::trace!(
36-
"Non-LAD chapter: {}",
37-
serde_json::to_string_pretty(&chapter).unwrap_or_default()
38-
);
103+
// then try match items themselves
104+
book.for_each_mut(|item| {
105+
if let mdbook::BookItem::Chapter(chapter) = item {
106+
if !LADPreprocessor::is_lad_file(chapter) {
39107
return;
40108
}
41109

42-
let chapter_title = chapter.name.clone();
43-
44-
let lad = match ladfile::parse_lad_file(&chapter.content) {
45-
Ok(lad) => lad,
110+
let new_chapter = match LADPreprocessor::process_lad_chapter(chapter, None, 0) {
111+
Ok(new_chapter) => new_chapter,
46112
Err(e) => {
47-
log::debug!("Failed to parse LAD file: {:?}", e);
48-
errors.push(Error::new(e).context("Failed to parse LAD file"));
113+
errors.push(e);
49114
return;
50115
}
51116
};
52117

53-
log::debug!(
54-
"Parsed LAD file: {}",
55-
serde_json::to_string_pretty(&lad).unwrap_or_default()
56-
);
57-
58-
let sections = sections::lad_file_to_sections(&lad, Some(chapter_title));
59-
60-
let new_chapter = sections::section_to_chapter(
61-
sections,
62-
Some(chapter),
63-
chapter.parent_names.clone(),
64-
chapter.number.clone(),
65-
None,
66-
None,
67-
);
68-
69-
// serialize chapter to json
70-
log::debug!(
71-
"New chapter: {}",
72-
serde_json::to_string_pretty(&new_chapter).unwrap_or_default()
73-
);
74-
75118
*chapter = new_chapter;
76119
}
77120
});
78121

122+
log::debug!(
123+
"Book after LAD processing: {}",
124+
serde_json::to_string_pretty(&book).unwrap_or_default()
125+
);
126+
79127
if !errors.is_empty() {
80128
// return on first error
81129
for error in errors {

crates/lad_backends/mdbook_lad_preprocessor/src/markdown.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::borrow::Cow;
22

3-
/// Takes the first n characters from the markdown, without splitting any formatting
3+
/// Takes the first n characters from the markdown, without splitting any formatting.
44
pub(crate) fn markdown_substring(markdown: &str, length: usize) -> &str {
55
if markdown.len() <= length {
66
return markdown;

0 commit comments

Comments
 (0)