mirror of
https://github.com/rust-lang/mdBook.git
synced 2025-12-27 10:16:09 -05:00
Add an iterator over chapters
This adds the `Book::chapters` iterator (and `for_each_chapter_mut`) to iterate over non-draft chapters. This is a common pattern I keep encountering, and I figure it might simplify things. It runs a little risk that callers may not be properly handling every item type, but I think it should be ok.
This commit is contained in:
@@ -46,6 +46,14 @@ impl Book {
|
||||
}
|
||||
}
|
||||
|
||||
/// A depth-first iterator over each [`Chapter`], skipping draft chapters.
|
||||
pub fn chapters(&self) -> impl Iterator<Item = &Chapter> {
|
||||
self.iter().filter_map(|item| match item {
|
||||
BookItem::Chapter(ch) if !ch.is_draft_chapter() => Some(ch),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Recursively apply a closure to each item in the book, allowing you to
|
||||
/// mutate them.
|
||||
///
|
||||
@@ -61,6 +69,26 @@ impl Book {
|
||||
for_each_mut(&mut func, &mut self.items);
|
||||
}
|
||||
|
||||
/// Recursively apply a closure to each non-draft chapter in the book,
|
||||
/// allowing you to mutate them.
|
||||
pub fn for_each_chapter_mut<F>(&mut self, mut func: F)
|
||||
where
|
||||
F: FnMut(&mut Chapter),
|
||||
{
|
||||
for_each_mut(
|
||||
&mut |item| {
|
||||
let BookItem::Chapter(ch) = item else {
|
||||
return;
|
||||
};
|
||||
if ch.is_draft_chapter() {
|
||||
return;
|
||||
}
|
||||
func(ch)
|
||||
},
|
||||
&mut self.items,
|
||||
);
|
||||
}
|
||||
|
||||
/// Append a `BookItem` to the `Book`.
|
||||
pub fn push_item<I: Into<BookItem>>(&mut self, item: I) -> &mut Self {
|
||||
self.items.push(item.into());
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use anyhow::{Context, Result};
|
||||
use mdbook_core::book::BookItem;
|
||||
use mdbook_core::utils;
|
||||
use mdbook_renderer::{RenderContext, Renderer};
|
||||
use std::fs;
|
||||
@@ -33,17 +32,13 @@ impl Renderer for MarkdownRenderer {
|
||||
}
|
||||
|
||||
trace!("markdown render");
|
||||
for item in book.iter() {
|
||||
if let BookItem::Chapter(ref ch) = *item {
|
||||
if !ch.is_draft_chapter() {
|
||||
for ch in book.chapters() {
|
||||
utils::fs::write_file(
|
||||
&ctx.destination,
|
||||
ch.path.as_ref().expect("Checked path exists before"),
|
||||
ch.content.as_bytes(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fs::create_dir_all(destination)
|
||||
.with_context(|| "Unexpected error when constructing destination path")?;
|
||||
|
||||
@@ -459,13 +459,7 @@ impl Renderer for HtmlHandlebars {
|
||||
utils::fs::write_file(destination, "CNAME", format!("{cname}\n").as_bytes())?;
|
||||
}
|
||||
|
||||
let chapters: Vec<_> = book
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
BookItem::Chapter(ch) if !ch.is_draft_chapter() => Some(ch),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let chapters: Vec<_> = book.chapters().collect();
|
||||
for (i, ch) in chapters.iter().enumerate() {
|
||||
let previous = (i != 0).then(|| chapters[i - 1]);
|
||||
let next = (i != chapters.len() - 1).then(|| chapters[i + 1]);
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::static_files::StaticFiles;
|
||||
use crate::theme::searcher;
|
||||
use anyhow::{Context, Result, bail};
|
||||
use elasticlunr::{Index, IndexBuilder};
|
||||
use mdbook_core::book::{Book, BookItem, Chapter};
|
||||
use mdbook_core::book::{Book, Chapter};
|
||||
use mdbook_core::config::{Search, SearchChapterSettings};
|
||||
use mdbook_core::utils;
|
||||
use mdbook_markdown::HtmlRenderOptions;
|
||||
@@ -43,11 +43,7 @@ pub(super) fn create_files(
|
||||
let chapter_configs = sort_search_config(&search_config.chapter);
|
||||
validate_chapter_config(&chapter_configs, book)?;
|
||||
|
||||
for item in book.iter() {
|
||||
let chapter = match item {
|
||||
BookItem::Chapter(ch) if !ch.is_draft_chapter() => ch,
|
||||
_ => continue,
|
||||
};
|
||||
for chapter in book.chapters() {
|
||||
if let Some(path) = settings_path(chapter) {
|
||||
let chapter_settings = get_chapter_settings(&chapter_configs, path);
|
||||
if !chapter_settings.enable.unwrap_or(true) {
|
||||
@@ -349,11 +345,8 @@ fn validate_chapter_config(
|
||||
) -> Result<()> {
|
||||
for (path, _) in chapter_configs {
|
||||
let found = book
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
BookItem::Chapter(ch) if !ch.is_draft_chapter() => settings_path(ch),
|
||||
_ => None,
|
||||
})
|
||||
.chapters()
|
||||
.filter_map(|ch| settings_path(ch))
|
||||
.any(|source_path| source_path.starts_with(path));
|
||||
if !found {
|
||||
bail!(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! This is a demonstration of an mdBook preprocessor which parses markdown
|
||||
//! and removes any instances of emphasis.
|
||||
|
||||
use mdbook_preprocessor::book::{Book, BookItem, Chapter};
|
||||
use mdbook_preprocessor::book::{Book, Chapter};
|
||||
use mdbook_preprocessor::errors::Result;
|
||||
use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
|
||||
use pulldown_cmark::{Event, Parser, Tag, TagEnd};
|
||||
@@ -36,17 +36,9 @@ impl Preprocessor for RemoveEmphasis {
|
||||
|
||||
fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
|
||||
let mut total = 0;
|
||||
book.for_each_mut(|item| {
|
||||
let BookItem::Chapter(ch) = item else {
|
||||
return;
|
||||
};
|
||||
if ch.is_draft_chapter() {
|
||||
return;
|
||||
}
|
||||
match remove_emphasis(&mut total, ch) {
|
||||
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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Preprocessor for the mdBook guide.
|
||||
|
||||
use mdbook_preprocessor::book::{Book, BookItem};
|
||||
use mdbook_preprocessor::book::Book;
|
||||
use mdbook_preprocessor::errors::Result;
|
||||
use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
|
||||
use semver::{Version, VersionReq};
|
||||
@@ -53,13 +53,7 @@ fn insert_version(book: &mut Book) {
|
||||
let manifest: toml::Value = toml::from_str(&manifest_contents).unwrap();
|
||||
let version = manifest["package"]["version"].as_str().unwrap();
|
||||
const MARKER: &str = "{{ mdbook-version }}";
|
||||
book.for_each_mut(|item| {
|
||||
let BookItem::Chapter(ch) = item else {
|
||||
return;
|
||||
};
|
||||
if ch.is_draft_chapter() {
|
||||
return;
|
||||
}
|
||||
book.for_each_chapter_mut(|ch| {
|
||||
if ch.content.contains(MARKER) {
|
||||
ch.content = ch.content.replace(MARKER, version);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user