neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 701258921ed1dcd81d51c02051bd04967088ed23
parent 25bc41847e495aa55ede1090f29afd2a1709b0b4
Author: TheBlob42 <hessenmobbel@web.de>
Date:   Tue, 19 Aug 2025 15:21:32 +0200

feat(snippet): highlight active tabstop (#35378)


Diffstat:
Mruntime/colors/vim.lua | 1+
Mruntime/doc/lua.txt | 3++-
Mruntime/doc/news.txt | 1+
Mruntime/doc/syntax.txt | 3+++
Mruntime/lua/vim/snippet.lua | 13+++++++++----
Msrc/nvim/highlight_group.c | 1+
Mtest/functional/lua/snippet_spec.lua | 14++++++++++++++
7 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/runtime/colors/vim.lua b/runtime/colors/vim.lua @@ -134,6 +134,7 @@ hi('DiagnosticDeprecated', { sp = 'Red', strikethrough = true, cterm = hi('DiagnosticUnnecessary', { link = 'Comment' }) hi('LspInlayHint', { link = 'NonText' }) hi('SnippetTabstop', { link = 'Visual' }) +hi('SnippetTabstopActive', { link = 'SnippetTabstop' }) -- Text hi('@markup.raw', { link = 'Comment' }) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt @@ -4354,7 +4354,8 @@ vim.snippet.expand({input}) *vim.snippet.expand()* https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax for the specification of valid input. - Tabstops are highlighted with |hl-SnippetTabstop|. + Tabstops are highlighted with |hl-SnippetTabstop| and + |hl-SnippetTabstopActive|. Parameters: ~ • {input} (`string`) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt @@ -192,6 +192,7 @@ HIGHLIGHTS • |hl-DiffTextAdd| highlights added text within a changed line. • |hl-StderrMsg| |hl-StdoutMsg| +• |hl-SnippetTabstopActive| highlights the currently active tabstop. LSP diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt @@ -5343,6 +5343,9 @@ Search Last search pattern highlighting (see 'hlsearch'). Also used for similar items that need to stand out. *hl-SnippetTabstop* SnippetTabstop Tabstops in snippets. |vim.snippet| + *hl-SnippetTabstopActive* +SnippetTabstopActive + The currently active tabstop. |vim.snippet| *hl-SpecialKey* SpecialKey Unprintable characters: Text displayed differently from what it really is. But not 'listchars' whitespace. |hl-Whitespace| diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua @@ -2,6 +2,7 @@ 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 hl_group_active = 'SnippetTabstopActive' --- Returns the 0-based cursor position. --- @@ -124,7 +125,7 @@ function Tabstop.new(index, bufnr, placement, range, choices) end_right_gravity = false, end_line = range[3], end_col = range[4], - hl_group = hl_group, + hl_group = index == 1 and hl_group_active or hl_group, }) local self = setmetatable({ @@ -168,19 +169,22 @@ function Tabstop:set_text(text) end ---@alias (private) vim.snippet.TabStopGravity ---- | "expand" Expand the (usually current) tabstop on text insert +--- | "expand" Expand the current tabstop on text insert --- | "lock" The tabstop should NOT move on text insert --- | "shift" The tabstop should move on text insert (default) --- Sets the right gravity of the tabstop's extmark. +--- Sets the active highlight group for current ("expand") tabstops --- ---@package ---@param target vim.snippet.TabStopGravity function Tabstop:set_gravity(target) + local hl = hl_group local right_gravity = true local end_right_gravity = true if target == 'expand' then + hl = hl_group_active right_gravity = false end_right_gravity = true elseif target == 'lock' then @@ -189,12 +193,13 @@ function Tabstop:set_gravity(target) end local range = self:get_range() + vim.api.nvim_buf_del_extmark(self.bufnr, snippet_ns, self.extmark_id) self.extmark_id = vim.api.nvim_buf_set_extmark(self.bufnr, snippet_ns, range[1], range[2], { right_gravity = right_gravity, end_right_gravity = end_right_gravity, end_line = range[3], end_col = range[4], - hl_group = hl_group, + hl_group = hl, }) end @@ -469,7 +474,7 @@ end --- Refer to https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax --- for the specification of valid input. --- ---- Tabstops are highlighted with |hl-SnippetTabstop|. +--- Tabstops are highlighted with |hl-SnippetTabstop| and |hl-SnippetTabstopActive|. --- --- @param input string function M.expand(input) diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c @@ -221,6 +221,7 @@ static const char *highlight_init_both[] = { "default link LspReferenceTarget LspReferenceText", "default link LspSignatureActiveParameter Visual", "default link SnippetTabstop Visual", + "default link SnippetTabstopActive SnippetTabstop", // Diagnostic "default link DiagnosticFloatingError DiagnosticError", diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua @@ -116,6 +116,20 @@ describe('vim.snippet', function() test_expand_success({ 'print($UNKNOWN)' }, { 'print(UNKNOWN)' }) end) + it('highlights active tabstop with SnippetTabstopActive', function() + local function get_extmark_details(col, end_col) + return api.nvim_buf_get_extmarks(0, -1, { 0, col }, { 0, end_col }, { details = true })[1][4] + end + + test_expand_success({ 'local ${1:name} = ${2:value}' }, { 'local name = value' }) + eq('SnippetTabstopActive', get_extmark_details(6, 10).hl_group) + eq('SnippetTabstop', get_extmark_details(13, 18).hl_group) + feed('<Tab>') + poke_eventloop() + eq('SnippetTabstop', get_extmark_details(6, 10).hl_group) + eq('SnippetTabstopActive', get_extmark_details(13, 18).hl_group) + end) + it('does not jump outside snippet range', function() test_expand_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) eq(false, exec_lua('return vim.snippet.active({ direction = -1 })'))