Users can now manually specify whether a preprocessor should run for a renderer

This commit is contained in:
Michael Bryan 2018-08-30 22:33:33 +08:00
parent 995efc22d5
commit d0a6d7c87c
No known key found for this signature in database
GPG Key ID: E9C602B0D9A998DC
3 changed files with 96 additions and 3 deletions

View File

@ -156,6 +156,7 @@ impl MDBook {
Ok(()) Ok(())
} }
/// Run the entire build process for a particular `Renderer`.
fn execute_build_process(&self, renderer: &Renderer) -> Result<()> { fn execute_build_process(&self, renderer: &Renderer) -> Result<()> {
let mut preprocessed_book = self.book.clone(); let mut preprocessed_book = self.book.clone();
let preprocess_ctx = PreprocessorContext::new(self.root.clone(), let preprocess_ctx = PreprocessorContext::new(self.root.clone(),
@ -163,10 +164,12 @@ impl MDBook {
renderer.name().to_string()); renderer.name().to_string());
for preprocessor in &self.preprocessors { for preprocessor in &self.preprocessors {
if preprocessor_should_run(&**preprocessor, renderer, &self.config) {
debug!("Running the {} preprocessor.", preprocessor.name()); debug!("Running the {} preprocessor.", preprocessor.name());
preprocessed_book = preprocessed_book =
preprocessor.run(&preprocess_ctx, preprocessed_book)?; preprocessor.run(&preprocess_ctx, preprocessed_book)?;
} }
}
info!("Running the {} backend", renderer.name()); info!("Running the {} backend", renderer.name());
self.render(&preprocessed_book, renderer)?; self.render(&preprocessed_book, renderer)?;
@ -382,6 +385,23 @@ fn interpret_custom_renderer(key: &str, table: &Value) -> Box<Renderer> {
Box::new(CmdRenderer::new(key.to_string(), command.to_string())) Box::new(CmdRenderer::new(key.to_string(), command.to_string()))
} }
/// Check whether we should run a particular `Preprocessor` in combination
/// with the renderer, falling back to `Preprocessor::supports_renderer()`
/// method if the user doesn't say anything.
fn preprocessor_should_run(preprocessor: &Preprocessor, renderer: &Renderer, cfg: &Config) -> bool {
let key = format!("preprocessor.{}.renderers", preprocessor.name());
let renderer_name = renderer.name();
if let Some(Value::Array(ref explicit_renderers)) = cfg.get(&key) {
return explicit_renderers.into_iter()
.filter_map(|val| val.as_str())
.any(|name| name == renderer_name);
}
preprocessor.supports_renderer(renderer_name)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -484,4 +504,57 @@ mod tests {
assert!(got.is_err()); assert!(got.is_err());
} }
#[test]
fn config_respects_preprocessor_selection() {
let cfg_str: &'static str = r#"
[preprocessor.links]
renderers = ["html"]
"#;
let cfg = Config::from_str(cfg_str).unwrap();
// double-check that we can access preprocessor.links.renderers[0]
let html = cfg.get_preprocessor("links")
.and_then(|links| links.get("renderers"))
.and_then(|renderers| renderers.as_array())
.and_then(|renderers| renderers.get(0))
.and_then(|renderer| renderer.as_str())
.unwrap();
assert_eq!(html, "html");
let html_renderer = HtmlHandlebars::default();
let pre = LinkPreprocessor::new();
let should_run = preprocessor_should_run(&pre, &html_renderer, &cfg);
assert!(should_run);
}
struct BoolPreprocessor(bool);
impl Preprocessor for BoolPreprocessor {
fn name(&self) -> &str {
"bool-preprocessor"
}
fn run(&self, _ctx: &PreprocessorContext, _book: Book) -> Result<Book> {
unimplemented!()
}
fn supports_renderer(&self, _renderer: &str) -> bool {
self.0
}
}
#[test]
fn preprocessor_should_run_falls_back_to_supports_renderer_method() {
let cfg = Config::default();
let html = HtmlHandlebars::new();
let should_be = true;
let got = preprocessor_should_run(&BoolPreprocessor(should_be), &html, &cfg);
assert_eq!(got, should_be);
let should_be = false;
let got = preprocessor_should_run(&BoolPreprocessor(should_be), &html, &cfg);
assert_eq!(got, should_be);
}
} }

View File

@ -209,6 +209,18 @@ impl Config {
Ok(()) Ok(())
} }
/// Get the table associated with a particular renderer.
pub fn get_renderer<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
let key = format!("output.{}", index.as_ref());
self.get(&key).and_then(|v| v.as_table())
}
/// Get the table associated with a particular preprocessor.
pub fn get_preprocessor<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
let key = format!("preprocessor.{}", index.as_ref());
self.get(&key).and_then(|v| v.as_table())
}
fn from_legacy(mut table: Value) -> Config { fn from_legacy(mut table: Value) -> Config {
let mut cfg = Config::default(); let mut cfg = Config::default();

View File

@ -39,4 +39,12 @@ pub trait Preprocessor {
/// Run this `Preprocessor`, allowing it to update the book before it is /// Run this `Preprocessor`, allowing it to update the book before it is
/// given to a renderer. /// given to a renderer.
fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book>; fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book>;
/// A hint to `MDBook` whether this preprocessor is compatible with a
/// particular renderer.
///
/// By default, always returns `true`.
fn supports_renderer(&self, _renderer: &str) -> bool {
true
}
} }