mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(lsp): track snippet deletion
This commit is contained in:
		 Maria José Solano
					Maria José Solano
				
			
				
					committed by
					
						 Mathias Fußenegger
						Mathias Fußenegger
					
				
			
			
				
	
			
			
			 Mathias Fußenegger
						Mathias Fußenegger
					
				
			
						parent
						
							5e5f5174e3
						
					
				
				
					commit
					370232dbef
				
			| @@ -90,6 +90,18 @@ local function compute_tabstop_range(snippet, placeholder) | |||||||
|   return { start_row, start_col, end_row, end_col } |   return { start_row, start_col, end_row, end_col } | ||||||
| end | end | ||||||
|  |  | ||||||
|  | --- Returns the range spanned by the respective extmark. | ||||||
|  | --- | ||||||
|  | --- @param bufnr integer | ||||||
|  | --- @param extmark_id integer | ||||||
|  | --- @return Range4 | ||||||
|  | local function get_extmark_range(bufnr, extmark_id) | ||||||
|  |   local mark = vim.api.nvim_buf_get_extmark_by_id(bufnr, snippet_ns, extmark_id, { details = true }) | ||||||
|  |  | ||||||
|  |   --- @diagnostic disable-next-line: undefined-field | ||||||
|  |   return { mark[1], mark[2], mark[3].end_row, mark[3].end_col } | ||||||
|  | end | ||||||
|  |  | ||||||
| --- @class vim.snippet.Tabstop | --- @class vim.snippet.Tabstop | ||||||
| --- @field extmark_id integer | --- @field extmark_id integer | ||||||
| --- @field index integer | --- @field index integer | ||||||
| @@ -125,11 +137,7 @@ end | |||||||
| --- @package | --- @package | ||||||
| --- @return Range4 | --- @return Range4 | ||||||
| function Tabstop:get_range() | function Tabstop:get_range() | ||||||
|   local mark = |   return get_extmark_range(self.bufnr, self.extmark_id) | ||||||
|     vim.api.nvim_buf_get_extmark_by_id(self.bufnr, snippet_ns, self.extmark_id, { details = true }) |  | ||||||
|  |  | ||||||
|   --- @diagnostic disable-next-line: undefined-field |  | ||||||
|   return { mark[1], mark[2], mark[3].end_row, mark[3].end_col } |  | ||||||
| end | end | ||||||
|  |  | ||||||
| --- Returns the text spanned by the tabstop. | --- Returns the text spanned by the tabstop. | ||||||
| @@ -155,6 +163,7 @@ end | |||||||
|  |  | ||||||
| --- @class vim.snippet.Session | --- @class vim.snippet.Session | ||||||
| --- @field bufnr integer | --- @field bufnr integer | ||||||
|  | --- @field extmark_id integer | ||||||
| --- @field tabstops table<integer, vim.snippet.Tabstop[]> | --- @field tabstops table<integer, vim.snippet.Tabstop[]> | ||||||
| --- @field current_tabstop vim.snippet.Tabstop | --- @field current_tabstop vim.snippet.Tabstop | ||||||
| local Session = {} | local Session = {} | ||||||
| @@ -162,29 +171,27 @@ local Session = {} | |||||||
| --- Creates a new snippet session in the current buffer. | --- Creates a new snippet session in the current buffer. | ||||||
| --- | --- | ||||||
| --- @package | --- @package | ||||||
|  | --- @param bufnr integer | ||||||
|  | --- @param snippet_extmark integer | ||||||
|  | --- @param tabstop_ranges table<integer, Range4[]> | ||||||
| --- @return vim.snippet.Session | --- @return vim.snippet.Session | ||||||
| function Session.new() | function Session.new(bufnr, snippet_extmark, tabstop_ranges) | ||||||
|   local bufnr = vim.api.nvim_get_current_buf() |  | ||||||
|   local self = setmetatable({ |   local self = setmetatable({ | ||||||
|     bufnr = bufnr, |     bufnr = bufnr, | ||||||
|  |     extmark_id = snippet_extmark, | ||||||
|     tabstops = {}, |     tabstops = {}, | ||||||
|     current_tabstop = Tabstop.new(0, bufnr, { 0, 0, 0, 0 }), |     current_tabstop = Tabstop.new(0, bufnr, { 0, 0, 0, 0 }), | ||||||
|   }, { __index = Session }) |   }, { __index = Session }) | ||||||
|  |  | ||||||
|   return self |   -- Create the tabstops. | ||||||
| end |  | ||||||
|  |  | ||||||
| --- Creates the session tabstops. |  | ||||||
| --- |  | ||||||
| --- @package |  | ||||||
| --- @param tabstop_ranges table<integer, Range4[]> |  | ||||||
| function Session:set_tabstops(tabstop_ranges) |  | ||||||
|   for index, ranges in pairs(tabstop_ranges) do |   for index, ranges in pairs(tabstop_ranges) do | ||||||
|     for _, range in ipairs(ranges) do |     for _, range in ipairs(ranges) do | ||||||
|       self.tabstops[index] = self.tabstops[index] or {} |       self.tabstops[index] = self.tabstops[index] or {} | ||||||
|       table.insert(self.tabstops[index], Tabstop.new(index, self.bufnr, range)) |       table.insert(self.tabstops[index], Tabstop.new(index, self.bufnr, range)) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   return self | ||||||
| end | end | ||||||
|  |  | ||||||
| --- Returns the destination tabstop index when jumping in the given direction. | --- Returns the destination tabstop index when jumping in the given direction. | ||||||
| @@ -304,6 +311,15 @@ local function setup_autocmds(bufnr) | |||||||
|     desc = 'Update active tabstops when buffer text changes', |     desc = 'Update active tabstops when buffer text changes', | ||||||
|     buffer = bufnr, |     buffer = bufnr, | ||||||
|     callback = function() |     callback = function() | ||||||
|  |       -- Check that the snippet hasn't been deleted. | ||||||
|  |       local snippet_range = get_extmark_range(M._session.bufnr, M._session.extmark_id) | ||||||
|  |       if | ||||||
|  |         (snippet_range[1] == snippet_range[3] and snippet_range[2] == snippet_range[4]) | ||||||
|  |         or snippet_range[3] + 1 > vim.fn.line('$') | ||||||
|  |       then | ||||||
|  |         M.exit() | ||||||
|  |       end | ||||||
|  |  | ||||||
|       if not M.active() then |       if not M.active() then | ||||||
|         return true |         return true | ||||||
|       end |       end | ||||||
| @@ -331,8 +347,6 @@ function M.expand(input) | |||||||
|   local snippet = G.parse(input) |   local snippet = G.parse(input) | ||||||
|   local snippet_text = {} |   local snippet_text = {} | ||||||
|  |  | ||||||
|   M._session = Session.new() |  | ||||||
|  |  | ||||||
|   -- Get the placeholders we should use for each tabstop index. |   -- Get the placeholders we should use for each tabstop index. | ||||||
|   --- @type table<integer, string> |   --- @type table<integer, string> | ||||||
|   local placeholders = {} |   local placeholders = {} | ||||||
| @@ -427,19 +441,21 @@ function M.expand(input) | |||||||
|     add_tabstop(0) |     add_tabstop(0) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   -- Insert the snippet text. |   snippet_text = text_to_lines(snippet_text) | ||||||
|   local cursor_row, cursor_col = cursor_pos() |  | ||||||
|   vim.api.nvim_buf_set_text( |  | ||||||
|     M._session.bufnr, |  | ||||||
|     cursor_row, |  | ||||||
|     cursor_col, |  | ||||||
|     cursor_row, |  | ||||||
|     cursor_col, |  | ||||||
|     text_to_lines(snippet_text) |  | ||||||
|   ) |  | ||||||
|  |  | ||||||
|   -- Create the tabstops. |   -- Insert the snippet text. | ||||||
|   M._session:set_tabstops(tabstop_ranges) |   local bufnr = vim.api.nvim_get_current_buf() | ||||||
|  |   local cursor_row, cursor_col = cursor_pos() | ||||||
|  |   vim.api.nvim_buf_set_text(bufnr, cursor_row, cursor_col, cursor_row, cursor_col, snippet_text) | ||||||
|  |  | ||||||
|  |   -- Create the session. | ||||||
|  |   local snippet_extmark = vim.api.nvim_buf_set_extmark(bufnr, snippet_ns, cursor_row, cursor_col, { | ||||||
|  |     end_line = cursor_row + #snippet_text - 1, | ||||||
|  |     end_col = #snippet_text > 1 and #snippet_text[#snippet_text] or cursor_col + #snippet_text[1], | ||||||
|  |     right_gravity = false, | ||||||
|  |     end_right_gravity = true, | ||||||
|  |   }) | ||||||
|  |   M._session = Session.new(bufnr, snippet_extmark, tabstop_ranges) | ||||||
|  |  | ||||||
|   -- Jump to the first tabstop. |   -- Jump to the first tabstop. | ||||||
|   M.jump(1) |   M.jump(1) | ||||||
|   | |||||||
| @@ -154,4 +154,10 @@ describe('vim.snippet', function() | |||||||
|   it('errors with multiple $0 tabstops', function() |   it('errors with multiple $0 tabstops', function() | ||||||
|     test_fail('function $1() { $0 }$0', 'multiple $0 tabstops') |     test_fail('function $1() { $0 }$0', 'multiple $0 tabstops') | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|  |   it('cancels session when deleting the snippet', function() | ||||||
|  |     test_success({ 'local function $1()', '  $0', 'end' }, { 'local function ()', '  ', 'end' }) | ||||||
|  |     feed('<esc>Vjjd') | ||||||
|  |     eq(false, exec_lua('return vim.snippet.active()')) | ||||||
|  |   end) | ||||||
| end) | end) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user