1use log::info;
2use mdbook::book::Book;
3use mdbook::errors::Error;
4use mdbook::preprocess::{Preprocessor, PreprocessorContext};
5use mdbook::BookItem;
6use regex::Regex;
7
8pub struct HidePreprocessor {
9 hide: bool,
10 re: Regex,
11}
12
13const NAME: &str = "hide";
14
15impl HidePreprocessor {
16 pub fn new(ctx: &PreprocessorContext) -> HidePreprocessor {
17 let mut hide = false;
18 let re = Regex::new(r"<!--hidden-->").unwrap();
19
20 if let Some(cfg) = ctx.config.get_preprocessor(NAME) {
21 if cfg.contains_key("hide") {
22 hide = cfg.get("hide").unwrap().as_bool().unwrap();
23 }
24 }
25
26 HidePreprocessor { hide, re }
27 }
28
29 fn process_item(&self, item: BookItem) -> Option<BookItem> {
30 if let BookItem::Chapter(ref c) = item {
31 if self.re.is_match(&c.content) {
32 info!("removing chapter {}", c.name);
33 return None;
34 }
35
36 let mut new = c.clone();
37 new.sub_items.clear();
38
39 for i in c.sub_items.iter() {
40 let cloned_item = i.clone();
41
42 if let Some(cloned_item) = self.process_item(cloned_item) {
43 new.sub_items.push(cloned_item)
44 }
45 }
46
47 return Some(BookItem::Chapter(new));
48 } else {
49 Some(item)
50 }
51 }
52}
53
54impl Default for HidePreprocessor {
55 fn default() -> Self {
56 HidePreprocessor {
57 hide: false,
58 re: Regex::new(r"").unwrap(),
59 }
60 }
61}
62
63impl Preprocessor for HidePreprocessor {
64 fn name(&self) -> &str {
65 "hide"
66 }
67
68 fn run(&self, _ctx: &PreprocessorContext, book: Book) -> Result<Book, Error> {
69 info!("Running mdbook-hide preprocessor");
70
71 if !self.hide {
72 return Ok(book);
73 }
74
75 let mut updated = Book::new();
76
77 for section in book.sections.iter() {
78 let cloned_section = section.clone();
79
80 if let Some(proccessed_item) = self.process_item(cloned_section) {
81 updated.push_item(proccessed_item);
82 }
83 }
84
85 Ok(updated)
86 }
87
88 fn supports_renderer(&self, renderer: &str) -> bool {
89 renderer != "not-supported"
90 }
91}