1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use log::info;
use mdbook::book::Book;
use mdbook::errors::Error;
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
use mdbook::BookItem;
use regex::Regex;

pub struct HidePreprocessor {
    hide: bool,
    re: Regex,
}

const NAME: &str = "hide";

impl HidePreprocessor {
    pub fn new(ctx: &PreprocessorContext) -> HidePreprocessor {
        let mut hide = false;
        let re = Regex::new(r"<!--hidden-->").unwrap();

        if let Some(cfg) = ctx.config.get_preprocessor(NAME) {
            if cfg.contains_key("hide") {
                hide = cfg.get("hide").unwrap().as_bool().unwrap();
            }
        }

        HidePreprocessor { hide, re }
    }

    fn process_item(&self, item: BookItem) -> Option<BookItem> {
        if let BookItem::Chapter(ref c) = item {
            if self.re.is_match(&c.content) {
                info!("removing chapter {}", c.name);
                return None;
            }

            let mut new = c.clone();
            new.sub_items.clear();

            for i in c.sub_items.iter() {
                let cloned_item = i.clone();

                if let Some(cloned_item) = self.process_item(cloned_item) {
                    new.sub_items.push(cloned_item)
                }
            }

            return Some(BookItem::Chapter(new));
        } else {
            Some(item)
        }
    }
}

impl Default for HidePreprocessor {
    fn default() -> Self {
        HidePreprocessor {
            hide: false,
            re: Regex::new(r"").unwrap(),
        }
    }
}

impl Preprocessor for HidePreprocessor {
    fn name(&self) -> &str {
        "hide"
    }

    fn run(&self, _ctx: &PreprocessorContext, book: Book) -> Result<Book, Error> {
        info!("Running mdbook-hide preprocessor");

        if !self.hide {
            return Ok(book);
        }

        let mut updated = Book::new();

        for section in book.sections.iter() {
            let cloned_section = section.clone();

            if let Some(proccessed_item) = self.process_item(cloned_section) {
                updated.push_item(proccessed_item);
            }
        }

        Ok(updated)
    }

    fn supports_renderer(&self, renderer: &str) -> bool {
        renderer != "not-supported"
    }
}