docs_preprocessor.rs

 1use anyhow::Result;
 2use mdbook::book::{Book, BookItem};
 3use mdbook::errors::Error;
 4use mdbook::preprocess::{Preprocessor, PreprocessorContext as MdBookContext};
 5use settings::KeymapFile;
 6use std::sync::Arc;
 7use util::asset_str;
 8
 9mod templates;
10
11use templates::{ActionTemplate, KeybindingTemplate, Template};
12
13pub struct PreprocessorContext {
14    macos_keymap: Arc<KeymapFile>,
15    linux_keymap: Arc<KeymapFile>,
16}
17
18impl PreprocessorContext {
19    pub fn new() -> Result<Self> {
20        let macos_keymap = Arc::new(load_keymap("keymaps/default-macos.json")?);
21        let linux_keymap = Arc::new(load_keymap("keymaps/default-linux.json")?);
22        Ok(Self {
23            macos_keymap,
24            linux_keymap,
25        })
26    }
27
28    pub fn find_binding(&self, os: &str, action: &str) -> Option<String> {
29        let keymap = match os {
30            "macos" => &self.macos_keymap,
31            "linux" => &self.linux_keymap,
32            _ => return None,
33        };
34
35        keymap.sections().find_map(|section| {
36            section.bindings().find_map(|(keystroke, a)| {
37                if a.to_string() == action {
38                    Some(keystroke.to_string())
39                } else {
40                    None
41                }
42            })
43        })
44    }
45}
46
47fn load_keymap(asset_path: &str) -> Result<KeymapFile> {
48    let content = asset_str::<settings::SettingsAssets>(asset_path);
49    KeymapFile::parse(content.as_ref())
50}
51
52pub struct ZedDocsPreprocessor {
53    context: PreprocessorContext,
54    templates: Vec<Box<dyn Template>>,
55}
56
57impl ZedDocsPreprocessor {
58    pub fn new() -> Result<Self> {
59        let context = PreprocessorContext::new()?;
60        let templates: Vec<Box<dyn Template>> = vec![
61            Box::new(KeybindingTemplate::new()),
62            Box::new(ActionTemplate::new()),
63        ];
64        Ok(Self { context, templates })
65    }
66
67    fn process_content(&self, content: &str) -> String {
68        let mut processed = content.to_string();
69        for template in &self.templates {
70            processed = template.process(&self.context, &processed);
71        }
72        processed
73    }
74}
75
76impl Preprocessor for ZedDocsPreprocessor {
77    fn name(&self) -> &str {
78        "zed-docs-preprocessor"
79    }
80
81    fn run(&self, _ctx: &MdBookContext, mut book: Book) -> Result<Book, Error> {
82        book.for_each_mut(|item| {
83            if let BookItem::Chapter(chapter) = item {
84                chapter.content = self.process_content(&chapter.content);
85            }
86        });
87        Ok(book)
88    }
89
90    fn supports_renderer(&self, renderer: &str) -> bool {
91        renderer != "not-supported"
92    }
93}