feat(snippet): set snippet keymaps permanent instead of dynamic (#31887)

Problem:

Given that `vim.snippet.expand()` sets temporary `<tab>`/`<s-tab>`
keymaps there is no way to build "smart-tab" functionality where `<tab>`
chooses the next completion candidate if the popup menu is visible.

Solution:

Set the keymap permanent in `_defaults`.

The downside of this approach is that users of multiple snippet engine's
need to adapt their keymaps to handle all their engines that are in use.
For example:

    vim.keymap.set({ 'i', 's' }, "<Tab>", function()
      if foreign_snippet.active() then
        return "<Cmd>lua require('foreign_snippet').jump()<CR>"
      elseif vim.snippet.active({ direction = 1 }) then
        return "<Cmd>lua vim.snippet.jump(1)<CR>"
      else
        return key
      end
    end, { expr = true })

Upside is that using `vim.keymap.set` to override keymaps is a well
established pattern and `vim.snippet.expand` calls made by nvim itself
or plugins have working keymaps out of the box.


Co-authored-by: Maria José Solano <majosolano99@gmail.com>
This commit is contained in:
Mathias Fußenegger
2025-03-14 09:51:52 +01:00
committed by GitHub
parent 6401b433f7
commit 123f8d229e
5 changed files with 43 additions and 106 deletions

View File

@@ -218,6 +218,27 @@ do
end, { desc = 'vim.lsp.buf.signature_help()' })
end
do
---@param direction vim.snippet.Direction
---@param key string
local function set_snippet_jump(direction, key)
vim.keymap.set({ 'i', 's' }, key, function()
if vim.snippet.active({ direction = direction }) then
return string.format('<Cmd>lua vim.snippet.jump(%d)<CR>', direction)
else
return key
end
end, {
desc = 'vim.snippet.jump if active, otherwise ' .. key,
expr = true,
silent = true,
})
end
set_snippet_jump(1, '<Tab>')
set_snippet_jump(-1, '<S-Tab>')
end
--- Map [d and ]d to move to the previous/next diagnostic. Map <C-W>d to open a floating window
--- for the diagnostic under the cursor.
---