Accept null
as a valid action, to disable a keystroke
co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
76af424d79
commit
4c51ab8a25
4 changed files with 197 additions and 21 deletions
|
@ -1,7 +1,7 @@
|
|||
use crate::{settings_store::parse_json_with_comments, SettingsAssets};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use collections::BTreeMap;
|
||||
use gpui::{keymap_matcher::Binding, AppContext};
|
||||
use gpui::{keymap_matcher::Binding, AppContext, NoAction};
|
||||
use schemars::{
|
||||
gen::{SchemaGenerator, SchemaSettings},
|
||||
schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation},
|
||||
|
@ -11,18 +11,18 @@ use serde::Deserialize;
|
|||
use serde_json::Value;
|
||||
use util::{asset_str, ResultExt};
|
||||
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
#[derive(Debug, Deserialize, Default, Clone, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
pub struct KeymapFile(Vec<KeymapBlock>);
|
||||
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
#[derive(Debug, Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct KeymapBlock {
|
||||
#[serde(default)]
|
||||
context: Option<String>,
|
||||
bindings: BTreeMap<String, KeymapAction>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Debug, Deserialize, Default, Clone)]
|
||||
#[serde(transparent)]
|
||||
pub struct KeymapAction(Value);
|
||||
|
||||
|
@ -61,21 +61,22 @@ impl KeymapFile {
|
|||
// 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.
|
||||
if let Value::Array(items) = action {
|
||||
let Ok([name, data]): Result<[serde_json::Value; 2], _> = items.try_into() else {
|
||||
return Some(Err(anyhow!("Expected array of length 2")));
|
||||
};
|
||||
let serde_json::Value::String(name) = name else {
|
||||
return Some(Err(anyhow!("Expected first item in array to be a string.")))
|
||||
};
|
||||
cx.deserialize_action(
|
||||
&name,
|
||||
Some(data),
|
||||
)
|
||||
} else if let Value::String(name) = action {
|
||||
cx.deserialize_action(&name, None)
|
||||
} else {
|
||||
return Some(Err(anyhow!("Expected two-element array, got {:?}", action)));
|
||||
match action {
|
||||
Value::Array(items) => {
|
||||
let Ok([name, data]): Result<[serde_json::Value; 2], _> = items.try_into() else {
|
||||
return Some(Err(anyhow!("Expected array of length 2")));
|
||||
};
|
||||
let serde_json::Value::String(name) = name else {
|
||||
return Some(Err(anyhow!("Expected first item in array to be a string.")))
|
||||
};
|
||||
cx.deserialize_action(
|
||||
&name,
|
||||
Some(data),
|
||||
)
|
||||
},
|
||||
Value::String(name) => cx.deserialize_action(&name, None),
|
||||
Value::Null => Ok(no_action()),
|
||||
_ => return Some(Err(anyhow!("Expected two-element array, got {action:?}"))),
|
||||
}
|
||||
.with_context(|| {
|
||||
format!(
|
||||
|
@ -115,6 +116,10 @@ impl KeymapFile {
|
|||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
|
||||
..Default::default()
|
||||
}),
|
||||
Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Null))),
|
||||
..Default::default()
|
||||
}),
|
||||
]),
|
||||
..Default::default()
|
||||
})),
|
||||
|
@ -129,6 +134,10 @@ impl KeymapFile {
|
|||
}
|
||||
}
|
||||
|
||||
fn no_action() -> Box<dyn gpui::Action> {
|
||||
Box::new(NoAction {})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::KeymapFile;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue