diff --git a/src/bib/bibliography.rs b/src/bib/bibliography.rs index 62a1b6f..f1048b7 100644 --- a/src/bib/bibliography.rs +++ b/src/bib/bibliography.rs @@ -1,17 +1,17 @@ -use std::{io, path::Path}; +use std::io; -use hayagriva::Entry; +use hayagriva::{io::from_biblatex_str, Entry}; -use crate::{utils::find_root, walk::Walker}; +use crate::walk::Walker; -pub fn get_bib_entries>(path: Option

) -> io::Result> { - let bibtex_content = match path { - Some(path) => Walker::new(path)?.filter_extensions(&["bib", "bibtex"]), - _ => Walker::new(".")?.filter_extensions(&["bib", "bibtex"]), - } - .map(std::fs::read_to_string) - .collect::>()?; +pub fn get_bib_entries() -> io::Result> { + let bibtex_content = Walker::new(".")? + .max_nesting(5) + .filter_extensions(&["bib", "bibtex"]) + .map(std::fs::read_to_string) + .collect::>()?; // TODO: Handle error(s) - Ok(hayagriva::io::from_biblatex_str(&bibtex_content).unwrap()) + let entries = from_biblatex_str(&bibtex_content).unwrap(); + Ok(entries) } diff --git a/src/bib/mod.rs b/src/bib/mod.rs index 5de9bda..1608e74 100644 --- a/src/bib/mod.rs +++ b/src/bib/mod.rs @@ -1,5 +1,5 @@ mod bibliography; -mod csl; +// mod csl; pub use bibliography::get_bib_entries; -pub use csl::get_csl; +// pub use csl::get_csl; diff --git a/src/builder.rs b/src/builder.rs index f8cc5e5..caaf8a9 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,6 +1,8 @@ use std::path::PathBuf; -use crate::manifest::BuilderManifest; +use hayagriva::Entry; + +use crate::{bib, manifest::BuilderManifest}; const DEFAULT_LOCALE: &str = "en_US"; @@ -13,6 +15,7 @@ pub struct Builder { pub(crate) build_dir: Option, pub(crate) locale: String, pub(crate) add_title: bool, + pub(crate) bib: Vec, } impl Default for Builder { @@ -22,6 +25,7 @@ impl Default for Builder { build_dir: None, locale: DEFAULT_LOCALE.to_string(), add_title: false, + bib: Vec::new(), } } } @@ -33,6 +37,7 @@ impl Builder { locale: manifest.locale.clone().unwrap_or(DEFAULT_LOCALE.into()), build_dir: manifest.build_dir.clone(), add_title: manifest.add_title.unwrap_or(false), + bib: bib::get_bib_entries().unwrap(), } } diff --git a/src/lib.rs b/src/lib.rs index c3e647f..30f864f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ //! ``` mod author; +mod bib; mod builder; mod date; mod document; diff --git a/src/pdf/mod.rs b/src/pdf/mod.rs index f8a9c46..811b3b4 100644 --- a/src/pdf/mod.rs +++ b/src/pdf/mod.rs @@ -11,10 +11,12 @@ use std::{ fs, io::{self, Write}, path::PathBuf, + sync::{Arc, Mutex}, time::SystemTime, }; -use jotdown::{Parser, Render}; +use hayagriva::style::{Citation, Database, ChicagoAuthorDate}; +use jotdown::{Container, Event, Parser, Render}; use rayon::prelude::*; use super::Builder; @@ -101,7 +103,11 @@ impl Builder { /// .write_latex(&document, &mut std::io::stdout()) /// .unwrap(); /// ``` - pub fn write_latex(&self, document: &Document, mut w: W) -> Result<(), PdfError> { + pub fn write_latex<'s, W: Write>( + &self, + document: &'s Document, + mut w: W, + ) -> Result<(), PdfError> { let mut inner = || -> Result<(), PdfError> { writeln!(w, r"\documentclass{{{}}}", document.document_type.as_ref())?; @@ -137,6 +143,8 @@ impl Builder { writeln!(w, "}}")?; } + let db = Arc::new(Mutex::new(Database::from_entries(self.bib.iter()))); + let bib_style = Arc::new(Mutex::new(ChicagoAuthorDate::new())); writeln!(w, r"\begin{{document}}")?; if self.add_title { @@ -147,15 +155,50 @@ impl Builder { .texts .par_iter() .try_fold_with(Vec::new(), |mut buf, text| { + let mut cite = None; + let citations = |event: Event<'s>| -> Event<'s> { + match event { + Event::Start(Container::Span, ref attrs) => { + if let Some(key) = attrs.get("cite") { + let mut db = db.lock().unwrap(); + // TODO: Should avoid this clone + if let Some(record) = + db.records.clone().get(key.to_string().as_str()) + { + let citation = db.citation( + &mut *bib_style.lock().unwrap(), + &[Citation::new(record.entry, None)], + ); + cite = Some(citation.display.value); + } + } + } + Event::Str(ref s) if cite.is_some() && s == "@" => { + return Event::Str(cite.take().unwrap().into()) + } + _ => {} + } + event + }; latex::Renderer::default() .number_sections(self.number_sections) - .write(Parser::new(text), &mut buf)?; + .write(Parser::new(text).map(citations), &mut buf)?; Ok(buf) }) .collect::>, PdfError>>()? .into_iter() .try_for_each(|s| w.write_all(&s))?; + writeln!(w, r"\begin{{itemize}}")?; + for reference in db.lock().unwrap().bibliography(&ChicagoAuthorDate::new(), None) { + write!(w, r"\item")?; + if let Some(prefix) = reference.prefix { + write!(w, r"[{}]", prefix.value.replace('[', "\\["))?; + } + writeln!(w, r" {}", reference.display.value)?; + } + writeln!(w, r"\end{{itemize}}")?; + writeln!(w, r"\end{{document}}")?; Ok(()) diff --git a/src/walk.rs b/src/walk.rs index 2a347f2..ef5c5ed 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -61,6 +61,12 @@ impl Walker { }) } + /// Sets the maximum nesting level. + pub fn max_nesting(mut self, max_nesting: usize) -> Self { + self.max_nesting = max_nesting; + self + } + /// Returns a new iterator that only yields paths with the given extensions. pub fn filter_extensions(self, extensions: &'static [&'static str]) -> FilteredWalker { FilteredWalker {