From 41fa343484685f5835672e7e7ce5863e9bb8ffbd Mon Sep 17 00:00:00 2001 From: TheBlob42 Date: Sun, 27 Jul 2025 22:10:00 +0200 Subject: [PATCH] fix(snippet): jumping backwards to choice node (#35062) Avoid duplicate text when jumping back to a choice node. Set cursor to end of tabstop range and prioritize current choice in completion items. (cherry picked from commit 628d569a594c762952b769776b9c79221fdb23d0) --- runtime/lua/vim/snippet.lua | 14 +++++++++++++- test/functional/lua/snippet_spec.lua | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 4ef86af16d..33c3e11e3d 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -257,10 +257,21 @@ local M = { session = nil } local function display_choices(tabstop) assert(tabstop.choices, 'Tabstop has no choices') + local text = tabstop:get_text() + local found_text = false + local start_col = tabstop:get_range()[2] + 1 local matches = {} --- @type table[] for _, choice in ipairs(tabstop.choices) do - matches[#matches + 1] = { word = choice } + if choice ~= text then + matches[#matches + 1] = { word = choice } + else + found_text = true + end + end + + if found_text then + table.insert(matches, 1, text) end vim.defer_fn(function() @@ -298,6 +309,7 @@ local function select_tabstop(tabstop) vim.cmd.startinsert({ bang = range[4] >= #vim.api.nvim_get_current_line() }) end if tabstop.choices then + vim.fn.cursor(range[3] + 1, range[4] + 1) display_choices(tabstop) end else diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 57b58e68bb..45141739b6 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -240,6 +240,23 @@ describe('vim.snippet', function() eq({ 'public function foo() {', '\t', '}' }, buf_lines(0)) end) + it('does not change the chosen text when jumping back to a choice tabstop', function() + test_expand_success( + { '${1|public,protected,private|} function ${2:name}() {', '\t$0', '}' }, + { ' function name() {', '\t', '}' } + ) + wait_for_pum() + feed('') + poke_eventloop() + feed('') + poke_eventloop() + wait_for_pum() + feed('') + poke_eventloop() + feed('foo') + eq({ 'protected function foo() {', '\t', '}' }, buf_lines(0)) + end) + it('jumps through adjacent tabstops', function() test_expand_success( { 'for i=1,${1:to}${2:,step} do\n\t$3\nend' },