refactor(keymap): improve fallback and key handling
Things I want to test/fix:
- [ ] Handle multi-key sequences Issue: #453
{
['jk'] = { 'hide', 'fallback' },
['<C-x><C-o>'] = { 'show', 'fallback' },
['<Leader>cc'] = { 'show', 'fallback' },
}
- [ ] Preserve key special notation when fallback Issue: #2119
vim.keymap.set('i', '<C-i>', function() vim.print('fallback to <C-i>') end, { unique = false })
vim.keymap.set('i', '<Tab>', function() vim.print('fallback to <Tab>') end, { unique = false })
vim.keymap.set('i', '<C-m>', function() vim.print('fallback to <C-m>') end, { unique = false })
{
['<C-i>'] = { 'accept', 'snippet_forward', 'fallback' }, -- when fall back prints "fallback to <C-i>"
['<C-m>'] = { 'accept', 'fallback' }, -- when fall back prints "fallback to <C-m>"
}
- [ ] Key composition
{
['<C-n>'] = { 'select_next' },
['<Tab>'] = {
function() return '' end, -- would fallback
function() return '<C-n>' end, -- would call `select_next`
},
},
- [ ] Recursive keymap
vim.keymap.set('i', '<F2>', '<Esc>:echo "Hello from F2"<CR>a', { noremap = true, silent = true })
{
['<Space><Space>'] = { function() return '<F2>' end }, -- would print "Hello from F2"
}
- [ ] Handle script mappings correctly:
<SNR>,<SID>,<Plug>Issue: #714
vim.cmd([[
function! s:MyFunction()
echo "script local function invoked"
endfunction
nnoremap <silent> <SNR>42_mykey :call <SID>MyFunction()<CR>
nnoremap <silent> <Plug>(MyPlug) :echo "Plug mapping triggered"<CR>
]])
{
['<Leader>m'] = { function() return '<Esc><Plug>(MyPlug)a' end }, -- prints "Plug mapping triggered"
}
- [ ] Apply blink.cmp keymaps eagerly when triggering snippets from normal mode Issue: #2164
- [ ] Reapply blink.cmp keymaps if stolen by others Issue: #406
- [ ] Refactoring:
- [ ] Consolidate and keep the
keymapmodule as simply as possible - [ ] Don't rely anymore on
expr, - [ ] Drop the
vim.schedulein all commands and return boolean value from the function itself:
- [ ] Consolidate and keep the
- vim.schedule(function() completion_list.accept(opts) end)
- return true
+ return completion_list.accept(opts)
- [ ] Documentation: Revamp the keymap section Issue: #2182
Long-standing issue fixed!
I was curious because I couldn't find any neovim issues about it, so I tinker a bit and found that we cannot rely on expr when using multi-key sequences. The fix is actually pretty simple and works reliably :smile:. If I have faith I'll rework a bit the keymap section in the documentation to include this in another PR.
Does calling feedkeys have any caveats that we should be aware of? If not, I'd like to adopt it for all the keymaps! Avoiding expr = true would avoid having to vim.schedule anything that edits the buffer, which would be great for scriptability. I don't mind the way you're detecting multi-key mappings but it would be great if there was a less hacky way (maybe replace_keycodes could help?)
Thanks for the feedback, you give me some additional thinking! I'd like to explore this approach a bit more. The feedkeys solution does seem cleaner and we could get rid of multi-key detection if we turn off expr.
Edit: Updated PR description
Wow this is quite a bit of work, you'd end up fixing all the major issues with keymaps! These changes would be breaking, since theyre no longer vim.schedule so it might make sense to artificially vim.schedule or merge this into a new v2 branch.
Fyi, I got a bit ambitious with v2 so I'm going to reduce its scope. Just planning some light refactoring, these keymap changes, source-per-LSP, adopt blink.lib, and the improved API (for keymaps, enable, vim.g, dynamic config, etc)
Yeah, as long as I'm here, I might as well fix these issues once and for all. I've had promising results locally. I don't mind working on this for v2, but last time I switched to this branch, everything was so broken that it was hard to make any convincing commits. Feel free to keep in touch on Matrix to coordinate!