mirror of
https://github.com/neovim/neovim.git
synced 2025-10-03 16:36:30 +00:00
fix(diagnostics): showing stale diagnostics in handlers #35890
Fixes #35884 Problem: Since `once_buf_loaded` might call a callback passed to it at a later point (which is it's reason to exist) that callback might end up referring to stale diagnostics in a handler's `show` function. For example, if we first call `vim.diagnostic.set` for an unloaded buffer, then call `vim.diagnostic.reset` and only then load the buffer, we might still see diagnostics from `vim.diagnostic.set` call, which are stale at this point. Solution: only keep one autocommand from the most reset `show` call and delete it when `hide` is called.
This commit is contained in:

committed by
GitHub

parent
237827a0da
commit
a1bc5d0ae6
@@ -1266,11 +1266,12 @@ end
|
|||||||
---
|
---
|
||||||
---@param bufnr integer Buffer number
|
---@param bufnr integer Buffer number
|
||||||
---@param fn fun()
|
---@param fn fun()
|
||||||
|
---@return integer?
|
||||||
local function once_buf_loaded(bufnr, fn)
|
local function once_buf_loaded(bufnr, fn)
|
||||||
if api.nvim_buf_is_loaded(bufnr) then
|
if api.nvim_buf_is_loaded(bufnr) then
|
||||||
fn()
|
fn()
|
||||||
else
|
else
|
||||||
api.nvim_create_autocmd('BufRead', {
|
return api.nvim_create_autocmd('BufRead', {
|
||||||
buffer = bufnr,
|
buffer = bufnr,
|
||||||
once = true,
|
once = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
@@ -1625,6 +1626,32 @@ function M.goto_next(opts)
|
|||||||
goto_diagnostic(M.get_next(opts), opts)
|
goto_diagnostic(M.get_next(opts), opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param autocmd_key string
|
||||||
|
---@param ns vim.diagnostic.NS
|
||||||
|
local function cleanup_show_autocmd(autocmd_key, ns)
|
||||||
|
if ns.user_data[autocmd_key] then
|
||||||
|
api.nvim_del_autocmd(ns.user_data[autocmd_key])
|
||||||
|
|
||||||
|
---@type integer?
|
||||||
|
ns.user_data[autocmd_key] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param autocmd_key string
|
||||||
|
---@param ns vim.diagnostic.NS
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param fn fun()
|
||||||
|
local function show_once_loaded(autocmd_key, ns, bufnr, fn)
|
||||||
|
cleanup_show_autocmd(autocmd_key, ns)
|
||||||
|
|
||||||
|
---@type integer?
|
||||||
|
ns.user_data[autocmd_key] = once_buf_loaded(bufnr, function()
|
||||||
|
---@type integer?
|
||||||
|
ns.user_data[autocmd_key] = nil
|
||||||
|
fn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
M.handlers.signs = {
|
M.handlers.signs = {
|
||||||
show = function(namespace, bufnr, diagnostics, opts)
|
show = function(namespace, bufnr, diagnostics, opts)
|
||||||
vim.validate('namespace', namespace, 'number')
|
vim.validate('namespace', namespace, 'number')
|
||||||
@@ -1636,12 +1663,12 @@ M.handlers.signs = {
|
|||||||
bufnr = vim._resolve_bufnr(bufnr)
|
bufnr = vim._resolve_bufnr(bufnr)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
once_buf_loaded(bufnr, function()
|
local ns = M.get_namespace(namespace)
|
||||||
|
show_once_loaded('sign_show_autocmd', ns, bufnr, function()
|
||||||
-- 10 is the default sign priority when none is explicitly specified
|
-- 10 is the default sign priority when none is explicitly specified
|
||||||
local priority = opts.signs and opts.signs.priority or 10
|
local priority = opts.signs and opts.signs.priority or 10
|
||||||
local get_priority = severity_to_extmark_priority(priority, opts)
|
local get_priority = severity_to_extmark_priority(priority, opts)
|
||||||
|
|
||||||
local ns = M.get_namespace(namespace)
|
|
||||||
if not ns.user_data.sign_ns then
|
if not ns.user_data.sign_ns then
|
||||||
ns.user_data.sign_ns =
|
ns.user_data.sign_ns =
|
||||||
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.signs', ns.name))
|
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.signs', ns.name))
|
||||||
@@ -1679,6 +1706,7 @@ M.handlers.signs = {
|
|||||||
--- @param bufnr integer
|
--- @param bufnr integer
|
||||||
hide = function(namespace, bufnr)
|
hide = function(namespace, bufnr)
|
||||||
local ns = M.get_namespace(namespace)
|
local ns = M.get_namespace(namespace)
|
||||||
|
cleanup_show_autocmd('sign_show_autocmd', ns)
|
||||||
if ns.user_data.sign_ns and api.nvim_buf_is_valid(bufnr) then
|
if ns.user_data.sign_ns and api.nvim_buf_is_valid(bufnr) then
|
||||||
api.nvim_buf_clear_namespace(bufnr, ns.user_data.sign_ns, 0, -1)
|
api.nvim_buf_clear_namespace(bufnr, ns.user_data.sign_ns, 0, -1)
|
||||||
end
|
end
|
||||||
@@ -1695,8 +1723,8 @@ M.handlers.underline = {
|
|||||||
bufnr = vim._resolve_bufnr(bufnr)
|
bufnr = vim._resolve_bufnr(bufnr)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
once_buf_loaded(bufnr, function()
|
local ns = M.get_namespace(namespace)
|
||||||
local ns = M.get_namespace(namespace)
|
show_once_loaded('underline_show_autocmd', ns, bufnr, function()
|
||||||
if not ns.user_data.underline_ns then
|
if not ns.user_data.underline_ns then
|
||||||
ns.user_data.underline_ns =
|
ns.user_data.underline_ns =
|
||||||
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.underline', ns.name))
|
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.underline', ns.name))
|
||||||
@@ -1735,6 +1763,7 @@ M.handlers.underline = {
|
|||||||
end,
|
end,
|
||||||
hide = function(namespace, bufnr)
|
hide = function(namespace, bufnr)
|
||||||
local ns = M.get_namespace(namespace)
|
local ns = M.get_namespace(namespace)
|
||||||
|
cleanup_show_autocmd('underline_show_autocmd', ns)
|
||||||
if ns.user_data.underline_ns then
|
if ns.user_data.underline_ns then
|
||||||
diagnostic_cache_extmarks[bufnr][ns.user_data.underline_ns] = {}
|
diagnostic_cache_extmarks[bufnr][ns.user_data.underline_ns] = {}
|
||||||
if api.nvim_buf_is_valid(bufnr) then
|
if api.nvim_buf_is_valid(bufnr) then
|
||||||
@@ -1791,7 +1820,8 @@ M.handlers.virtual_text = {
|
|||||||
bufnr = vim._resolve_bufnr(bufnr)
|
bufnr = vim._resolve_bufnr(bufnr)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
once_buf_loaded(bufnr, function()
|
local ns = M.get_namespace(namespace)
|
||||||
|
show_once_loaded('virtual_text_show_autocmd', ns, bufnr, function()
|
||||||
if opts.virtual_text then
|
if opts.virtual_text then
|
||||||
if opts.virtual_text.format then
|
if opts.virtual_text.format then
|
||||||
diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics)
|
diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics)
|
||||||
@@ -1804,7 +1834,6 @@ M.handlers.virtual_text = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local ns = M.get_namespace(namespace)
|
|
||||||
if not ns.user_data.virt_text_ns then
|
if not ns.user_data.virt_text_ns then
|
||||||
ns.user_data.virt_text_ns =
|
ns.user_data.virt_text_ns =
|
||||||
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_text', ns.name))
|
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_text', ns.name))
|
||||||
@@ -1842,6 +1871,7 @@ M.handlers.virtual_text = {
|
|||||||
end,
|
end,
|
||||||
hide = function(namespace, bufnr)
|
hide = function(namespace, bufnr)
|
||||||
local ns = M.get_namespace(namespace)
|
local ns = M.get_namespace(namespace)
|
||||||
|
cleanup_show_autocmd('virtual_text_show_autocmd', ns)
|
||||||
if ns.user_data.virt_text_ns then
|
if ns.user_data.virt_text_ns then
|
||||||
diagnostic_cache_extmarks[bufnr][ns.user_data.virt_text_ns] = {}
|
diagnostic_cache_extmarks[bufnr][ns.user_data.virt_text_ns] = {}
|
||||||
if api.nvim_buf_is_valid(bufnr) then
|
if api.nvim_buf_is_valid(bufnr) then
|
||||||
@@ -2053,8 +2083,8 @@ M.handlers.virtual_lines = {
|
|||||||
bufnr = vim._resolve_bufnr(bufnr)
|
bufnr = vim._resolve_bufnr(bufnr)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
once_buf_loaded(bufnr, function()
|
local ns = M.get_namespace(namespace)
|
||||||
local ns = M.get_namespace(namespace)
|
show_once_loaded('virtual_lines_show_autocmd', ns, bufnr, function()
|
||||||
if not ns.user_data.virt_lines_ns then
|
if not ns.user_data.virt_lines_ns then
|
||||||
ns.user_data.virt_lines_ns =
|
ns.user_data.virt_lines_ns =
|
||||||
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_lines', ns.name))
|
api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_lines', ns.name))
|
||||||
@@ -2101,6 +2131,7 @@ M.handlers.virtual_lines = {
|
|||||||
end,
|
end,
|
||||||
hide = function(namespace, bufnr)
|
hide = function(namespace, bufnr)
|
||||||
local ns = M.get_namespace(namespace)
|
local ns = M.get_namespace(namespace)
|
||||||
|
cleanup_show_autocmd('virtual_lines_show_autocmd', ns)
|
||||||
if ns.user_data.virt_lines_ns then
|
if ns.user_data.virt_lines_ns then
|
||||||
diagnostic_cache_extmarks[bufnr][ns.user_data.virt_lines_ns] = {}
|
diagnostic_cache_extmarks[bufnr][ns.user_data.virt_lines_ns] = {}
|
||||||
if api.nvim_buf_is_valid(bufnr) then
|
if api.nvim_buf_is_valid(bufnr) then
|
||||||
|
Reference in New Issue
Block a user