From 123f8d229eef05869ee4c98dfd4934c22a03b1f6 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 14 Mar 2025 09:51:52 +0100 Subject: feat(snippet): set snippet keymaps permanent instead of dynamic (#31887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Given that `vim.snippet.expand()` sets temporary ``/`` keymaps there is no way to build "smart-tab" functionality where `` 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' }, "", function() if foreign_snippet.active() then return "lua require('foreign_snippet').jump()" elseif vim.snippet.active({ direction = 1 }) then return "lua vim.snippet.jump(1)" 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 --- runtime/lua/vim/snippet.lua | 75 ++------------------------------------------- 1 file changed, 2 insertions(+), 73 deletions(-) (limited to 'runtime/lua/vim/snippet.lua') diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index bfd439181e..2edea6d5ad 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -2,8 +2,6 @@ local G = vim.lsp._snippet_grammar local snippet_group = vim.api.nvim_create_augroup('nvim.snippet', {}) local snippet_ns = vim.api.nvim_create_namespace('nvim.snippet') local hl_group = 'SnippetTabstop' -local jump_forward_key = '' -local jump_backward_key = '' --- Returns the 0-based cursor position. --- @@ -213,64 +211,9 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) end end - self:set_keymaps() - return self end ---- Sets the snippet navigation keymaps. ---- ---- @package -function Session:set_keymaps() - local function maparg(key, mode) - local map = vim.fn.maparg(key, mode, false, true) --[[ @as table ]] - if not vim.tbl_isempty(map) and map.buffer == 1 then - return map - else - return nil - end - end - - local function set(jump_key, direction) - vim.keymap.set({ 'i', 's' }, jump_key, function() - return vim.snippet.active({ direction = direction }) - and 'lua vim.snippet.jump(' .. direction .. ')' - or jump_key - end, { expr = true, silent = true, buffer = self.bufnr }) - end - - self.tab_keymaps = { - i = maparg(jump_forward_key, 'i'), - s = maparg(jump_forward_key, 's'), - } - self.shift_tab_keymaps = { - i = maparg(jump_backward_key, 'i'), - s = maparg(jump_backward_key, 's'), - } - set(jump_forward_key, 1) - set(jump_backward_key, -1) -end - ---- Restores/deletes the keymaps used for snippet navigation. ---- ---- @package -function Session:restore_keymaps() - local function restore(keymap, lhs, mode) - if keymap then - vim._with({ buf = self.bufnr }, function() - vim.fn.mapset(keymap) - end) - else - vim.api.nvim_buf_del_keymap(self.bufnr, mode, lhs) - end - end - - restore(self.tab_keymaps.i, jump_forward_key, 'i') - restore(self.tab_keymaps.s, jump_forward_key, 's') - restore(self.shift_tab_keymaps.i, jump_backward_key, 'i') - restore(self.shift_tab_keymaps.s, jump_backward_key, 's') -end - --- Returns the destination tabstop index when jumping in the given direction. --- --- @package @@ -604,7 +547,7 @@ end --- Jumps to the next (or previous) placeholder in the current snippet, if possible. --- ---- For example, map `` to jump while a snippet is active: +--- By default `` is setup to jump if a snippet is active. The default mapping looks like: --- --- ```lua --- vim.keymap.set({ 'i', 's' }, '', function() @@ -613,7 +556,7 @@ end --- else --- return '' --- end ---- end, { expr = true }) +--- end, { descr = '...', expr = true, silent = true }) --- ``` --- --- @param direction (vim.snippet.Direction) Navigation direction. -1 for previous, 1 for next. @@ -656,18 +599,6 @@ end --- Returns `true` if there's an active snippet in the current buffer, --- applying the given filter if provided. --- ---- You can use this function to navigate a snippet as follows: ---- ---- ```lua ---- vim.keymap.set({ 'i', 's' }, '', function() ---- if vim.snippet.active({ direction = 1 }) then ---- return 'lua vim.snippet.jump(1)' ---- else ---- return '' ---- end ---- end, { expr = true }) ---- ``` ---- --- @param filter? vim.snippet.ActiveFilter Filter to constrain the search with: --- - `direction` (vim.snippet.Direction): Navigation direction. Will return `true` if the snippet --- can be jumped in the given direction. @@ -689,8 +620,6 @@ function M.stop() return end - M._session:restore_keymaps() - vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._session.bufnr }) vim.api.nvim_buf_clear_namespace(M._session.bufnr, snippet_ns, 0, -1) -- cgit