Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: correctly number chapters #58

Merged
merged 1 commit into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ mod tests {
fmt::{self, Write},
fs,
io::{self, Read, Seek},
iter,
path::{Path, PathBuf},
str::FromStr,
};
Expand Down Expand Up @@ -282,14 +281,33 @@ mod tests {
self
}

pub fn chapter(mut self, chapter: Chapter) -> Self {
let Chapter { chapter } = chapter;
for chapter in
iter::once(&chapter).chain(chapter.sub_items.iter().filter_map(|item| match item {
BookItem::Chapter(chapter) => Some(chapter),
_ => None,
}))
{
pub fn chapter(mut self, Chapter { mut chapter }: Chapter) -> Self {
use mdbook::book::SectionNumber;
let number = (self.book.book.sections.iter())
.filter(
|item| matches!(item, BookItem::Chapter(chapter) if chapter.number.is_some()),
)
.count();
chapter.number = Some(SectionNumber(vec![number as u32]));
let mut chapters = vec![&mut chapter];
while let Some(chapter) = chapters.pop() {
let number = &chapter.number;
for (idx, chapter) in chapter
.sub_items
.iter_mut()
.filter_map(|item| match item {
BookItem::Chapter(chapter) => Some(chapter),
_ => None,
})
.enumerate()
{
if let Some(number) = number {
let mut number = number.clone();
number.push(idx as u32 + 1);
chapter.number = Some(number);
}
chapters.push(chapter);
}
if let Some(path) = &chapter.path {
let path = self.book.source_dir().join(path);
if let Some(parent) = path.parent() {
Expand Down
98 changes: 54 additions & 44 deletions src/preprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,48 +363,6 @@ impl<'book> Preprocessor<'book> {
})
}

fn update_heading<'b>(
&mut self,
chapter: &Chapter,
level: HeadingLevel,
id: Option<&'b str>,
mut classes: Vec<&'b str>,
) -> Option<(HeadingLevel, Option<&'b str>, Vec<&'b str>)> {
const PANDOC_UNNUMBERED_CLASS: &str = "unnumbered";
const PANDOC_UNLISTED_CLASS: &str = "unlisted";

if level != HeadingLevel::H1
&& (self.ctx.pandoc)
.enable_extension(pandoc::Extension::Attributes)
.is_available()
{
classes.push(PANDOC_UNNUMBERED_CLASS);
classes.push(PANDOC_UNLISTED_CLASS);
}

let shift_smaller = |level| {
use HeadingLevel::*;
match level {
H1 => Some(H2),
H2 => Some(H3),
H3 => Some(H4),
H4 => Some(H5),
H5 => Some(H6),
H6 => None,
}
};
let Some(level) = iter::successors(Some(level), |level| shift_smaller(*level))
.nth(chapter.parent_names.len())
else {
log::warn!(
"Heading (level {level}) converted to paragraph in chapter: {}",
chapter.name
);
return None;
};
Some((level, id, classes))
}

fn make_kebab_case(s: &str) -> String {
const SEPARATORS: &[char] = &['_', '/', '.', '&', '?', '='];
s
Expand Down Expand Up @@ -487,6 +445,7 @@ struct PreprocessChapter<'book, 'preprocessor> {
chapter: &'book Chapter,
parser: Peekable<pulldown_cmark::Parser<'book, 'book>>,
start_tags: Vec<pulldown_cmark::Tag<'book>>,
encountered_h1: bool,
}

impl<'book, 'preprocessor> PreprocessChapter<'book, 'preprocessor> {
Expand All @@ -509,7 +468,59 @@ impl<'book, 'preprocessor> PreprocessChapter<'book, 'preprocessor> {
chapter,
parser: pulldown_cmark::Parser::new_ext(&chapter.content, PARSER_OPTIONS).peekable(),
start_tags: Default::default(),
encountered_h1: false,
}
}

fn update_heading<'b>(
&mut self,
level: HeadingLevel,
id: Option<&'b str>,
mut classes: Vec<&'b str>,
) -> Option<(HeadingLevel, Option<&'b str>, Vec<&'b str>)> {
const PANDOC_UNNUMBERED_CLASS: &str = "unnumbered";
const PANDOC_UNLISTED_CLASS: &str = "unlisted";

if (self.preprocessor.ctx.pandoc)
.enable_extension(pandoc::Extension::Attributes)
.is_available()
{
if let HeadingLevel::H1 = level {
// Number the first H1 in each numbered chapter, mirroring mdBook
if self.encountered_h1 {
classes.push(PANDOC_UNNUMBERED_CLASS);
classes.push(PANDOC_UNLISTED_CLASS);
} else if self.chapter.number.is_none() {
classes.push(PANDOC_UNNUMBERED_CLASS);
}
self.encountered_h1 = true;
} else {
classes.push(PANDOC_UNNUMBERED_CLASS);
classes.push(PANDOC_UNLISTED_CLASS);
}
}

let shift_smaller = |level| {
use HeadingLevel::*;
match level {
H1 => Some(H2),
H2 => Some(H3),
H3 => Some(H4),
H4 => Some(H5),
H5 => Some(H6),
H6 => None,
}
};
let Some(level) = iter::successors(Some(level), |level| shift_smaller(*level))
.nth(self.chapter.parent_names.len())
else {
log::warn!(
"Heading (level {level}) converted to paragraph in chapter: {}",
self.chapter.name
);
return None;
};
Some((level, id, classes))
}
}

Expand Down Expand Up @@ -549,8 +560,7 @@ impl<'book> Iterator for PreprocessChapter<'book, '_> {
Tag::Table(alignment)
}
Tag::Heading(level, id, classes) => self
.preprocessor
.update_heading(self.chapter, level, id, classes)
.update_heading(level, id, classes)
.map(|(level, id, classes)| {
if id.is_some() || !classes.is_empty() {
// pandoc does not support `header_attributes` with commonmark
Expand Down
4 changes: 2 additions & 2 deletions src/snapshots/mdbook_pandoc__tests__cargo_book.snap
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ expression: logs
WARN mdbook_pandoc::preprocess: Unable to normalize link '../../reference/attributes/codegen.html#the-target_feature-attribute' in chapter 'Appendix: Glossary': Unable to canonicalize path: $ROOT/src/appendix/../../reference/attributes/codegen.html: No such file or directory (os error 2)
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__commands__cargomd__option-cargo---offline'
on page 277 undefined on input line 19240.
on page 277 undefined on input line 19241.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__commands__cargo-buildmd__option-cargo-build---keep-going'
on page 281 undefined on input line 19477.
on page 281 undefined on input line 19478.
[WARNING] [makePDF] LaTeX Warning: There were undefined references.
INFO mdbook_pandoc::pandoc::renderer: Wrote output to book/pdf/book.pdf

8 changes: 4 additions & 4 deletions src/snapshots/mdbook_pandoc__tests__rust_book.snap
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ expression: logs
WARN mdbook_pandoc::preprocess: Unable to normalize link '../std/index.html' in chapter 'C - Derivable Traits': Unable to canonicalize path: $ROOT/src/../std/index.html: No such file or directory (os error 2)
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__ch15-02-derefmd__following-the-pointer-to-the-value-with-the-dereference-operator'
on page 188 undefined on input line 10883.
on page 188 undefined on input line 10886.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__ch06-02-matchmd__the-match-control-flow-operator'
on page 589 undefined on input line 33735.
on page 589 undefined on input line 33738.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__ch13-01-closuresmd__moving-captured-values-out-of-the-closure-and-the-fn-traits'
on page 630 undefined on input line 36105.
on page 630 undefined on input line 36108.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__ch04-01-what-is-ownershipmd__ways-variables-and-data-interact-clone'
on page 680 undefined on input line 38922.
on page 680 undefined on input line 38925.
[WARNING] [makePDF] LaTeX Warning: There were undefined references.
[WARNING] Missing character: There is no 🚨 (U+1F6A8) (U+1F6A8) in font NotoSerif/B:mode=node;scri
[WARNING] Missing character: There is no 👍 (U+1F44D) (U+1F44D) in font NotoSansMono:mode=node;scr
Expand Down
28 changes: 14 additions & 14 deletions src/snapshots/mdbook_pandoc__tests__rust_reference.snap
Original file line number Diff line number Diff line change
Expand Up @@ -196,46 +196,46 @@ expression: logs
WARN mdbook_pandoc::preprocess: Unable to normalize link '../alloc/alloc/trait.GlobalAlloc.html' in chapter 'The Rust runtime': Unable to canonicalize path: $ROOT/src/../alloc/alloc/trait.GlobalAlloc.html: No such file or directory (os error 2)
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__type-layoutmd__the-default-representation'
on page 84 undefined on input line 5417.
on page 84 undefined on input line 5418.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__unit-only-enum' on
page 84 undefined on input line 5436.
page 84 undefined on input line 5437.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__unit-only-enum' on
page 85 undefined on input line 5532.
page 85 undefined on input line 5533.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__field-less-enum' on
page 85 undefined on input line 5553.
page 85 undefined on input line 5554.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__statementsmd__let-else-restriction' on page
159 undefined on input line 10699.
159 undefined on input line 10700.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__unit-only-enum' on
page 185 undefined on input line 12670.
page 185 undefined on input line 12671.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__field-less-enum' on
page 185 undefined on input line 12673.
page 185 undefined on input line 12674.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__type-layoutmd__the-rust-representation' on
page 262 undefined on input line 18031.
page 262 undefined on input line 18032.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__type-layoutmd__the-rust-representation' on
page 262 undefined on input line 18062.
page 262 undefined on input line 18063.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__field-less-enum' on
page 266 undefined on input line 18293.
page 266 undefined on input line 18294.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__field-less-enum' on
page 266 undefined on input line 18306.
page 266 undefined on input line 18307.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__field-less-enum' on
page 266 undefined on input line 18311.
page 266 undefined on input line 18312.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__items__enumerationsmd__field-less-enum' on
page 268 undefined on input line 18419.
page 268 undefined on input line 18420.
[WARNING] [makePDF] LaTeX Warning: Hyper reference
`book__pdf__src__type-layoutmd__the-rust-representation' on
page 271 undefined on input line 18594.
page 271 undefined on input line 18595.
[WARNING] [makePDF] LaTeX Warning: There were undefined references.
[WARNING] Missing character: There is no 東 (U+6771) (U+6771) in font NotoSansMono:mode=node;scrip
[WARNING] Missing character: There is no 京 (U+4EAC) (U+4EAC) in font NotoSansMono:mode=node;scrip
Expand Down
Loading