1use anyhow::{Result, anyhow};
2use itertools::Itertools;
3use mdbook_preprocessor::{Preprocessor, PreprocessorContext, book::Book};
4
5use config::{BibliographyLocation, Config};
6
7mod bib;
8mod config;
9#[cfg(test)]
10mod tests;
11
12pub struct BibtexPreprocessor;
13
14impl Preprocessor for BibtexPreprocessor {
15 fn name(&self) -> &str {
16 "bibtex-preprocessor"
17 }
18
19 fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
20 let config: Config = (&ctx.config).try_into()?;
21
22 match config.biblio_location {
23 BibliographyLocation::Footnotes | BibliographyLocation::Chapter => {
24 let mut errs = vec![];
25 book.for_each_chapter_mut(|chapter| {
26 let mut f = || -> Result<()> {
27 let mut pass = bib::BibPass::new(&config)?;
28 pass.collect_citations(chapter)?;
29 let pass = pass.render()?;
30 pass.replace_citations(chapter);
31 pass.add_chapter_bib(chapter);
32 Ok(())
33 };
34
35 if let Err(e) = f() {
36 errs.push(e);
37 }
38 });
39 if !errs.is_empty() {
40 Err(anyhow!(errs.into_iter().map(|e| e.to_string()).join("\n")))?;
41 }
42 }
43 BibliographyLocation::Global => {
44 let mut pass = bib::BibPass::new(&config)?;
45
46 let mut errs = vec![];
47 book.chapters().for_each(|chapter| {
48 if let Err(e) = pass.collect_citations(chapter) {
49 errs.push(e);
50 }
51 });
52 if !errs.is_empty() {
53 Err(anyhow!(errs.into_iter().map(|e| e.to_string()).join("\n")))?;
54 }
55
56 let pass = pass.render()?;
57 book.for_each_chapter_mut(|chapter| {
58 pass.replace_citations(chapter);
59 });
60 pass.add_global_bib(&mut book);
61 }
62 }
63
64 Ok(book)
65 }
66
67 fn supports_renderer(&self, renderer: &str) -> Result<bool> {
68 Ok(renderer != "not-supported")
69 }
70}