mirror of
https://github.com/nushell/nushell.git
synced 2024-11-24 17:34:00 +01:00
Improve keybinding parsing for Unicode support (#14020)
# Description This pull request enhances the `add_parsed_keybinding` function to provide greater flexibility in specifying keycodes for keybindings in Nushell. Previously, the function only supported specifying keycodes directly through character notation (e.g., `char_e` for the character `e`). This limited users to a small set of keybindings, especially in scenarios where specific non-English characters were needed. With this new version, users can also specify characters using their Unicode codes, such as `char_u003B` for the semicolon (`;`), providing a more flexible approach to customization, for example like this: ```nushell { name: move_to_line_end_or_take_history_hint modifier: shift keycode: char_u003B # char_; mode: vi_normal event: { until: [ { send: historyhintcomplete } { edit: movetolineend } ] } } ``` # User-Facing Changes Added support for specifying keycodes using Unicode codes, e.g., char_u002C (comma - `,`): ```nushell { name: <command_name>, # name of the command modifier: none, # key modifier keycode: char_u002C, # Unicode code for the comma (',') mode: vi_normal, # mode in which this binding should work event: { send: <action> # action to be performed } } ```
This commit is contained in:
parent
2830ec008c
commit
55c3fc9141
@ -833,64 +833,76 @@ fn add_parsed_keybinding(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let keycode = match keybinding
|
let keycode_str = keybinding
|
||||||
.keycode
|
.keycode
|
||||||
.to_expanded_string("", config)
|
.to_expanded_string("", config)
|
||||||
.to_ascii_lowercase()
|
.to_ascii_lowercase();
|
||||||
.as_str()
|
|
||||||
{
|
|
||||||
"backspace" => KeyCode::Backspace,
|
|
||||||
"enter" => KeyCode::Enter,
|
|
||||||
c if c.starts_with("char_") => {
|
|
||||||
let mut char_iter = c.chars().skip(5);
|
|
||||||
let pos1 = char_iter.next();
|
|
||||||
let pos2 = char_iter.next();
|
|
||||||
|
|
||||||
let char = if let (Some(char), None) = (pos1, pos2) {
|
let keycode = if let Some(rest) = keycode_str.strip_prefix("char_") {
|
||||||
char
|
let error = |exp: &str, value| ShellError::UnsupportedConfigValue {
|
||||||
} else {
|
expected: exp.to_string(),
|
||||||
|
value,
|
||||||
|
span: keybinding.keycode.span(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut char_iter = rest.chars();
|
||||||
|
let char = match (char_iter.next(), char_iter.next()) {
|
||||||
|
(Some(char), None) => char,
|
||||||
|
(Some('u'), Some(_)) => {
|
||||||
|
// This will never panic as we know there are at least two symbols
|
||||||
|
let Ok(code_point) = u32::from_str_radix(&rest[1..], 16) else {
|
||||||
|
return Err(error("valid hex code in keycode", keycode_str));
|
||||||
|
};
|
||||||
|
|
||||||
|
char::from_u32(code_point).ok_or(error("valid Unicode code point", keycode_str))?
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(error(
|
||||||
|
"format 'char_<char>' or 'char_u<hex code>'",
|
||||||
|
keycode_str,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyCode::Char(char)
|
||||||
|
} else {
|
||||||
|
match keycode_str.as_str() {
|
||||||
|
"backspace" => KeyCode::Backspace,
|
||||||
|
"enter" => KeyCode::Enter,
|
||||||
|
"space" => KeyCode::Char(' '),
|
||||||
|
"down" => KeyCode::Down,
|
||||||
|
"up" => KeyCode::Up,
|
||||||
|
"left" => KeyCode::Left,
|
||||||
|
"right" => KeyCode::Right,
|
||||||
|
"home" => KeyCode::Home,
|
||||||
|
"end" => KeyCode::End,
|
||||||
|
"pageup" => KeyCode::PageUp,
|
||||||
|
"pagedown" => KeyCode::PageDown,
|
||||||
|
"tab" => KeyCode::Tab,
|
||||||
|
"backtab" => KeyCode::BackTab,
|
||||||
|
"delete" => KeyCode::Delete,
|
||||||
|
"insert" => KeyCode::Insert,
|
||||||
|
c if c.starts_with('f') => {
|
||||||
|
let fn_num: u8 = c[1..]
|
||||||
|
.parse()
|
||||||
|
.ok()
|
||||||
|
.filter(|num| matches!(num, 1..=20))
|
||||||
|
.ok_or(ShellError::UnsupportedConfigValue {
|
||||||
|
expected: "(f1|f2|...|f20)".to_string(),
|
||||||
|
value: format!("unknown function key: {c}"),
|
||||||
|
span: keybinding.keycode.span(),
|
||||||
|
})?;
|
||||||
|
KeyCode::F(fn_num)
|
||||||
|
}
|
||||||
|
"null" => KeyCode::Null,
|
||||||
|
"esc" | "escape" => KeyCode::Esc,
|
||||||
|
_ => {
|
||||||
return Err(ShellError::UnsupportedConfigValue {
|
return Err(ShellError::UnsupportedConfigValue {
|
||||||
expected: "char_<CHAR: unicode codepoint>".to_string(),
|
expected: "crossterm KeyCode".to_string(),
|
||||||
value: c.to_string(),
|
value: keybinding.keycode.to_abbreviated_string(config),
|
||||||
span: keybinding.keycode.span(),
|
span: keybinding.keycode.span(),
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
KeyCode::Char(char)
|
|
||||||
}
|
|
||||||
"space" => KeyCode::Char(' '),
|
|
||||||
"down" => KeyCode::Down,
|
|
||||||
"up" => KeyCode::Up,
|
|
||||||
"left" => KeyCode::Left,
|
|
||||||
"right" => KeyCode::Right,
|
|
||||||
"home" => KeyCode::Home,
|
|
||||||
"end" => KeyCode::End,
|
|
||||||
"pageup" => KeyCode::PageUp,
|
|
||||||
"pagedown" => KeyCode::PageDown,
|
|
||||||
"tab" => KeyCode::Tab,
|
|
||||||
"backtab" => KeyCode::BackTab,
|
|
||||||
"delete" => KeyCode::Delete,
|
|
||||||
"insert" => KeyCode::Insert,
|
|
||||||
c if c.starts_with('f') => {
|
|
||||||
let fn_num: u8 = c[1..]
|
|
||||||
.parse()
|
|
||||||
.ok()
|
|
||||||
.filter(|num| matches!(num, 1..=20))
|
|
||||||
.ok_or(ShellError::UnsupportedConfigValue {
|
|
||||||
expected: "(f1|f2|...|f20)".to_string(),
|
|
||||||
value: format!("unknown function key: {c}"),
|
|
||||||
span: keybinding.keycode.span(),
|
|
||||||
})?;
|
|
||||||
KeyCode::F(fn_num)
|
|
||||||
}
|
|
||||||
"null" => KeyCode::Null,
|
|
||||||
"esc" | "escape" => KeyCode::Esc,
|
|
||||||
_ => {
|
|
||||||
return Err(ShellError::UnsupportedConfigValue {
|
|
||||||
expected: "crossterm KeyCode".to_string(),
|
|
||||||
value: keybinding.keycode.to_abbreviated_string(config),
|
|
||||||
span: keybinding.keycode.span(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(event) = parse_event(&keybinding.event, config)? {
|
if let Some(event) = parse_event(&keybinding.event, config)? {
|
||||||
|
Loading…
Reference in New Issue
Block a user