1use anyhow::{Context, Result};
2use assets::Assets;
3use collections::BTreeMap;
4use gpui::{keymap::Binding, MutableAppContext};
5use serde::Deserialize;
6use serde_json::value::RawValue;
7
8#[derive(Deserialize, Default, Clone)]
9#[serde(transparent)]
10pub struct KeymapFile(BTreeMap<String, ActionsByKeystroke>);
11
12type ActionsByKeystroke = BTreeMap<String, Box<RawValue>>;
13
14#[derive(Deserialize)]
15struct ActionWithData<'a>(#[serde(borrow)] &'a str, #[serde(borrow)] &'a RawValue);
16
17impl KeymapFile {
18 pub fn load_defaults(cx: &mut MutableAppContext) {
19 for path in ["keymaps/default.json", "keymaps/vim.json"] {
20 Self::load(path, cx).unwrap();
21 }
22 }
23
24 pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
25 let content = Assets::get(asset_path).unwrap().data;
26 let content_str = std::str::from_utf8(content.as_ref()).unwrap();
27 Ok(serde_json::from_str::<Self>(content_str)?.add(cx)?)
28 }
29
30 pub fn add(self, cx: &mut MutableAppContext) -> Result<()> {
31 for (context, actions) in self.0 {
32 let context = if context.is_empty() {
33 None
34 } else {
35 Some(context)
36 };
37 cx.add_bindings(
38 actions
39 .into_iter()
40 .map(|(keystroke, action)| {
41 let action = action.get();
42 let action = if action.starts_with('[') {
43 let ActionWithData(name, data) = serde_json::from_str(action)?;
44 cx.deserialize_action(name, Some(data.get()))
45 } else {
46 let name = serde_json::from_str(action)?;
47 cx.deserialize_action(name, None)
48 }
49 .with_context(|| {
50 format!(
51 "invalid binding value for keystroke {keystroke}, context {context:?}"
52 )
53 })?;
54 Binding::load(&keystroke, action, context.as_deref())
55 })
56 .collect::<Result<Vec<_>>>()?,
57 )
58 }
59 Ok(())
60 }
61}