Support unbinding a particular key event (#5152)

To remove a default keybinding for a particular edit mode, set the `event: null`:

e.g. to disable screen clearing with Ctrl-L

```
let $config = {keybindings: [{
        modifier: control
        keycode: char_l
        mode: [emacs, vi_normal, vi_insert]
        event: null
      } ]}

```
This commit is contained in:
Stefan Holderbach 2022-04-10 23:54:09 +02:00 committed by GitHub
parent d18f34daa4
commit 625e807a35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 20 deletions

2
Cargo.lock generated
View File

@ -3529,7 +3529,7 @@ dependencies = [
[[package]] [[package]]
name = "reedline" name = "reedline"
version = "0.3.1" version = "0.3.1"
source = "git+https://github.com/nushell/reedline?branch=main#922fab18e0e4dc3320300e30e240b8396a042682" source = "git+https://github.com/nushell/reedline?branch=main#7ce8b674e060a120c2b110d367aff623c792abcd"
dependencies = [ dependencies = [
"chrono", "chrono",
"crossterm", "crossterm",

View File

@ -698,10 +698,11 @@ fn add_parsed_keybinding(
)) ))
} }
}; };
if let Some(event) = parse_event(&keybinding.event, config)? {
let event = parse_event(&keybinding.event, config)?;
keybindings.add_binding(modifier, keycode, event); keybindings.add_binding(modifier, keycode, event);
} else {
keybindings.remove_binding(modifier, keycode);
}
Ok(()) Ok(())
} }
@ -726,7 +727,7 @@ impl<'config> EventType<'config> {
} }
} }
fn parse_event(value: &Value, config: &Config) -> Result<ReedlineEvent, ShellError> { fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>, ShellError> {
match value { match value {
Value::Record { cols, vals, span } => { Value::Record { cols, vals, span } => {
match EventType::try_from_columns(cols, vals, span)? { match EventType::try_from_columns(cols, vals, span)? {
@ -736,7 +737,8 @@ fn parse_event(value: &Value, config: &Config) -> Result<ReedlineEvent, ShellErr
vals, vals,
config, config,
span, span,
), )
.map(Some),
EventType::Edit(value) => { EventType::Edit(value) => {
let edit = edit_from_record( let edit = edit_from_record(
value.into_string("", config).to_lowercase().as_str(), value.into_string("", config).to_lowercase().as_str(),
@ -745,16 +747,26 @@ fn parse_event(value: &Value, config: &Config) -> Result<ReedlineEvent, ShellErr
config, config,
span, span,
)?; )?;
Ok(ReedlineEvent::Edit(vec![edit])) Ok(Some(ReedlineEvent::Edit(vec![edit])))
} }
EventType::Until(value) => match value { EventType::Until(value) => match value {
Value::List { vals, .. } => { Value::List { vals, .. } => {
let events = vals let events = vals
.iter() .iter()
.map(|value| parse_event(value, config)) .map(|value| match parse_event(value, config) {
Ok(inner) => match inner {
None => Err(ShellError::UnsupportedConfigValue(
"List containing valid events".to_string(),
"Nothing value (null)".to_string(),
value.span()?,
)),
Some(event) => Ok(event),
},
Err(e) => Err(e),
})
.collect::<Result<Vec<ReedlineEvent>, ShellError>>()?; .collect::<Result<Vec<ReedlineEvent>, ShellError>>()?;
Ok(ReedlineEvent::UntilFound(events)) Ok(Some(ReedlineEvent::UntilFound(events)))
} }
v => Err(ShellError::UnsupportedConfigValue( v => Err(ShellError::UnsupportedConfigValue(
"list of events".to_string(), "list of events".to_string(),
@ -767,13 +779,24 @@ fn parse_event(value: &Value, config: &Config) -> Result<ReedlineEvent, ShellErr
Value::List { vals, .. } => { Value::List { vals, .. } => {
let events = vals let events = vals
.iter() .iter()
.map(|value| parse_event(value, config)) .map(|value| match parse_event(value, config) {
Ok(inner) => match inner {
None => Err(ShellError::UnsupportedConfigValue(
"List containing valid events".to_string(),
"Nothing value (null)".to_string(),
value.span()?,
)),
Some(event) => Ok(event),
},
Err(e) => Err(e),
})
.collect::<Result<Vec<ReedlineEvent>, ShellError>>()?; .collect::<Result<Vec<ReedlineEvent>, ShellError>>()?;
Ok(ReedlineEvent::Multiple(events)) Ok(Some(ReedlineEvent::Multiple(events)))
} }
Value::Nothing { .. } => Ok(None),
v => Err(ShellError::UnsupportedConfigValue( v => Err(ShellError::UnsupportedConfigValue(
"record or list of records".to_string(), "record or list of records, null to unbind key".to_string(),
v.into_abbreviated_string(config), v.into_abbreviated_string(config),
v.span()?, v.span()?,
)), )),
@ -965,7 +988,7 @@ mod test {
let config = Config::default(); let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap(); let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!(parsed_event, ReedlineEvent::Enter); assert_eq!(parsed_event, Some(ReedlineEvent::Enter));
} }
#[test] #[test]
@ -988,7 +1011,10 @@ mod test {
let config = Config::default(); let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap(); let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!(parsed_event, ReedlineEvent::Edit(vec![EditCommand::Clear])); assert_eq!(
parsed_event,
Some(ReedlineEvent::Edit(vec![EditCommand::Clear]))
);
} }
#[test] #[test]
@ -1019,7 +1045,7 @@ mod test {
let parsed_event = parse_event(&event, &config).unwrap(); let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!( assert_eq!(
parsed_event, parsed_event,
ReedlineEvent::Menu("history_menu".to_string()) Some(ReedlineEvent::Menu("history_menu".to_string()))
); );
} }
@ -1078,10 +1104,10 @@ mod test {
let parsed_event = parse_event(&event, &config).unwrap(); let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!( assert_eq!(
parsed_event, parsed_event,
ReedlineEvent::UntilFound(vec![ Some(ReedlineEvent::UntilFound(vec![
ReedlineEvent::Menu("history_menu".to_string()), ReedlineEvent::Menu("history_menu".to_string()),
ReedlineEvent::Enter, ReedlineEvent::Enter,
]) ]))
); );
} }
@ -1129,10 +1155,10 @@ mod test {
let parsed_event = parse_event(&event, &config).unwrap(); let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!( assert_eq!(
parsed_event, parsed_event,
ReedlineEvent::Multiple(vec![ Some(ReedlineEvent::Multiple(vec![
ReedlineEvent::Menu("history_menu".to_string()), ReedlineEvent::Menu("history_menu".to_string()),
ReedlineEvent::Enter, ReedlineEvent::Enter,
]) ]))
); );
} }