1use chrono::Local;
2use env_logger::Builder;
3use log::info;
4use log::LevelFilter;
5use mdbook::book::Book;
6use mdbook::errors::Error;
7use mdbook::preprocess::{Preprocessor, PreprocessorContext};
8use std::env;
9use std::fs;
10use std::io::Write;
11use std::str;
12
13fn init_logger() {
14 let mut builder = Builder::new();
15
16 builder.format(|formatter, record| {
17 writeln!(
18 formatter,
19 "{} [{}] ({}): {}",
20 Local::now().format("%Y-%m-%d %H:%M:%S"),
21 record.level(),
22 record.target(),
23 record.args()
24 )
25 });
26
27 if let Ok(var) = env::var("RUST_LOG") {
28 builder.parse_filters(&var);
29 } else {
30 builder.filter(None, LevelFilter::Info);
32 builder.filter(Some("html5ever"), LevelFilter::Error);
34 }
35
36 builder.init();
37}
38pub mod pagetoc_lib {
39 use super::*;
40
41 pub struct PagetocPreprocessor;
42
43 impl Default for PagetocPreprocessor {
44 fn default() -> Self {
45 Self::new()
46 }
47 }
48
49 impl PagetocPreprocessor {
50 pub fn new() -> PagetocPreprocessor {
51 PagetocPreprocessor
52 }
53 }
54
55 impl Preprocessor for PagetocPreprocessor {
56 fn name(&self) -> &str {
57 "mdbook-pagetoc"
58 }
59
60 fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book, Error> {
61 init_logger();
62 let html_config = ctx.config.html_config().unwrap_or_default();
63
64 let pagetoc_js = include_str!("pagetoc.js");
65 let pagetoc_css = include_str!("pagetoc.css");
66 let theme_dir = match html_config.theme {
67 Some(ref theme) => ctx.root.join(theme),
68 None => ctx.root.join("theme"),
69 };
70
71 fs::create_dir_all(theme_dir.as_path()).expect("Unable to create directory");
72 for (file_name, contents) in [("pagetoc.js", pagetoc_js), ("pagetoc.css", pagetoc_css)]
73 {
74 let file_path = theme_dir.join(file_name);
75 if !file_path.exists() {
76 info!("{}: Writing {}", self.name(), file_path.display());
77 fs::write(file_path, contents).expect("Unable to write file");
78 }
79 }
80 Ok(book)
81 }
82
83 fn supports_renderer(&self, renderer: &str) -> bool {
84 renderer == "html"
85 }
86 }
87}