So their advice is to make each section a (separate) chapter on its own, that is, starting the first heading with "#" instead of "##"? So a book would have a few hundred chapters -- or sub-chapters, as they call it? That is a strange system, not really logical, and different from other authoring systems like LaTeX or AsciiDoctor. While it fixes the issue introduced with mdbook v0.5, it has the effect that our former section headings use now a very large font, and for my book now the section headings extend often to more than a single line, due to the large font.
I tried it with the mdbook preprocessor below, which is just a modification of an example shipped with mdbook.
//! This is a demonstration of an mdBook preprocessor which parses markdown
//! and removes any instances of emphasis.
use mdbook_preprocessor::book::{Book, Chapter};
use mdbook_preprocessor::errors::Result;
use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
use pulldown_cmark::HeadingLevel;
use pulldown_cmark::Tag::Heading;
use pulldown_cmark::{Event, Parser, Tag, TagEnd};
use std::io;
fn main() {
let mut args = std::env::args().skip(1);
match args.next().as_deref() {
Some("supports") => {
// Supports all renderers.
return;
}
Some(arg) => {
eprintln!("unknown argument: {arg}");
std::process::exit(1);
}
None => {}
}
if let Err(e) = handle_preprocessing() {
eprintln!("{e}");
std::process::exit(1);
}
}
struct RemoveEmphasis;
impl Preprocessor for RemoveEmphasis {
fn name(&self) -> &str {
"remove-emphasis"
}
fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
let mut total = 0;
book.for_each_chapter_mut(|ch| match remove_emphasis(&mut total, ch) {
Ok(s) => ch.content = s,
Err(e) => eprintln!("failed to process chapter: {e:?}"),
});
eprintln!("removed {total} emphasis");
Ok(book)
}
}
// ANCHOR: remove_emphasis
fn remove_emphasis(num_removed_items: &mut usize, chapter: &mut Chapter) -> Result<String> {
let mut buf = String::with_capacity(chapter.content.len());
let parser = Parser::new(&chapter.content);
let new_v: Vec<_> = parser
.into_iter()
.map(|item| match item {
Event::Start(Heading {
level,
id,
classes,
attrs,
}) => {
let l = match level {
HeadingLevel::H1 => HeadingLevel::H1,
HeadingLevel::H2 => HeadingLevel::H1,
HeadingLevel::H3 => HeadingLevel::H2,
HeadingLevel::H4 => HeadingLevel::H3,
HeadingLevel::H5 => HeadingLevel::H4,
HeadingLevel::H6 => HeadingLevel::H5,
//_ => level,
};
Event::Start(Heading {
level: l,
id,
classes,
attrs,
})
}
other => other,
})
.collect();
Ok(pulldown_cmark_to_cmark::cmark(new_v.into_iter(), &mut buf).map(|_| buf)?)
}
// ANCHOR_END: remove_emphasis
pub fn handle_preprocessing() -> Result<()> {
let pre = RemoveEmphasis;
let (ctx, book) = mdbook_preprocessor::parse_input(io::stdin())?;
let processed_book = pre.run(&ctx, book)?;
serde_json::to_writer(io::stdout(), &processed_book)?;
Ok(())
}
[package]
name = "mdfix"
version = "0.1.0"
edition = "2024"
[dependencies]
#mdbook = { version = "0.5.2" }
mdbook-preprocessor = "0.5.2"
pulldown-cmark = { version = "0.13.3", default-features = false }
pulldown-cmark-to-cmark = "22.0.0"
serde_json = "1.0.149"
[EDIT]
I think for my book the best option is to use
[output.html]
sidebar-header-nav = false
to obtain a plain TOC structure as before mdbook v0.5.