feat(cli): add vi solidus / keybinding (#14908)

# Description

- Add keybinding for `/` when in vi normal mode which activates the
history menu.
- Make keybinding `mode` (`edit_mode`) case-insensitive.

This keybinding exists both in vim and GNU Readline (e.g. bash) when in
vi normal mode. The reason this keybinding is getting added here (and
not in `reedline`) is because it triggers the history menu, and should
only be defined when the history menu exists. Menus are defined
externally to `reedline`.

# User-Facing Changes

Added keybinding for `/` when in vi normal mode which activates the
history menu.

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the
tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting

TODO: Update docs
This commit is contained in:
Tyler Miller 2025-02-06 04:53:32 -08:00 committed by GitHub
parent 164a089656
commit c7d3014849
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -707,6 +707,11 @@ pub(crate) fn create_keybindings(config: &Config) -> Result<KeybindingsMode, She
EditBindings::Vi => { EditBindings::Vi => {
add_menu_keybindings(&mut insert_keybindings); add_menu_keybindings(&mut insert_keybindings);
add_menu_keybindings(&mut normal_keybindings); add_menu_keybindings(&mut normal_keybindings);
normal_keybindings.add_binding(
KeyModifiers::NONE,
KeyCode::Char('/'),
ReedlineEvent::Menu("history_menu".to_string()),
);
} }
} }
for keybinding in parsed_keybindings { for keybinding in parsed_keybindings {
@ -740,9 +745,15 @@ fn add_keybinding(
let span = mode.span(); let span = mode.span();
match &mode { match &mode {
Value::String { val, .. } => match val.as_str() { Value::String { val, .. } => match val.as_str() {
"emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config), str if str.eq_ignore_ascii_case("emacs") => {
"vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config), add_parsed_keybinding(emacs_keybindings, keybinding, config)
"vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config), }
str if str.eq_ignore_ascii_case("vi_insert") => {
add_parsed_keybinding(insert_keybindings, keybinding, config)
}
str if str.eq_ignore_ascii_case("vi_normal") => {
add_parsed_keybinding(normal_keybindings, keybinding, config)
}
str => Err(ShellError::InvalidValue { str => Err(ShellError::InvalidValue {
valid: "'emacs', 'vi_insert', or 'vi_normal'".into(), valid: "'emacs', 'vi_insert', or 'vi_normal'".into(),
actual: format!("'{str}'"), actual: format!("'{str}'"),