use super::prelude::*;
use crate::prelude::*;
mod directory_template;
use crate::index::DirIndex;
use crate::mdbook::traits::*;
pub use directory_template::*;
pub struct SimpleDirPreprocessor<T>
where
T: JournalLoaderTrait,
{
journal: Journal<T>,
}
impl<T> SimpleDirPreprocessor<T>
where
T: JournalLoaderTrait,
{
pub fn new<J>(journal: J) -> Self
where
J: Into<Journal<T>>,
{
Self {
journal: journal.into(),
}
}
}
impl<T> Preprocessor for SimpleDirPreprocessor<T>
where
T: JournalLoaderTrait,
{
fn name(&self) -> &str {
"Simple Directory Preprocessor"
}
fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
let journal = &self.journal;
let writing = &mut book;
let mut section = writing
.max_section_number()
.and_then(|s| s.root())
.unwrap_or_default();
for topic in journal.each_topic() {
let mut entries = journal.entries_for_topic(&topic.name())?;
entries.sort_by(|a, b| b.created_at().cmp(a.created_at()));
section.increment();
let chapter = topic_chapter(topic, &entries, section.clone())?;
writing.push_item(chapter);
}
Ok(book)
}
}
fn topic_chapter(topic: &Topic, entries: &[Entry], section: SectionNumber) -> Result<BookItem> {
let index = DirIndex::for_topic(entries, topic)?;
let parents = vec![topic.name().to_owned()];
let mut path = topic.virtual_root().clone();
path.push("README.md");
let sub_items = if index.is_empty() {
vec![]
} else {
build_sub_items(
topic,
&index[topic.name()],
parents,
section.advance_level(),
)?
};
Ok(BookItem::Chapter(Chapter {
sub_items,
name: topic.name().to_owned(),
path: Some(path),
number: Some(section),
..Default::default()
}))
}
fn build_sub_items(
topic: &Topic,
index: &DirIndex,
parents: Vec<String>,
mut section: SectionNumber,
) -> Result<Vec<BookItem>> {
Ok(if index.is_leaf() {
index
.entries()
.map(|entry| {
section.increment();
entry_chapter(topic, entry, parents.clone(), section.clone())
})
.collect()
} else {
index
.children()
.try_fold(Vec::new(), |mut vec, (name, dir)| {
let name = name.to_owned();
let mut new_parents = parents.clone();
new_parents.push(name.clone());
let mut path: PathBuf = new_parents.join("/").into();
section.increment();
path.push("README.md");
let content = build_content(dir, &path, topic)?;
vec.push(BookItem::Chapter(Chapter {
sub_items: build_sub_items(topic, dir, new_parents, section.advance_level())?,
parent_names: parents.clone(),
number: Some(section.clone()),
name,
path: Some(path),
content,
..Default::default()
}));
Ok(vec)
})?
})
}
fn build_content(dir: &DirIndex, path: &Path, topic: &Topic) -> Result<String> {
if !dir.is_leaf() {
return Ok(String::new());
}
let entries: Vec<_> = dir.entries().collect();
let data = &serde_json::json!({
"path": path,
"entries": entries,
});
topic
.directory_template()
.generate_content(data)
.with_context(|| format!("Generating contant with data:\n{data:#?}"))
}
fn entry_chapter(
topic: &Topic,
entry: &Entry,
parents: Vec<String>,
section: SectionNumber,
) -> BookItem {
let name = match entry.meta_value(&"title") {
Some(MetaValue::String(title)) => title.to_owned(),
_ => String::from("Untitled"),
};
let content = entry.content().to_owned();
BookItem::Chapter(Chapter {
name,
content,
number: Some(section),
path: topic.virtual_path(entry).ok(),
source_path: entry.file_location().cloned(),
parent_names: parents,
..Default::default()
})
}