mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(diagnostics): avoid jumping to diagnostics in deleted ranges #35088
Problem: diagnostic extmark used for positioning continues to exist after deleting a range containing it, so it's possible to jump to a next/previous diagnositc, which isn't visible in any way, including not being shown via `open_float`. Solution: enable `invalidate` flag when setting an extmark to be able to filter out diagnostics based on `invalid` flag when looking for next/previous diagnostic to jump to.
This commit is contained in:
		 Sergei Slipchenko
					Sergei Slipchenko
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							5151f635ca
						
					
				
				
					commit
					7a051a4c38
				
			| @@ -648,6 +648,7 @@ local sign_highlight_map = make_highlight_map('Sign') | |||||||
| --- @return integer col | --- @return integer col | ||||||
| --- @return integer end_lnum | --- @return integer end_lnum | ||||||
| --- @return integer end_col | --- @return integer end_col | ||||||
|  | --- @return boolean valid | ||||||
| local function get_logical_pos(diagnostic) | local function get_logical_pos(diagnostic) | ||||||
|   local ns = M.get_namespace(diagnostic.namespace) |   local ns = M.get_namespace(diagnostic.namespace) | ||||||
|   local extmark = api.nvim_buf_get_extmark_by_id( |   local extmark = api.nvim_buf_get_extmark_by_id( | ||||||
| @@ -657,7 +658,7 @@ local function get_logical_pos(diagnostic) | |||||||
|     { details = true } |     { details = true } | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
|   return extmark[1], extmark[2], extmark[3].end_row, extmark[3].end_col |   return extmark[1], extmark[2], extmark[3].end_row, extmark[3].end_col, not extmark[3].invalid | ||||||
| end | end | ||||||
|  |  | ||||||
| --- @param diagnostics vim.Diagnostic[] | --- @param diagnostics vim.Diagnostic[] | ||||||
| @@ -669,7 +670,8 @@ local function diagnostic_lines(diagnostics) | |||||||
|  |  | ||||||
|   local diagnostics_by_line = {} --- @type table<integer,vim.Diagnostic[]> |   local diagnostics_by_line = {} --- @type table<integer,vim.Diagnostic[]> | ||||||
|   for _, diagnostic in ipairs(diagnostics) do |   for _, diagnostic in ipairs(diagnostics) do | ||||||
|     local lnum = get_logical_pos(diagnostic) |     local lnum, _, _, _, valid = get_logical_pos(diagnostic) | ||||||
|  |     if valid then | ||||||
|       local line_diagnostics = diagnostics_by_line[lnum] |       local line_diagnostics = diagnostics_by_line[lnum] | ||||||
|       if not line_diagnostics then |       if not line_diagnostics then | ||||||
|         line_diagnostics = {} |         line_diagnostics = {} | ||||||
| @@ -677,6 +679,7 @@ local function diagnostic_lines(diagnostics) | |||||||
|       end |       end | ||||||
|       table.insert(line_diagnostics, diagnostic) |       table.insert(line_diagnostics, diagnostic) | ||||||
|     end |     end | ||||||
|  |   end | ||||||
|   return diagnostics_by_line |   return diagnostics_by_line | ||||||
| end | end | ||||||
|  |  | ||||||
| @@ -1332,6 +1335,7 @@ function M.set(namespace, bufnr, diagnostics, opts) | |||||||
|       diagnostic._extmark_id = api.nvim_buf_set_extmark(bufnr, ns.user_data.location_ns, row, col, { |       diagnostic._extmark_id = api.nvim_buf_set_extmark(bufnr, ns.user_data.location_ns, row, col, { | ||||||
|         end_row = end_row, |         end_row = end_row, | ||||||
|         end_col = end_col, |         end_col = end_col, | ||||||
|  |         invalidate = true, | ||||||
|       }) |       }) | ||||||
|     end |     end | ||||||
|   end) |   end) | ||||||
|   | |||||||
| @@ -1433,15 +1433,6 @@ describe('vim.diagnostic', function() | |||||||
|  |  | ||||||
|     describe('after inserting text before diagnostic position', function() |     describe('after inserting text before diagnostic position', function() | ||||||
|       before_each(function() |       before_each(function() | ||||||
|         exec_lua(function() |  | ||||||
|           vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) |  | ||||||
|  |  | ||||||
|           vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { |  | ||||||
|             _G.make_error('Diagnostic #1', 1, 4, 1, 7), |  | ||||||
|             _G.make_error('Diagnostic #2', 3, 0, 3, 3), |  | ||||||
|           }) |  | ||||||
|         end) |  | ||||||
|  |  | ||||||
|         api.nvim_buf_set_text(0, 3, 0, 3, 0, { 'new line', 'new ' }) |         api.nvim_buf_set_text(0, 3, 0, 3, 0, { 'new line', 'new ' }) | ||||||
|       end) |       end) | ||||||
|  |  | ||||||
| @@ -1449,7 +1440,7 @@ describe('vim.diagnostic', function() | |||||||
|         eq( |         eq( | ||||||
|           { 5, 4 }, |           { 5, 4 }, | ||||||
|           exec_lua(function() |           exec_lua(function() | ||||||
|             vim.api.nvim_win_set_cursor(0, { 2, 4 }) |             vim.api.nvim_win_set_cursor(0, { 3, 1 }) | ||||||
|             vim.diagnostic.jump({ count = 1 }) |             vim.diagnostic.jump({ count = 1 }) | ||||||
|             return vim.api.nvim_win_get_cursor(0) |             return vim.api.nvim_win_get_cursor(0) | ||||||
|           end) |           end) | ||||||
| @@ -1471,8 +1462,6 @@ describe('vim.diagnostic', function() | |||||||
|     describe('if diagnostic is set after last character in line', function() |     describe('if diagnostic is set after last character in line', function() | ||||||
|       before_each(function() |       before_each(function() | ||||||
|         exec_lua(function() |         exec_lua(function() | ||||||
|           vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) |  | ||||||
|  |  | ||||||
|           vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { |           vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { | ||||||
|             _G.make_error('Diagnostic #1', 2, 3, 3, 4), |             _G.make_error('Diagnostic #1', 2, 3, 3, 4), | ||||||
|           }) |           }) | ||||||
| @@ -1501,6 +1490,34 @@ describe('vim.diagnostic', function() | |||||||
|         ) |         ) | ||||||
|       end) |       end) | ||||||
|     end) |     end) | ||||||
|  |  | ||||||
|  |     describe('after entire text range with a diagnostic was deleted', function() | ||||||
|  |       before_each(function() | ||||||
|  |         api.nvim_buf_set_text(0, 1, 1, 1, 4, {}) | ||||||
|  |       end) | ||||||
|  |  | ||||||
|  |       it('does not find next diagnostic inside the deleted range', function() | ||||||
|  |         eq( | ||||||
|  |           { 3, 0 }, | ||||||
|  |           exec_lua(function() | ||||||
|  |             vim.api.nvim_win_set_cursor(0, { 1, 0 }) | ||||||
|  |             vim.diagnostic.jump({ count = 1 }) | ||||||
|  |             return vim.api.nvim_win_get_cursor(0) | ||||||
|  |           end) | ||||||
|  |         ) | ||||||
|  |       end) | ||||||
|  |  | ||||||
|  |       it('does not find previous diagnostic inside the deleted range', function() | ||||||
|  |         eq( | ||||||
|  |           { 1, 0 }, | ||||||
|  |           exec_lua(function() | ||||||
|  |             vim.api.nvim_win_set_cursor(0, { 3, 0 }) | ||||||
|  |             vim.diagnostic.jump({ count = -1 }) | ||||||
|  |             return vim.api.nvim_win_get_cursor(0) | ||||||
|  |           end) | ||||||
|  |         ) | ||||||
|  |       end) | ||||||
|  |     end) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   describe('get()', function() |   describe('get()', function() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user