From 769fd948685825fb2b885a45f52d72fddd32f33d Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Thu, 30 Aug 2018 21:31:14 +0800 Subject: [PATCH] The preprocessor trait now returns a modified book instead of editing in place --- examples/de-emphasize.rs | 120 ++++++++++++++++++++------------------- src/book/mod.rs | 38 ++++++++----- src/preprocess/index.rs | 4 +- src/preprocess/links.rs | 4 +- src/preprocess/mod.rs | 2 +- tests/testing.rs | 4 +- 6 files changed, 94 insertions(+), 78 deletions(-) diff --git a/examples/de-emphasize.rs b/examples/de-emphasize.rs index 0e2ae983..88c1b3a4 100644 --- a/examples/de-emphasize.rs +++ b/examples/de-emphasize.rs @@ -14,45 +14,7 @@ use std::env::{args, args_os}; use std::ffi::OsString; use std::process; -struct Deemphasize; - -impl Preprocessor for Deemphasize { - fn name(&self) -> &str { - "md-links-to-html-links" - } - - fn run(&self, _ctx: &PreprocessorContext, book: &mut Book) -> Result<()> { - eprintln!("Running '{}' preprocessor", self.name()); - let mut res: Option<_> = None; - let mut num_removed_items = 0; - book.for_each_mut(|item: &mut BookItem| { - if let Some(Err(_)) = res { - return; - } - if let BookItem::Chapter(ref mut chapter) = *item { - eprintln!("{}: processing chapter '{}'", self.name(), chapter.name); - res = Some( - match Deemphasize::remove_emphasis(&mut num_removed_items, chapter) { - Ok(md) => { - chapter.content = md; - Ok(()) - } - Err(err) => Err(err), - }, - ); - } - }); - eprintln!( - "{}: removed {} events from markdown stream.", - self.name(), - num_removed_items - ); - match res { - Some(res) => res, - None => Ok(()), - } - } -} +const NAME: &str = "md-links-to-html-links"; fn do_it(book: OsString) -> Result<()> { let mut book = MDBook::load(book)?; @@ -71,24 +33,66 @@ fn main() { } } -impl Deemphasize { - fn remove_emphasis(num_removed_items: &mut i32, chapter: &mut Chapter) -> Result { - let mut buf = String::with_capacity(chapter.content.len()); - let events = Parser::new(&chapter.content).filter(|e| { - let should_keep = match *e { - Event::Start(Tag::Emphasis) - | Event::Start(Tag::Strong) - | Event::End(Tag::Emphasis) - | Event::End(Tag::Strong) => false, - _ => true, - }; - if !should_keep { - *num_removed_items += 1; - } - should_keep - }); - cmark(events, &mut buf, None) - .map(|_| buf) - .map_err(|err| Error::from(format!("Markdown serialization failed: {}", err))) +struct Deemphasize; + +impl Preprocessor for Deemphasize { + fn name(&self) -> &str { + NAME + } + + fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result { + eprintln!("Running '{}' preprocessor", self.name()); + let mut num_removed_items = 0; + + process(&mut book.sections, &mut num_removed_items)?; + + eprintln!( + "{}: removed {} events from markdown stream.", + self.name(), + num_removed_items + ); + + Ok(book) } } + +fn process<'a, I>(items: I, num_removed_items: &mut usize) -> Result<()> +where + I: IntoIterator + 'a, +{ + for item in items { + if let BookItem::Chapter(ref mut chapter) = *item { + eprintln!("{}: processing chapter '{}'", NAME, chapter.name); + + let md = remove_emphasis(num_removed_items, chapter)?; + chapter.content = md; + } + } + + Ok(()) +} + +fn remove_emphasis( + num_removed_items: &mut usize, + chapter: &mut Chapter, +) -> Result { + let mut buf = String::with_capacity(chapter.content.len()); + + let events = Parser::new(&chapter.content).filter(|e| { + let should_keep = match *e { + Event::Start(Tag::Emphasis) + | Event::Start(Tag::Strong) + | Event::End(Tag::Emphasis) + | Event::End(Tag::Strong) => false, + _ => true, + }; + if !should_keep { + *num_removed_items += 1; + } + should_keep + }); + + cmark(events, &mut buf, None).map(|_| buf).map_err(|err| { + Error::from(format!("Markdown serialization failed: {}", err)) + }) +} diff --git a/src/book/mod.rs b/src/book/mod.rs index d1ed19c4..a8f07575 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -149,23 +149,35 @@ impl MDBook { pub fn build(&self) -> Result<()> { info!("Book building has started"); - let mut preprocessed_book = self.book.clone(); - let preprocess_ctx = PreprocessorContext::new(self.root.clone(), self.config.clone()); - - for preprocessor in &self.preprocessors { - debug!("Running the {} preprocessor.", preprocessor.name()); - preprocessor.run(&preprocess_ctx, &mut preprocessed_book)?; - } - for renderer in &self.renderers { - info!("Running the {} backend", renderer.name()); - self.run_renderer(&preprocessed_book, renderer.as_ref())?; + self.execute_build_process(&**renderer)?; } Ok(()) } - fn run_renderer(&self, preprocessed_book: &Book, renderer: &Renderer) -> Result<()> { + fn execute_build_process(&self, renderer: &Renderer) -> Result<()> { + let mut preprocessed_book = self.book.clone(); + let preprocess_ctx = + PreprocessorContext::new(self.root.clone(), self.config.clone()); + + for preprocessor in &self.preprocessors { + debug!("Running the {} preprocessor.", preprocessor.name()); + preprocessed_book = + preprocessor.run(&preprocess_ctx, preprocessed_book)?; + } + + info!("Running the {} backend", renderer.name()); + self.render(&preprocessed_book, renderer)?; + + Ok(()) + } + + fn render( + &self, + preprocessed_book: &Book, + renderer: &Renderer, + ) -> Result<()> { let name = renderer.name(); let build_dir = self.build_dir_for(name); if build_dir.exists() { @@ -217,11 +229,11 @@ impl MDBook { let preprocess_context = PreprocessorContext::new(self.root.clone(), self.config.clone()); - LinkPreprocessor::new().run(&preprocess_context, &mut self.book)?; + let book = LinkPreprocessor::new().run(&preprocess_context, self.book.clone())?; // Index Preprocessor is disabled so that chapter paths continue to point to the // actual markdown files. - for item in self.iter() { + for item in book.iter() { if let BookItem::Chapter(ref ch) = *item { if !ch.path.as_os_str().is_empty() { let path = self.source_dir().join(&ch.path); diff --git a/src/preprocess/index.rs b/src/preprocess/index.rs index 0ec89b80..674f78c0 100644 --- a/src/preprocess/index.rs +++ b/src/preprocess/index.rs @@ -22,7 +22,7 @@ impl Preprocessor for IndexPreprocessor { "index" } - fn run(&self, ctx: &PreprocessorContext, book: &mut Book) -> Result<()> { + fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result { let source_dir = ctx.root.join(&ctx.config.book.src); book.for_each_mut(|section: &mut BookItem| { if let BookItem::Chapter(ref mut ch) = *section { @@ -37,7 +37,7 @@ impl Preprocessor for IndexPreprocessor { } }); - Ok(()) + Ok(book) } } diff --git a/src/preprocess/links.rs b/src/preprocess/links.rs index 696919df..48af3ba8 100644 --- a/src/preprocess/links.rs +++ b/src/preprocess/links.rs @@ -27,7 +27,7 @@ impl Preprocessor for LinkPreprocessor { "links" } - fn run(&self, ctx: &PreprocessorContext, book: &mut Book) -> Result<()> { + fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result { let src_dir = ctx.root.join(&ctx.config.book.src); book.for_each_mut(|section: &mut BookItem| { @@ -43,7 +43,7 @@ impl Preprocessor for LinkPreprocessor { } }); - Ok(()) + Ok(book) } } diff --git a/src/preprocess/mod.rs b/src/preprocess/mod.rs index 57a18f0c..555768b3 100644 --- a/src/preprocess/mod.rs +++ b/src/preprocess/mod.rs @@ -36,5 +36,5 @@ 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: &mut Book) -> Result<()>; + fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result; } diff --git a/tests/testing.rs b/tests/testing.rs index 48e02892..84a9e21c 100644 --- a/tests/testing.rs +++ b/tests/testing.rs @@ -39,9 +39,9 @@ fn mdbook_runs_preprocessors() { "dummy" } - fn run(&self, _ctx: &PreprocessorContext, _book: &mut Book) -> Result<()> { + fn run(&self, _ctx: &PreprocessorContext, book: Book) -> Result { *self.0.lock().unwrap() = true; - Ok(()) + Ok(book) } }