use anyhow::Result; use mdbook::book::{Book, BookItem}; use mdbook::errors::Error; use mdbook::preprocess::{Preprocessor, PreprocessorContext as MdBookContext}; use settings::KeymapFile; use std::sync::Arc; use util::asset_str; mod templates; use templates::{ActionTemplate, KeybindingTemplate, Template}; pub struct PreprocessorContext { macos_keymap: Arc, linux_keymap: Arc, } impl PreprocessorContext { pub fn new() -> Result { let macos_keymap = Arc::new(load_keymap("keymaps/default-macos.json")?); let linux_keymap = Arc::new(load_keymap("keymaps/default-linux.json")?); Ok(Self { macos_keymap, linux_keymap, }) } pub fn find_binding(&self, os: &str, action: &str) -> Option { let keymap = match os { "macos" => &self.macos_keymap, "linux" => &self.linux_keymap, _ => return None, }; // Find the binding in reverse order, as the last binding takes precedence. keymap.sections().rev().find_map(|section| { section.bindings().rev().find_map(|(keystroke, a)| { if a.to_string() == action { Some(keystroke.to_string()) } else { None } }) }) } } fn load_keymap(asset_path: &str) -> Result { let content = asset_str::(asset_path); KeymapFile::parse(content.as_ref()) } pub struct ZedDocsPreprocessor { context: PreprocessorContext, templates: Vec>, } impl ZedDocsPreprocessor { pub fn new() -> Result { let context = PreprocessorContext::new()?; let templates: Vec> = vec![ Box::new(KeybindingTemplate::new()), Box::new(ActionTemplate::new()), ]; Ok(Self { context, templates }) } fn process_content(&self, content: &str) -> String { let mut processed = content.to_string(); for template in &self.templates { processed = template.process(&self.context, &processed); } processed } } impl Preprocessor for ZedDocsPreprocessor { fn name(&self) -> &str { "zed-docs-preprocessor" } fn run(&self, _ctx: &MdBookContext, mut book: Book) -> Result { book.for_each_mut(|item| { if let BookItem::Chapter(chapter) = item { chapter.content = self.process_content(&chapter.content); } }); Ok(book) } fn supports_renderer(&self, renderer: &str) -> bool { renderer != "not-supported" } }