Drinks - DRY Links Proof of Concept
Uses links dict in drinks.txt for general links storage Replaces `{{#drink somedrink}}` placeholders with value from the dict
This commit is contained in:
parent
5a35144d4f
commit
5e6bacf545
|
@ -83,6 +83,8 @@ impl BookBuilder {
|
|||
|
||||
self.write_book_toml()?;
|
||||
|
||||
self.write_drinks_txt()?;
|
||||
|
||||
match MDBook::load(&self.root) {
|
||||
Ok(book) => Ok(book),
|
||||
Err(e) => {
|
||||
|
@ -108,6 +110,18 @@ impl BookBuilder {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_drinks_txt(&self) -> Result<()> {
|
||||
debug!("Writing drinks.txt");
|
||||
let drinks_txt = self.root.join("drinks.txt");
|
||||
let entry = "hello: https://world.org";
|
||||
|
||||
File::create(drinks_txt)
|
||||
.with_context(|| "Couldn't create drinks.txt")?
|
||||
.write_all(&entry.as_bytes())
|
||||
.with_context(|| "Unable to write config to drinks.txt")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_across_theme(&self) -> Result<()> {
|
||||
debug!("Copying theme");
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ use topological_sort::TopologicalSort;
|
|||
|
||||
use crate::errors::*;
|
||||
use crate::preprocess::{
|
||||
CmdPreprocessor, IndexPreprocessor, LinkPreprocessor, Preprocessor, PreprocessorContext,
|
||||
CmdPreprocessor, DrinkPreprocessor, IndexPreprocessor, LinkPreprocessor, Preprocessor, PreprocessorContext,
|
||||
};
|
||||
use crate::renderer::{CmdRenderer, HtmlHandlebars, MarkdownRenderer, RenderContext, Renderer};
|
||||
use crate::utils;
|
||||
|
@ -432,7 +432,7 @@ fn determine_renderers(config: &Config) -> Vec<Box<dyn Renderer>> {
|
|||
renderers
|
||||
}
|
||||
|
||||
const DEFAULT_PREPROCESSORS: &[&str] = &["links", "index"];
|
||||
const DEFAULT_PREPROCESSORS: &[&str] = &["drinks", "links", "index"];
|
||||
|
||||
fn is_default_preprocessor(pre: &dyn Preprocessor) -> bool {
|
||||
let name = pre.name();
|
||||
|
@ -533,6 +533,7 @@ fn determine_preprocessors(config: &Config) -> Result<Vec<Box<dyn Preprocessor>>
|
|||
names.sort();
|
||||
for name in names {
|
||||
let preprocessor: Box<dyn Preprocessor> = match name.as_str() {
|
||||
"drinks" => Box::new(DrinkPreprocessor::new()),
|
||||
"links" => Box::new(LinkPreprocessor::new()),
|
||||
"index" => Box::new(IndexPreprocessor::new()),
|
||||
_ => {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
use crate::errors::*;
|
||||
|
||||
use super::{Preprocessor, PreprocessorContext};
|
||||
use crate::book::{Book, BookItem, Chapter};
|
||||
use regex::{Captures, Regex};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::fs::File;
|
||||
use std::collections::HashMap;
|
||||
|
||||
const SPLITTER: char = ':';
|
||||
|
||||
type Dict=HashMap<String, String>;
|
||||
|
||||
/// DRY Links - A preprocessor for using centralized links collection:
|
||||
///
|
||||
/// - `{{# drink}}` - Insert link from the collection
|
||||
#[derive(Default)]
|
||||
pub struct DrinkPreprocessor;
|
||||
|
||||
impl DrinkPreprocessor {
|
||||
pub(crate) const NAME: &'static str = "drinks";
|
||||
|
||||
/// Create a new `DrinkPreprocessor`.
|
||||
pub fn new() -> Self {
|
||||
DrinkPreprocessor
|
||||
}
|
||||
|
||||
fn replace_drinks(&self, chapter: &mut Chapter, dict: &Dict) -> Result<String, Error> {
|
||||
static RE: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(
|
||||
r"(?x) # insignificant whitespace mode
|
||||
\{\{\s* # link opening parens and whitespace
|
||||
\#(drink) # drink marker
|
||||
\s+ # separating whitespace
|
||||
(?<drink>[A-z0-9_-]+) # drink name
|
||||
\}\} # link closing parens",
|
||||
).unwrap()
|
||||
});
|
||||
|
||||
static NODRINK: Lazy<String> = Lazy::new(|| {
|
||||
"deadbeef".to_string()
|
||||
});
|
||||
|
||||
let res = RE.replace_all(&chapter.content, |caps: &Captures<'_>| {
|
||||
dict.get(&caps["drink"]).unwrap_or(&NODRINK)
|
||||
});
|
||||
Ok(res.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Preprocessor for DrinkPreprocessor {
|
||||
fn name(&self) -> &str {
|
||||
Self::NAME
|
||||
}
|
||||
|
||||
fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
|
||||
let path = ctx.root.join("drinks.txt");
|
||||
|
||||
let drinks: Dict = {
|
||||
let reader = BufReader::new(File::open(path).expect("Cannot open drinks dictionary"));
|
||||
reader.lines().filter_map(|l| {
|
||||
l.expect("Cannot read line in drinks dictionary").split_once(SPLITTER).map(|(name, value)| (name.trim().to_owned(), value.trim().to_owned()))
|
||||
}).collect::<HashMap<_, _>>()
|
||||
};
|
||||
|
||||
book.for_each_mut(|section: &mut BookItem| {
|
||||
if let BookItem::Chapter(ref mut ch) = *section {
|
||||
ch.content = self
|
||||
.replace_drinks(ch, &drinks)
|
||||
.expect("Error converting drinks into links for chapter");
|
||||
}
|
||||
});
|
||||
|
||||
Ok(book)
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
//! Book preprocessing.
|
||||
|
||||
pub use self::cmd::CmdPreprocessor;
|
||||
pub use self::drinks::DrinkPreprocessor;
|
||||
pub use self::index::IndexPreprocessor;
|
||||
pub use self::links::LinkPreprocessor;
|
||||
|
||||
mod cmd;
|
||||
mod drinks;
|
||||
mod index;
|
||||
mod links;
|
||||
|
||||
|
|
Loading…
Reference in New Issue