kkawakam / rustyline

Readline Implementation in Rust
https://crates.io/crates/rustyline/
MIT License
1.55k stars 178 forks source link

How do you express a vi keybinding with numeric argument? #415

Open sophiajt opened 4 years ago

sophiajt commented 4 years ago

In nushell, we've been experimenting with adding configurable keybindings. We wanted to set up some configuration, and then call into rustyline using the bind_sequence commands, like this:

    // add key bindings to move over a whole word with Ctrl+ArrowLeft and Ctrl+ArrowRight
    rl.bind_sequence(
        KeyPress::ControlLeft,
        Cmd::Move(Movement::BackwardWord(1, Word::Vi)),
    );
    rl.bind_sequence(
        KeyPress::ControlRight,
        Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Vi)),
    );

An issue I'm running into: how would the user define their own vi bindings? I don't see a way to express a bind_sequence where there is a numeric parameter. When you call bind_sequence it looks like you have to pick a statically known number of repeats, rather than letting rustyline get the number from the user.

gwenn commented 4 years ago

See https://github.com/kkawakam/rustyline/blob/master/src/keymap.rs#L449. And https://github.com/kkawakam/rustyline/blob/master/src/keymap.rs#L595. If the command is repeatable, the static/default number should be replaced by the dynamic/user number.

sophiajt commented 4 years ago

@gwenn - is this right mental model:

The repeat number is the one used when there is no numeric argument given in vi mode. If there is a numeric argument, it overwrites the numeric argument set by the keybinding

gwenn commented 4 years ago

Yes.

fdncred commented 4 years ago

@gwenn I'm working with @jonathandturner on keybindings in nushell and I'm having trouble figuring out how I can remap some of these Vi keybindings that you have in keymap.rs where instead of calling a Cmd::something function, you have a code block.

It may also be helpful to understand that we're trying to use a yml file to express keybindings so that end users can change them if they wish. Here's an example of our yaml for one command.

- key:
    Char: e
  binding:
    Move:
      ForwardWord:
        repeat: 1
        at: BeforeEnd
        word: Vi

And this is the corresponding function in your code that we created this yaml from.

KeyPress::Char('e') => Cmd::Move(Movement::ForwardWord(n, At::BeforeEnd, Word::Vi)),

With that in mind. I'd appreciate any advice you could give for functions like this. Since they don't call a direct function, but more of a code block, I'm not sure how we can expose them to the user to change. Any ideas?

    KeyPress::Char('a') => {
        // vi-append-mode
        self.input_mode = InputMode::Insert;
        wrt.doing_insert();
        Cmd::Move(Movement::ForwardChar(n))
    }
    KeyPress::Char('c') => {
        self.input_mode = InputMode::Insert;
        match self.vi_cmd_motion(rdr, wrt, key, n)? {
            Some(mvt) => Cmd::Replace(mvt, None),
            None => Cmd::Unknown,
        }
    }
gwenn commented 4 years ago

See https://github.com/kkawakam/rustyline/issues/306 And https://github.com/kkawakam/rustyline/pull/293#issuecomment-557862724 => We need to refactor / introduce an indirection between KeyPress and action(s).