
* Collects and reports all parse errors * Shares parsed `KeyBindingContextPredicate` among the actions. * Updates gpui keybinding and action parsing to return structured errors. * Renames "block" to "section" to match the docs, as types like `KeymapSection` are shown in `json-language-server` hovers. * Removes wrapping of `context` and `use_key_equivalents` fields so that `json-language-server` auto-inserts `""` and `false` instead of `null`. * Updates `add_to_cx` to take `&self`, so that the user keymap doesn't get unnecessarily cloned. In retrospect I wish I'd just switched to using TreeSitter to do the parsing and provide proper diagnostics. This is tracked in #23333 Release Notes: - Improved handling of errors within the user keymap file. Parse errors within context, keystrokes, or actions no longer prevent loading the key bindings that do parse.
93 lines
2.6 KiB
Rust
93 lines
2.6 KiB
Rust
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<KeymapFile>,
|
|
linux_keymap: Arc<KeymapFile>,
|
|
}
|
|
|
|
impl PreprocessorContext {
|
|
pub fn new() -> Result<Self> {
|
|
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<String> {
|
|
let keymap = match os {
|
|
"macos" => &self.macos_keymap,
|
|
"linux" => &self.linux_keymap,
|
|
_ => return None,
|
|
};
|
|
|
|
keymap.sections().find_map(|section| {
|
|
section.bindings().find_map(|(keystroke, a)| {
|
|
if a.to_string() == action {
|
|
Some(keystroke.to_string())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
fn load_keymap(asset_path: &str) -> Result<KeymapFile> {
|
|
let content = asset_str::<settings::SettingsAssets>(asset_path);
|
|
KeymapFile::parse(content.as_ref())
|
|
}
|
|
|
|
pub struct ZedDocsPreprocessor {
|
|
context: PreprocessorContext,
|
|
templates: Vec<Box<dyn Template>>,
|
|
}
|
|
|
|
impl ZedDocsPreprocessor {
|
|
pub fn new() -> Result<Self> {
|
|
let context = PreprocessorContext::new()?;
|
|
let templates: Vec<Box<dyn Template>> = 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, Error> {
|
|
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"
|
|
}
|
|
}
|