mdbook_preprocessor/
lib.rs

1//! Library to assist implementing an mdbook preprocessor.
2//!
3//! This library is used to implement a
4//! [preprocessor](https://rust-lang.github.io/mdBook/for_developers/preprocessors.html)
5//! for [mdBook](https://rust-lang.github.io/mdBook/). See the linked chapter
6//! for more information on how to implement a preprocessor.
7
8use anyhow::Context;
9use mdbook_core::book::Book;
10use mdbook_core::config::Config;
11use mdbook_core::errors::Result;
12use serde::{Deserialize, Serialize};
13use std::cell::RefCell;
14use std::collections::HashMap;
15use std::io::Read;
16use std::path::PathBuf;
17
18pub use mdbook_core::MDBOOK_VERSION;
19pub use mdbook_core::book;
20pub use mdbook_core::config;
21pub use mdbook_core::errors;
22
23/// An operation which is run immediately after loading a book into memory and
24/// before it gets rendered.
25///
26/// Types that implement the `Preprocessor` trait can be used with
27/// [`MDBook::with_preprocessor`] to programmatically add preprocessors.
28///
29/// [`MDBook::with_preprocessor`]: https://docs.rs/mdbook-driver/latest/mdbook_driver/struct.MDBook.html#method.with_preprocessor
30pub trait Preprocessor {
31    /// Get the `Preprocessor`'s name.
32    fn name(&self) -> &str;
33
34    /// Run this `Preprocessor`, allowing it to update the book before it is
35    /// given to a renderer.
36    fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book>;
37
38    /// A hint to `MDBook` whether this preprocessor is compatible with a
39    /// particular renderer.
40    ///
41    /// By default, always returns `true`.
42    fn supports_renderer(&self, _renderer: &str) -> Result<bool> {
43        Ok(true)
44    }
45}
46
47/// Extra information for a `Preprocessor` to give them more context when
48/// processing a book.
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
50#[non_exhaustive]
51pub struct PreprocessorContext {
52    /// The location of the book directory on disk.
53    pub root: PathBuf,
54    /// The book configuration (`book.toml`).
55    pub config: Config,
56    /// The `Renderer` this preprocessor is being used with.
57    pub renderer: String,
58    /// The calling `mdbook` version.
59    pub mdbook_version: String,
60    /// Internal mapping of chapter titles.
61    ///
62    /// This is used internally by mdbook to compute custom chapter titles.
63    /// This should not be used outside of mdbook's internals.
64    #[serde(skip)]
65    pub chapter_titles: RefCell<HashMap<PathBuf, String>>,
66}
67
68impl PreprocessorContext {
69    /// Create a new `PreprocessorContext`.
70    pub fn new(root: PathBuf, config: Config, renderer: String) -> Self {
71        PreprocessorContext {
72            root,
73            config,
74            renderer,
75            mdbook_version: crate::MDBOOK_VERSION.to_string(),
76            chapter_titles: RefCell::new(HashMap::new()),
77        }
78    }
79}
80
81/// Parses the input given to a preprocessor.
82pub fn parse_input<R: Read>(reader: R) -> Result<(PreprocessorContext, Book)> {
83    serde_json::from_reader(reader).with_context(|| "Unable to parse the input")
84}