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_book_toml()?;
|
||||||
|
|
||||||
|
self.write_drinks_txt()?;
|
||||||
|
|
||||||
match MDBook::load(&self.root) {
|
match MDBook::load(&self.root) {
|
||||||
Ok(book) => Ok(book),
|
Ok(book) => Ok(book),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -108,6 +110,18 @@ impl BookBuilder {
|
||||||
Ok(())
|
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<()> {
|
fn copy_across_theme(&self) -> Result<()> {
|
||||||
debug!("Copying theme");
|
debug!("Copying theme");
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use topological_sort::TopologicalSort;
|
||||||
|
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::preprocess::{
|
use crate::preprocess::{
|
||||||
CmdPreprocessor, IndexPreprocessor, LinkPreprocessor, Preprocessor, PreprocessorContext,
|
CmdPreprocessor, DrinkPreprocessor, IndexPreprocessor, LinkPreprocessor, Preprocessor, PreprocessorContext,
|
||||||
};
|
};
|
||||||
use crate::renderer::{CmdRenderer, HtmlHandlebars, MarkdownRenderer, RenderContext, Renderer};
|
use crate::renderer::{CmdRenderer, HtmlHandlebars, MarkdownRenderer, RenderContext, Renderer};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
@ -432,7 +432,7 @@ fn determine_renderers(config: &Config) -> Vec<Box<dyn Renderer>> {
|
||||||
renderers
|
renderers
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_PREPROCESSORS: &[&str] = &["links", "index"];
|
const DEFAULT_PREPROCESSORS: &[&str] = &["drinks", "links", "index"];
|
||||||
|
|
||||||
fn is_default_preprocessor(pre: &dyn Preprocessor) -> bool {
|
fn is_default_preprocessor(pre: &dyn Preprocessor) -> bool {
|
||||||
let name = pre.name();
|
let name = pre.name();
|
||||||
|
@ -533,6 +533,7 @@ fn determine_preprocessors(config: &Config) -> Result<Vec<Box<dyn Preprocessor>>
|
||||||
names.sort();
|
names.sort();
|
||||||
for name in names {
|
for name in names {
|
||||||
let preprocessor: Box<dyn Preprocessor> = match name.as_str() {
|
let preprocessor: Box<dyn Preprocessor> = match name.as_str() {
|
||||||
|
"drinks" => Box::new(DrinkPreprocessor::new()),
|
||||||
"links" => Box::new(LinkPreprocessor::new()),
|
"links" => Box::new(LinkPreprocessor::new()),
|
||||||
"index" => Box::new(IndexPreprocessor::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.
|
//! Book preprocessing.
|
||||||
|
|
||||||
pub use self::cmd::CmdPreprocessor;
|
pub use self::cmd::CmdPreprocessor;
|
||||||
|
pub use self::drinks::DrinkPreprocessor;
|
||||||
pub use self::index::IndexPreprocessor;
|
pub use self::index::IndexPreprocessor;
|
||||||
pub use self::links::LinkPreprocessor;
|
pub use self::links::LinkPreprocessor;
|
||||||
|
|
||||||
mod cmd;
|
mod cmd;
|
||||||
|
mod drinks;
|
||||||
mod index;
|
mod index;
|
||||||
mod links;
|
mod links;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue