mdbook-bibtex 0.1.0

Adds support for bibliographies to mdbook. Backed by hayagriva, supporting all CSL citation styles.
Documentation
use anyhow::{Result, anyhow};
use itertools::Itertools;
use mdbook_preprocessor::{Preprocessor, PreprocessorContext, book::Book};

use config::{BibliographyLocation, Config};

mod bib;
mod config;
#[cfg(test)]
mod tests;

pub struct BibtexPreprocessor;

impl Preprocessor for BibtexPreprocessor {
    fn name(&self) -> &str {
        "bibtex-preprocessor"
    }

    fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
        let config: Config = (&ctx.config).try_into()?;

        match config.biblio_location {
            BibliographyLocation::Footnotes | BibliographyLocation::Chapter => {
                let mut errs = vec![];
                book.for_each_chapter_mut(|chapter| {
                    let mut f = || -> Result<()> {
                        let mut pass = bib::BibPass::new(&config)?;
                        pass.collect_citations(chapter)?;
                        let pass = pass.render()?;
                        pass.replace_citations(chapter);
                        pass.add_chapter_bib(chapter);
                        Ok(())
                    };

                    if let Err(e) = f() {
                        errs.push(e);
                    }
                });
                if !errs.is_empty() {
                    Err(anyhow!(errs.into_iter().map(|e| e.to_string()).join("\n")))?;
                }
            }
            BibliographyLocation::Global => {
                let mut pass = bib::BibPass::new(&config)?;

                let mut errs = vec![];
                book.chapters().for_each(|chapter| {
                    if let Err(e) = pass.collect_citations(chapter) {
                        errs.push(e);
                    }
                });
                if !errs.is_empty() {
                    Err(anyhow!(errs.into_iter().map(|e| e.to_string()).join("\n")))?;
                }

                let pass = pass.render()?;
                book.for_each_chapter_mut(|chapter| {
                    pass.replace_citations(chapter);
                });
                pass.add_global_bib(&mut book);
            }
        }

        Ok(book)
    }

    fn supports_renderer(&self, renderer: &str) -> Result<bool> {
        Ok(renderer != "not-supported")
    }
}