|
| 1 | +//! This is a demonstration of an mdBook preprocessor which parses markdown |
| 2 | +//! and removes any instances of emphasis. |
| 3 | +
|
| 4 | +use mdbook::book::{Book, Chapter}; |
| 5 | +use mdbook::errors::Error; |
| 6 | +use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; |
| 7 | +use mdbook::BookItem; |
| 8 | +use pulldown_cmark::{Event, Parser, Tag, TagEnd}; |
| 9 | +use std::io; |
| 10 | + |
| 11 | +fn main() { |
| 12 | + let mut args = std::env::args().skip(1); |
| 13 | + match args.next().as_deref() { |
| 14 | + Some("supports") => { |
| 15 | + // Supports all renderers. |
| 16 | + return; |
| 17 | + } |
| 18 | + Some(arg) => { |
| 19 | + eprintln!("unknown argument: {arg}"); |
| 20 | + std::process::exit(1); |
| 21 | + } |
| 22 | + None => {} |
| 23 | + } |
| 24 | + |
| 25 | + if let Err(e) = handle_preprocessing() { |
| 26 | + eprintln!("{}", e); |
| 27 | + std::process::exit(1); |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +struct RemoveEmphasis; |
| 32 | + |
| 33 | +impl Preprocessor for RemoveEmphasis { |
| 34 | + fn name(&self) -> &str { |
| 35 | + "remove-emphasis" |
| 36 | + } |
| 37 | + |
| 38 | + fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> { |
| 39 | + let mut total = 0; |
| 40 | + book.for_each_mut(|item| { |
| 41 | + let BookItem::Chapter(ch) = item else { |
| 42 | + return; |
| 43 | + }; |
| 44 | + if ch.is_draft_chapter() { |
| 45 | + return; |
| 46 | + } |
| 47 | + match remove_emphasis(&mut total, ch) { |
| 48 | + Ok(s) => ch.content = s, |
| 49 | + Err(e) => eprintln!("failed to process chapter: {e:?}"), |
| 50 | + } |
| 51 | + }); |
| 52 | + eprintln!("removed {total} emphasis"); |
| 53 | + Ok(book) |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +// ANCHOR: remove_emphasis |
| 58 | +fn remove_emphasis(num_removed_items: &mut usize, chapter: &mut Chapter) -> Result<String, Error> { |
| 59 | + let mut buf = String::with_capacity(chapter.content.len()); |
| 60 | + |
| 61 | + let events = Parser::new(&chapter.content).filter(|e| match e { |
| 62 | + Event::Start(Tag::Emphasis) | Event::Start(Tag::Strong) => { |
| 63 | + *num_removed_items += 1; |
| 64 | + false |
| 65 | + } |
| 66 | + Event::End(TagEnd::Emphasis) | Event::End(TagEnd::Strong) => false, |
| 67 | + _ => true, |
| 68 | + }); |
| 69 | + |
| 70 | + Ok(pulldown_cmark_to_cmark::cmark(events, &mut buf).map(|_| buf)?) |
| 71 | +} |
| 72 | +// ANCHOR_END: remove_emphasis |
| 73 | + |
| 74 | +pub fn handle_preprocessing() -> Result<(), Error> { |
| 75 | + let pre = RemoveEmphasis; |
| 76 | + let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; |
| 77 | + |
| 78 | + let processed_book = pre.run(&ctx, book)?; |
| 79 | + serde_json::to_writer(io::stdout(), &processed_book)?; |
| 80 | + |
| 81 | + Ok(()) |
| 82 | +} |
0 commit comments