1use crate::parse_json_with_comments;
2use anyhow::{Context, Result};
3use assets::Assets;
4use collections::BTreeMap;
5use gpui::{keymap::Binding, MutableAppContext};
6use serde::Deserialize;
7use serde_json::value::RawValue;
8
9#[derive(Deserialize, Default, Clone)]
10#[serde(transparent)]
11pub struct KeymapFileContent(BTreeMap<String, ActionsByKeystroke>);
12
13type ActionsByKeystroke = BTreeMap<String, Box<RawValue>>;
14
15#[derive(Deserialize)]
16struct ActionWithData(Box<str>, Box<RawValue>);
17
18impl KeymapFileContent {
19 pub fn load_defaults(cx: &mut MutableAppContext) {
20 for path in ["keymaps/default.json", "keymaps/vim.json"] {
21 Self::load(path, cx).unwrap();
22 }
23 }
24
25 pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
26 let content = Assets::get(asset_path).unwrap().data;
27 let content_str = std::str::from_utf8(content.as_ref()).unwrap();
28 Ok(parse_json_with_comments::<Self>(content_str)?.add(cx)?)
29 }
30
31 pub fn add(self, cx: &mut MutableAppContext) -> Result<()> {
32 for (context, actions) in self.0 {
33 let context = if context == "*" { None } else { Some(context) };
34 cx.add_bindings(
35 actions
36 .into_iter()
37 .map(|(keystroke, action)| {
38 let action = action.get();
39
40 // This is a workaround for a limitation in serde: serde-rs/json#497
41 // We want to deserialize the action data as a `RawValue` so that we can
42 // deserialize the action itself dynamically directly from the JSON
43 // string. But `RawValue` currently does not work inside of an untagged enum.
44 let action = if action.starts_with('[') {
45 let ActionWithData(name, data) = serde_json::from_str(action)?;
46 cx.deserialize_action(&name, Some(data.get()))
47 } else {
48 let name = serde_json::from_str(action)?;
49 cx.deserialize_action(name, None)
50 }
51 .with_context(|| {
52 format!(
53 "invalid binding value for keystroke {keystroke}, context {context:?}"
54 )
55 })?;
56 Binding::load(&keystroke, action, context.as_deref())
57 })
58 .collect::<Result<Vec<_>>>()?,
59 )
60 }
61 Ok(())
62 }
63}