diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index e8805bc288..d7c1933104 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -1636,45 +1636,43 @@ M.handlers.signs = { bufnr = vim._resolve_bufnr(bufnr) opts = opts or {} - if not api.nvim_buf_is_loaded(bufnr) then - return - end + once_buf_loaded(bufnr, function() + -- 10 is the default sign priority when none is explicitly specified + local priority = opts.signs and opts.signs.priority or 10 + local get_priority = severity_to_extmark_priority(priority, opts) - -- 10 is the default sign priority when none is explicitly specified - local priority = opts.signs and opts.signs.priority or 10 - local get_priority = severity_to_extmark_priority(priority, opts) - - local ns = M.get_namespace(namespace) - if not ns.user_data.sign_ns then - ns.user_data.sign_ns = - api.nvim_create_namespace(string.format('nvim.%s.diagnostic.signs', ns.name)) - end - - local text = {} ---@type table - for k in pairs(M.severity) do - if opts.signs.text and opts.signs.text[k] then - text[k] = opts.signs.text[k] - elseif type(k) == 'string' and not text[k] then - text[k] = k:sub(1, 1):upper() + local ns = M.get_namespace(namespace) + if not ns.user_data.sign_ns then + ns.user_data.sign_ns = + api.nvim_create_namespace(string.format('nvim.%s.diagnostic.signs', ns.name)) end - end - local numhl = opts.signs.numhl or {} - local linehl = opts.signs.linehl or {} - - local line_count = api.nvim_buf_line_count(bufnr) - - for _, diagnostic in ipairs(diagnostics) do - if diagnostic.lnum <= line_count then - api.nvim_buf_set_extmark(bufnr, ns.user_data.sign_ns, diagnostic.lnum, 0, { - sign_text = text[diagnostic.severity] or text[M.severity[diagnostic.severity]] or 'U', - sign_hl_group = sign_highlight_map[diagnostic.severity], - number_hl_group = numhl[diagnostic.severity], - line_hl_group = linehl[diagnostic.severity], - priority = get_priority(diagnostic.severity), - }) + local text = {} ---@type table + for k in pairs(M.severity) do + if opts.signs.text and opts.signs.text[k] then + text[k] = opts.signs.text[k] + elseif type(k) == 'string' and not text[k] then + text[k] = k:sub(1, 1):upper() + end end - end + + local numhl = opts.signs.numhl or {} + local linehl = opts.signs.linehl or {} + + local line_count = api.nvim_buf_line_count(bufnr) + + for _, diagnostic in ipairs(diagnostics) do + if diagnostic.lnum <= line_count then + api.nvim_buf_set_extmark(bufnr, ns.user_data.sign_ns, diagnostic.lnum, 0, { + sign_text = text[diagnostic.severity] or text[M.severity[diagnostic.severity]] or 'U', + sign_hl_group = sign_highlight_map[diagnostic.severity], + number_hl_group = numhl[diagnostic.severity], + line_hl_group = linehl[diagnostic.severity], + priority = get_priority(diagnostic.severity), + }) + end + end + end) end, --- @param namespace integer @@ -1697,45 +1695,43 @@ M.handlers.underline = { bufnr = vim._resolve_bufnr(bufnr) opts = opts or {} - if not api.nvim_buf_is_loaded(bufnr) then - return - end - - local ns = M.get_namespace(namespace) - if not ns.user_data.underline_ns then - ns.user_data.underline_ns = - api.nvim_create_namespace(string.format('nvim.%s.diagnostic.underline', ns.name)) - end - - local underline_ns = ns.user_data.underline_ns - local get_priority = severity_to_extmark_priority(vim.hl.priorities.diagnostics, opts) - - for _, diagnostic in ipairs(diagnostics) do - local higroup = underline_highlight_map[diagnostic.severity] - - if diagnostic._tags then - -- TODO(lewis6991): we should be able to stack these. - if diagnostic._tags.unnecessary then - higroup = 'DiagnosticUnnecessary' - end - if diagnostic._tags.deprecated then - higroup = 'DiagnosticDeprecated' - end + once_buf_loaded(bufnr, function() + local ns = M.get_namespace(namespace) + if not ns.user_data.underline_ns then + ns.user_data.underline_ns = + api.nvim_create_namespace(string.format('nvim.%s.diagnostic.underline', ns.name)) end - local lines = - api.nvim_buf_get_lines(diagnostic.bufnr, diagnostic.lnum, diagnostic.lnum + 1, true) + local underline_ns = ns.user_data.underline_ns + local get_priority = severity_to_extmark_priority(vim.hl.priorities.diagnostics, opts) - vim.hl.range( - bufnr, - underline_ns, - higroup, - { diagnostic.lnum, math.min(diagnostic.col, #lines[1] - 1) }, - { diagnostic.end_lnum, diagnostic.end_col }, - { priority = get_priority(diagnostic.severity) } - ) - end - save_extmarks(underline_ns, bufnr) + for _, diagnostic in ipairs(diagnostics) do + local higroup = underline_highlight_map[diagnostic.severity] + + if diagnostic._tags then + -- TODO(lewis6991): we should be able to stack these. + if diagnostic._tags.unnecessary then + higroup = 'DiagnosticUnnecessary' + end + if diagnostic._tags.deprecated then + higroup = 'DiagnosticDeprecated' + end + end + + local lines = + api.nvim_buf_get_lines(diagnostic.bufnr, diagnostic.lnum, diagnostic.lnum + 1, true) + + vim.hl.range( + bufnr, + underline_ns, + higroup, + { diagnostic.lnum, math.min(diagnostic.col, #lines[1] - 1) }, + { diagnostic.end_lnum, diagnostic.end_col }, + { priority = get_priority(diagnostic.severity) } + ) + end + save_extmarks(underline_ns, bufnr) + end) end, hide = function(namespace, bufnr) local ns = M.get_namespace(namespace) @@ -1795,51 +1791,54 @@ M.handlers.virtual_text = { bufnr = vim._resolve_bufnr(bufnr) opts = opts or {} - if not api.nvim_buf_is_loaded(bufnr) then - return - end - - if opts.virtual_text then - if opts.virtual_text.format then - diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics) + once_buf_loaded(bufnr, function() + if opts.virtual_text then + if opts.virtual_text.format then + diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics) + end + if + opts.virtual_text.source + and (opts.virtual_text.source ~= 'if_many' or count_sources(bufnr) > 1) + then + diagnostics = prefix_source(diagnostics) + end end - if - opts.virtual_text.source - and (opts.virtual_text.source ~= 'if_many' or count_sources(bufnr) > 1) - then - diagnostics = prefix_source(diagnostics) + + local ns = M.get_namespace(namespace) + if not ns.user_data.virt_text_ns then + ns.user_data.virt_text_ns = + api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_text', ns.name)) + end + if not ns.user_data.virt_text_augroup then + ns.user_data.virt_text_augroup = api.nvim_create_augroup( + string.format('nvim.%s.diagnostic.virt_text', ns.name), + { clear = true } + ) end - end - local ns = M.get_namespace(namespace) - if not ns.user_data.virt_text_ns then - ns.user_data.virt_text_ns = - api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_text', ns.name)) - end - if not ns.user_data.virt_text_augroup then - ns.user_data.virt_text_augroup = api.nvim_create_augroup( - string.format('nvim.%s.diagnostic.virt_text', ns.name), - { clear = true } - ) - end + api.nvim_clear_autocmds({ group = ns.user_data.virt_text_augroup, buffer = bufnr }) - api.nvim_clear_autocmds({ group = ns.user_data.virt_text_augroup, buffer = bufnr }) + local line_diagnostics = diagnostic_lines(diagnostics, true) - local line_diagnostics = diagnostic_lines(diagnostics, true) + if opts.virtual_text.current_line ~= nil then + api.nvim_create_autocmd('CursorMoved', { + buffer = bufnr, + group = ns.user_data.virt_text_augroup, + callback = function() + render_virtual_text( + ns.user_data.virt_text_ns, + bufnr, + line_diagnostics, + opts.virtual_text + ) + end, + }) + end - if opts.virtual_text.current_line ~= nil then - api.nvim_create_autocmd('CursorMoved', { - buffer = bufnr, - group = ns.user_data.virt_text_augroup, - callback = function() - render_virtual_text(ns.user_data.virt_text_ns, bufnr, line_diagnostics, opts.virtual_text) - end, - }) - end + render_virtual_text(ns.user_data.virt_text_ns, bufnr, line_diagnostics, opts.virtual_text) - render_virtual_text(ns.user_data.virt_text_ns, bufnr, line_diagnostics, opts.virtual_text) - - save_extmarks(ns.user_data.virt_text_ns, bufnr) + save_extmarks(ns.user_data.virt_text_ns, bufnr) + end) end, hide = function(namespace, bufnr) local ns = M.get_namespace(namespace) @@ -2054,53 +2053,51 @@ M.handlers.virtual_lines = { bufnr = vim._resolve_bufnr(bufnr) opts = opts or {} - if not api.nvim_buf_is_loaded(bufnr) then - return - end + once_buf_loaded(bufnr, function() + local ns = M.get_namespace(namespace) + if not ns.user_data.virt_lines_ns then + ns.user_data.virt_lines_ns = + api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_lines', ns.name)) + end + if not ns.user_data.virt_lines_augroup then + ns.user_data.virt_lines_augroup = api.nvim_create_augroup( + string.format('nvim.%s.diagnostic.virt_lines', ns.name), + { clear = true } + ) + end - local ns = M.get_namespace(namespace) - if not ns.user_data.virt_lines_ns then - ns.user_data.virt_lines_ns = - api.nvim_create_namespace(string.format('nvim.%s.diagnostic.virtual_lines', ns.name)) - end - if not ns.user_data.virt_lines_augroup then - ns.user_data.virt_lines_augroup = api.nvim_create_augroup( - string.format('nvim.%s.diagnostic.virt_lines', ns.name), - { clear = true } - ) - end + api.nvim_clear_autocmds({ group = ns.user_data.virt_lines_augroup, buffer = bufnr }) - api.nvim_clear_autocmds({ group = ns.user_data.virt_lines_augroup, buffer = bufnr }) + diagnostics = + reformat_diagnostics(opts.virtual_lines.format or format_virtual_lines, diagnostics) - diagnostics = - reformat_diagnostics(opts.virtual_lines.format or format_virtual_lines, diagnostics) + if opts.virtual_lines.current_line == true then + -- Create a mapping from line -> diagnostics so that we can quickly get the + -- diagnostics we need when the cursor line doesn't change. + local line_diagnostics = diagnostic_lines(diagnostics, true) + api.nvim_create_autocmd('CursorMoved', { + buffer = bufnr, + group = ns.user_data.virt_lines_augroup, + callback = function() + render_virtual_lines( + ns.user_data.virt_lines_ns, + bufnr, + diagnostics_at_cursor(line_diagnostics) + ) + end, + }) + -- Also show diagnostics for the current line before the first CursorMoved event. + render_virtual_lines( + ns.user_data.virt_lines_ns, + bufnr, + diagnostics_at_cursor(line_diagnostics) + ) + else + render_virtual_lines(ns.user_data.virt_lines_ns, bufnr, diagnostics) + end - if opts.virtual_lines.current_line == true then - -- Create a mapping from line -> diagnostics so that we can quickly get the - -- diagnostics we need when the cursor line doesn't change. - local line_diagnostics = diagnostic_lines(diagnostics, true) - api.nvim_create_autocmd('CursorMoved', { - buffer = bufnr, - group = ns.user_data.virt_lines_augroup, - callback = function() - render_virtual_lines( - ns.user_data.virt_lines_ns, - bufnr, - diagnostics_at_cursor(line_diagnostics) - ) - end, - }) - -- Also show diagnostics for the current line before the first CursorMoved event. - render_virtual_lines( - ns.user_data.virt_lines_ns, - bufnr, - diagnostics_at_cursor(line_diagnostics) - ) - else - render_virtual_lines(ns.user_data.virt_lines_ns, bufnr, diagnostics) - end - - save_extmarks(ns.user_data.virt_lines_ns, bufnr) + save_extmarks(ns.user_data.virt_lines_ns, bufnr) + end) end, hide = function(namespace, bufnr) local ns = M.get_namespace(namespace)