From d0a6d7c87c89ef274db282ca8502ce40f80d0d26 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Thu, 30 Aug 2018 22:33:33 +0800 Subject: [PATCH] Users can now manually specify whether a preprocessor should run for a renderer --- src/book/mod.rs | 79 +++++++++++++++++++++++++++++++++++++++++-- src/config.rs | 12 +++++++ src/preprocess/mod.rs | 8 +++++ 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/book/mod.rs b/src/book/mod.rs index 1d261c9f..ce45282b 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -156,6 +156,7 @@ impl MDBook { Ok(()) } + /// Run the entire build process for a particular `Renderer`. fn execute_build_process(&self, renderer: &Renderer) -> Result<()> { let mut preprocessed_book = self.book.clone(); let preprocess_ctx = PreprocessorContext::new(self.root.clone(), @@ -163,9 +164,11 @@ impl MDBook { renderer.name().to_string()); for preprocessor in &self.preprocessors { - debug!("Running the {} preprocessor.", preprocessor.name()); - preprocessed_book = - preprocessor.run(&preprocess_ctx, preprocessed_book)?; + if preprocessor_should_run(&**preprocessor, renderer, &self.config) { + debug!("Running the {} preprocessor.", preprocessor.name()); + preprocessed_book = + preprocessor.run(&preprocess_ctx, preprocessed_book)?; + } } info!("Running the {} backend", renderer.name()); @@ -382,6 +385,23 @@ fn interpret_custom_renderer(key: &str, table: &Value) -> Box { 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)] mod tests { use super::*; @@ -484,4 +504,57 @@ mod tests { 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 { + 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); + } } diff --git a/src/config.rs b/src/config.rs index 338d7191..e3b9c0fe 100644 --- a/src/config.rs +++ b/src/config.rs @@ -209,6 +209,18 @@ impl Config { Ok(()) } + /// Get the table associated with a particular renderer. + pub fn get_renderer>(&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>(&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 { let mut cfg = Config::default(); diff --git a/src/preprocess/mod.rs b/src/preprocess/mod.rs index 7c78e058..5f59c5bf 100644 --- a/src/preprocess/mod.rs +++ b/src/preprocess/mod.rs @@ -39,4 +39,12 @@ pub trait Preprocessor { /// Run this `Preprocessor`, allowing it to update the book before it is /// given to a renderer. fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result; + + /// 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 + } }