2022-04-10 21:29:45 +00:00
|
|
|
use anyhow::{Context, Result};
|
2022-04-11 22:54:52 +00:00
|
|
|
use assets::Assets;
|
2022-04-09 00:32:58 +00:00
|
|
|
use collections::BTreeMap;
|
|
|
|
use gpui::{keymap::Binding, MutableAppContext};
|
|
|
|
use serde::Deserialize;
|
|
|
|
use serde_json::value::RawValue;
|
|
|
|
|
2022-04-11 23:50:44 +00:00
|
|
|
#[derive(Deserialize, Default, Clone)]
|
|
|
|
#[serde(transparent)]
|
2022-04-12 00:02:16 +00:00
|
|
|
pub struct KeymapFile(BTreeMap<String, ActionsByKeystroke>);
|
2022-04-11 23:50:44 +00:00
|
|
|
|
|
|
|
type ActionsByKeystroke = BTreeMap<String, Box<RawValue>>;
|
|
|
|
|
2022-04-09 00:32:58 +00:00
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct ActionWithData<'a>(#[serde(borrow)] &'a str, #[serde(borrow)] &'a RawValue);
|
|
|
|
|
2022-04-12 00:02:16 +00:00
|
|
|
impl KeymapFile {
|
2022-04-11 23:50:44 +00:00
|
|
|
pub fn load_defaults(cx: &mut MutableAppContext) {
|
|
|
|
for path in ["keymaps/default.json", "keymaps/vim.json"] {
|
|
|
|
Self::load(path, cx).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
|
|
|
|
let content = Assets::get(asset_path).unwrap().data;
|
|
|
|
let content_str = std::str::from_utf8(content.as_ref()).unwrap();
|
|
|
|
Ok(serde_json::from_str::<Self>(content_str)?.add(cx)?)
|
2022-04-11 22:54:52 +00:00
|
|
|
}
|
|
|
|
|
2022-04-11 23:50:44 +00:00
|
|
|
pub fn add(self, cx: &mut MutableAppContext) -> Result<()> {
|
|
|
|
for (context, actions) in self.0 {
|
2022-04-12 00:17:03 +00:00
|
|
|
let context = if context == "*" { None } else { Some(context) };
|
2022-04-11 23:50:44 +00:00
|
|
|
cx.add_bindings(
|
|
|
|
actions
|
|
|
|
.into_iter()
|
|
|
|
.map(|(keystroke, action)| {
|
|
|
|
let action = action.get();
|
2022-04-12 00:17:03 +00:00
|
|
|
|
|
|
|
// This is a workaround for a limitation in serde: serde-rs/json#497
|
|
|
|
// We want to deserialize the action data as a `RawValue` so that we can
|
|
|
|
// deserialize the action itself dynamically directly from the JSON
|
|
|
|
// string. But `RawValue` currently does not work inside of an untagged enum.
|
2022-04-11 23:50:44 +00:00
|
|
|
let action = if action.starts_with('[') {
|
|
|
|
let ActionWithData(name, data) = serde_json::from_str(action)?;
|
|
|
|
cx.deserialize_action(name, Some(data.get()))
|
|
|
|
} else {
|
|
|
|
let name = serde_json::from_str(action)?;
|
|
|
|
cx.deserialize_action(name, None)
|
|
|
|
}
|
|
|
|
.with_context(|| {
|
|
|
|
format!(
|
2022-04-10 21:29:45 +00:00
|
|
|
"invalid binding value for keystroke {keystroke}, context {context:?}"
|
|
|
|
)
|
2022-04-11 23:50:44 +00:00
|
|
|
})?;
|
|
|
|
Binding::load(&keystroke, action, context.as_deref())
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>>>()?,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Ok(())
|
2022-04-09 00:32:58 +00:00
|
|
|
}
|
|
|
|
}
|