keymap: Allow upper-case keys in keybinds (#27813)
Reverts the error behavior introduced in #27558. Upper-case keys in keybindings no longer generate errors, instead they are transformed into `shift-{KEY}` e.g. `ctrl-N` becomes `ctrl-shift-n` The behavior introduced in #27558 where "special" keys such as function keys, `control`, `shift`, etc. Are parsed case-insensitively is preserved. Release Notes: - Improved how upper-case characters are handled in keybinds. "special" keys such as the function keys, `control`, `shift`, etc. are now parsed case-insensitively, so for example `F8`, `CTRL`, `SHIFT` are now acceptable alternatives to `f8`, `ctrl`, and `shift` when declaring keybindings. Additionally, upper-case (ascii) characters will now be converted explicitly to `shift` + the lowercase version of the character, to match the Vim behavior. NOTE: Release notes above should replace the release notes from #27558
This commit is contained in:
parent
8a212be0b1
commit
a1bef28da3
4 changed files with 11 additions and 43 deletions
|
@ -240,7 +240,7 @@ impl EditorTestContext {
|
|||
// unlike cx.simulate_keystrokes(), this does not run_until_parked
|
||||
// so you can use it to test detailed timing
|
||||
pub fn simulate_keystroke(&mut self, keystroke_text: &str) {
|
||||
let keystroke = Keystroke::parse_case_insensitive(keystroke_text).unwrap();
|
||||
let keystroke = Keystroke::parse(keystroke_text).unwrap();
|
||||
self.cx.dispatch_keystroke(self.window, keystroke);
|
||||
}
|
||||
|
||||
|
|
|
@ -399,7 +399,7 @@ impl TestAppContext {
|
|||
pub fn simulate_keystrokes(&mut self, window: AnyWindowHandle, keystrokes: &str) {
|
||||
for keystroke in keystrokes
|
||||
.split(' ')
|
||||
.map(Keystroke::parse_case_insensitive)
|
||||
.map(Keystroke::parse)
|
||||
.map(Result::unwrap)
|
||||
{
|
||||
self.dispatch_keystroke(window, keystroke);
|
||||
|
@ -413,11 +413,7 @@ impl TestAppContext {
|
|||
/// will type abc into your current editor
|
||||
/// This will also run the background executor until it's parked.
|
||||
pub fn simulate_input(&mut self, window: AnyWindowHandle, input: &str) {
|
||||
for keystroke in input
|
||||
.split("")
|
||||
.map(Keystroke::parse_case_insensitive)
|
||||
.map(Result::unwrap)
|
||||
{
|
||||
for keystroke in input.split("").map(Keystroke::parse).map(Result::unwrap) {
|
||||
self.dispatch_keystroke(window, keystroke);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,9 @@ impl Display for InvalidKeystrokeError {
|
|||
}
|
||||
|
||||
/// Sentence explaining what keystroke parser expects, starting with "Expected ..."
|
||||
pub const KEYSTROKE_PARSE_EXPECTED_MESSAGE: &str = "Expected a sequence of lowercase modifiers \
|
||||
pub const KEYSTROKE_PARSE_EXPECTED_MESSAGE: &str = "Expected a sequence of modifiers \
|
||||
(`ctrl`, `alt`, `shift`, `fn`, `cmd`, `super`, or `win`) \
|
||||
followed by a lowercase key, separated by `-`.";
|
||||
followed by a key, separated by `-`.";
|
||||
|
||||
impl Keystroke {
|
||||
/// When matching a key we cannot know whether the user intended to type
|
||||
|
@ -81,28 +81,6 @@ impl Keystroke {
|
|||
/// secondary means "cmd" on macOS and "ctrl" on other platforms
|
||||
/// when matching a key with an key_char set will be matched without it.
|
||||
pub fn parse(source: &str) -> std::result::Result<Self, InvalidKeystrokeError> {
|
||||
return Self::parse_impl(source, true);
|
||||
}
|
||||
|
||||
/// Parse a keystroke case-insensitively. This means
|
||||
/// keystrokes like `ctrl-T` will not be rejected.
|
||||
/// Useful in tests to allow more concise keystroke inputs,
|
||||
/// e.g., `simulate_keystrokes("ctrl-T")` instead of `simulate_keystrokes("ctrl-shift-t")`.
|
||||
/// This also allows `simulate_input` style functions to support capital letters,
|
||||
/// e.g., `simulate_input("Title Case")` can work by just parsing each character as a keystroke
|
||||
/// and dispatching it, instead of needing to parse something like
|
||||
/// `simulate_input("shift-title shift-case")`.
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn parse_case_insensitive(
|
||||
source: &str,
|
||||
) -> std::result::Result<Self, InvalidKeystrokeError> {
|
||||
return Self::parse_impl(source, false);
|
||||
}
|
||||
|
||||
fn parse_impl(
|
||||
source: &str,
|
||||
case_sensitive: bool,
|
||||
) -> std::result::Result<Self, InvalidKeystrokeError> {
|
||||
let mut control = false;
|
||||
let mut alt = false;
|
||||
let mut shift = false;
|
||||
|
@ -166,16 +144,10 @@ impl Keystroke {
|
|||
}
|
||||
|
||||
if component.len() == 1 && component.as_bytes()[0].is_ascii_uppercase() {
|
||||
if case_sensitive {
|
||||
return Err(InvalidKeystrokeError {
|
||||
keystroke: source.to_owned(),
|
||||
});
|
||||
} else {
|
||||
// Convert to shift + lowercase char if parsing case insensitively
|
||||
shift = true;
|
||||
key_str.make_ascii_lowercase();
|
||||
}
|
||||
} else if case_sensitive {
|
||||
// Convert to shift + lowercase char
|
||||
shift = true;
|
||||
key_str.make_ascii_lowercase();
|
||||
} else {
|
||||
// convert ascii chars to lowercase so that named keys like "tab" and "enter"
|
||||
// are accepted case insensitively and stored how we expect so they are matched properly
|
||||
key_str.make_ascii_lowercase()
|
||||
|
|
|
@ -398,7 +398,7 @@ mod test {
|
|||
false
|
||||
),
|
||||
to_esc_str(
|
||||
&Keystroke::parse_case_insensitive(&format!("ctrl-{}", upper)).unwrap(),
|
||||
&Keystroke::parse(&format!("ctrl-{}", upper)).unwrap(),
|
||||
&mode,
|
||||
false
|
||||
),
|
||||
|
@ -415,7 +415,7 @@ mod test {
|
|||
for character in ascii_printable {
|
||||
assert_eq!(
|
||||
to_esc_str(
|
||||
&Keystroke::parse_case_insensitive(&format!("alt-{}", character)).unwrap(),
|
||||
&Keystroke::parse(&format!("alt-{}", character)).unwrap(),
|
||||
&TermMode::NONE,
|
||||
true
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue