Sketch in a table for the keybindings UI (#32436)
Adds the initial semblance of a keymap UI. It is currently gated behind the `settings-ui` feature flag. Follow up PRs will add polish and missing features. Release Notes: - N/A --------- Co-authored-by: Ben Kunkle <ben@zed.dev> Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
parent
32906bfa7c
commit
7609ca7a8d
23 changed files with 1967 additions and 494 deletions
|
@ -3,7 +3,7 @@ use collections::{BTreeMap, HashMap, IndexMap};
|
|||
use fs::Fs;
|
||||
use gpui::{
|
||||
Action, ActionBuildError, App, InvalidKeystrokeError, KEYSTROKE_PARSE_EXPECTED_MESSAGE,
|
||||
KeyBinding, KeyBindingContextPredicate, KeyBindingMetaIndex, NoAction,
|
||||
KeyBinding, KeyBindingContextPredicate, KeyBindingMetaIndex, Keystroke, NoAction, SharedString,
|
||||
};
|
||||
use schemars::{JsonSchema, json_schema};
|
||||
use serde::Deserialize;
|
||||
|
@ -399,7 +399,13 @@ impl KeymapFile {
|
|||
},
|
||||
};
|
||||
|
||||
let key_binding = match KeyBinding::load(keystrokes, action, context, key_equivalents) {
|
||||
let key_binding = match KeyBinding::load(
|
||||
keystrokes,
|
||||
action,
|
||||
context,
|
||||
key_equivalents,
|
||||
action_input_string.map(SharedString::from),
|
||||
) {
|
||||
Ok(key_binding) => key_binding,
|
||||
Err(InvalidKeystrokeError { keystroke }) => {
|
||||
return Err(format!(
|
||||
|
@ -626,6 +632,13 @@ impl KeymapFile {
|
|||
continue;
|
||||
};
|
||||
for (keystrokes, action) in bindings {
|
||||
let Ok(keystrokes) = keystrokes
|
||||
.split_whitespace()
|
||||
.map(Keystroke::parse)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if keystrokes != target.keystrokes {
|
||||
continue;
|
||||
}
|
||||
|
@ -640,9 +653,9 @@ impl KeymapFile {
|
|||
if let Some(index) = found_index {
|
||||
let (replace_range, replace_value) = replace_top_level_array_value_in_json_text(
|
||||
&keymap_contents,
|
||||
&["bindings", target.keystrokes],
|
||||
&["bindings", &target.keystrokes_unparsed()],
|
||||
Some(&source_action_value),
|
||||
Some(source.keystrokes),
|
||||
Some(&source.keystrokes_unparsed()),
|
||||
index,
|
||||
tab_size,
|
||||
)
|
||||
|
@ -674,7 +687,7 @@ impl KeymapFile {
|
|||
value.insert("bindings".to_string(), {
|
||||
let mut bindings = serde_json::Map::new();
|
||||
let action = keybinding.action_value()?;
|
||||
bindings.insert(keybinding.keystrokes.into(), action);
|
||||
bindings.insert(keybinding.keystrokes_unparsed(), action);
|
||||
bindings.into()
|
||||
});
|
||||
|
||||
|
@ -701,11 +714,11 @@ pub enum KeybindUpdateOperation<'a> {
|
|||
}
|
||||
|
||||
pub struct KeybindUpdateTarget<'a> {
|
||||
context: Option<&'a str>,
|
||||
keystrokes: &'a str,
|
||||
action_name: &'a str,
|
||||
use_key_equivalents: bool,
|
||||
input: Option<&'a str>,
|
||||
pub context: Option<&'a str>,
|
||||
pub keystrokes: &'a [Keystroke],
|
||||
pub action_name: &'a str,
|
||||
pub use_key_equivalents: bool,
|
||||
pub input: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> KeybindUpdateTarget<'a> {
|
||||
|
@ -721,6 +734,16 @@ impl<'a> KeybindUpdateTarget<'a> {
|
|||
};
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
fn keystrokes_unparsed(&self) -> String {
|
||||
let mut keystrokes = String::with_capacity(self.keystrokes.len() * 8);
|
||||
for keystroke in self.keystrokes {
|
||||
keystrokes.push_str(&keystroke.unparse());
|
||||
keystrokes.push(' ');
|
||||
}
|
||||
keystrokes.pop();
|
||||
keystrokes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -804,6 +827,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn keymap_update() {
|
||||
use gpui::Keystroke;
|
||||
|
||||
zlog::init_test();
|
||||
#[track_caller]
|
||||
fn check_keymap_update(
|
||||
|
@ -816,10 +841,18 @@ mod tests {
|
|||
pretty_assertions::assert_eq!(expected.to_string(), result);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn parse_keystrokes(keystrokes: &str) -> Vec<Keystroke> {
|
||||
return keystrokes
|
||||
.split(' ')
|
||||
.map(|s| Keystroke::parse(s).expect("Keystrokes valid"))
|
||||
.collect();
|
||||
}
|
||||
|
||||
check_keymap_update(
|
||||
"[]",
|
||||
KeybindUpdateOperation::Add(KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-a",
|
||||
keystrokes: &parse_keystrokes("ctrl-a"),
|
||||
action_name: "zed::SomeAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
@ -845,7 +878,7 @@ mod tests {
|
|||
]"#
|
||||
.unindent(),
|
||||
KeybindUpdateOperation::Add(KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
@ -876,7 +909,7 @@ mod tests {
|
|||
]"#
|
||||
.unindent(),
|
||||
KeybindUpdateOperation::Add(KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
@ -912,7 +945,7 @@ mod tests {
|
|||
]"#
|
||||
.unindent(),
|
||||
KeybindUpdateOperation::Add(KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: Some("Zed > Editor && some_condition = true"),
|
||||
use_key_equivalents: true,
|
||||
|
@ -951,14 +984,14 @@ mod tests {
|
|||
.unindent(),
|
||||
KeybindUpdateOperation::Replace {
|
||||
target: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-a",
|
||||
keystrokes: &parse_keystrokes("ctrl-a"),
|
||||
action_name: "zed::SomeAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
input: None,
|
||||
},
|
||||
source: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
@ -997,14 +1030,14 @@ mod tests {
|
|||
.unindent(),
|
||||
KeybindUpdateOperation::Replace {
|
||||
target: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-a",
|
||||
keystrokes: &parse_keystrokes("ctrl-a"),
|
||||
action_name: "zed::SomeAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
input: None,
|
||||
},
|
||||
source: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
@ -1038,14 +1071,14 @@ mod tests {
|
|||
.unindent(),
|
||||
KeybindUpdateOperation::Replace {
|
||||
target: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-a",
|
||||
keystrokes: &parse_keystrokes("ctrl-a"),
|
||||
action_name: "zed::SomeNonexistentAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
input: None,
|
||||
},
|
||||
source: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
@ -1081,14 +1114,14 @@ mod tests {
|
|||
.unindent(),
|
||||
KeybindUpdateOperation::Replace {
|
||||
target: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-a",
|
||||
keystrokes: &parse_keystrokes("ctrl-a"),
|
||||
action_name: "zed::SomeAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
input: None,
|
||||
},
|
||||
source: KeybindUpdateTarget {
|
||||
keystrokes: "ctrl-b",
|
||||
keystrokes: &parse_keystrokes("ctrl-b"),
|
||||
action_name: "zed::SomeOtherAction",
|
||||
context: None,
|
||||
use_key_equivalents: false,
|
||||
|
|
|
@ -14,8 +14,8 @@ use util::asset_str;
|
|||
pub use editable_setting_control::*;
|
||||
pub use key_equivalents::*;
|
||||
pub use keymap_file::{
|
||||
KeyBindingValidator, KeyBindingValidatorRegistration, KeybindSource, KeymapFile,
|
||||
KeymapFileLoadResult,
|
||||
KeyBindingValidator, KeyBindingValidatorRegistration, KeybindSource, KeybindUpdateOperation,
|
||||
KeybindUpdateTarget, KeymapFile, KeymapFileLoadResult,
|
||||
};
|
||||
pub use settings_file::*;
|
||||
pub use settings_json::*;
|
||||
|
|
|
@ -618,7 +618,7 @@ impl SettingsStore {
|
|||
));
|
||||
}
|
||||
|
||||
fn json_tab_size(&self) -> usize {
|
||||
pub fn json_tab_size(&self) -> usize {
|
||||
const DEFAULT_JSON_TAB_SIZE: usize = 2;
|
||||
|
||||
if let Some((setting_type_id, callback)) = &self.tab_size_callback {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue