Search code examples
neovimkey-bindingsediting

Unexpected behaviour of Neovim in insert mode when executing many key-bindings


I recently switched from Vim to Neovim (the latest version).

I have the following key-bindings in Neovim:

vim.keymap.set("i", "0", "<Esc>la", { noremap = true }) 
vim.keymap.set("i", "00", "0", { noremap = true })  
vim.keymap.set("i", "[]", "{}<Esc>ha", { noremap = true })

When I press 0[] in quick succession, I expect the cursor to move one step forward and write {} with cursor inside the braces (this is how Vim used to behave).

However, what I get is that the cursor moves one step forward and writes [] on the screen (instead of curly braces).

So, I have two questions:

  1. Is this a feature of Neovim which is deliberately different from Vim, or is it unintended?

  2. Can I set up Neovim so that it behaves like Vim in this regard?

I did notice that deleting the middle key-binding (the one which maps 00 to 0) produces the expected behaviour.

[Cross-posted on Vi and Vim and this behaviour was reproduced by another user.]


Solution

  • This is a feature and it is deliberate: whenever you have multiple key bindings that begin with the same key, there will be a time-out length to allow the user to press additional keys. This allows access to other key mappings.

    Currently, you have two mappings that begin with 0. So, upon pressing 0, Neovim waits to see if the subsequent key press will be another key that corresponds to another mapping that also begins with 0 (in this case, the 00 mapping). When you press [ it realises this isn't the 00 mapping invocation and thus executes the mapping for 0. The mapping for 0 leaves you in append mode, then Neovim registers and types the [ keypress followed by your subsequent key press(es) (i.e. ]).

    You have three basic options to get your desired behaviour:

    1. Press 0 then wait for the timeout length to finish and then press []. The timeout length can be adjusted by adding, for example,vim.opt.timeoutlen = 200 to your configuration.
    2. Remove the 00 key mapping.
    3. In addition to your other key mappings, add a direct mapping that performs the desired action (instead of attempting to perform the action indirectly via two separate key maps) i.e.
    vim.keymap.set({'i'}, '0[]', '<Esc>la{}<Esc>ha', { noremap = true })
    

    Ideally, one would set a per key mapping timeout length. However, this feature does not currently exist. GitHub issue 12093 is open and tracking such a feature request.

    Alternatively, some users use an auto-command to change the timeout length upon entering insert mode, and then another auto-command to change it back when leaving insert mode. This has the benefit of not affecting the timeout length of key mappings in other modes, however, this may cause issues with plug-ins.