local M = {} -- Show/navigate warning and errors by default. M.severity = vim.diagnostic.severity.WARN -- Go to next/prev diagnostic, but only if next item has a visible virtual text. -- If we can move, then also center screen at target location. local conditional_jump = function(count) vim.validate("count", count, "number") local get_diagnostic = count > 0 and vim.diagnostic.get_next or vim.diagnostic.get_prev local diagnostic = get_diagnostic { wrap = false, -- don't wrap around the begin/end of file severity = { -- only navigate items with visible virtual text min = M.severity, }, } if diagnostic then vim.diagnostic.jump { diagnostic = diagnostic, float = true } vim.cmd("normal zz") else local level = vim.diagnostic.severity[M.severity] or "???" local msg = string.format("No more diagnostics [level: %s]", level) vim.notify(msg, vim.log.levels.WARN) end end ---Move to the next diagnostic. M.goto_next = function() conditional_jump(1) end ---Move to the previous diagnostic. M.goto_prev = function() conditional_jump(-1) end ---Show diagnostics in a floating window. ---@param opts table|nil: options passed along to `vim.diagnostic.open_float`. M.open_float = function(opts) vim.diagnostic.open_float(opts) end ---Toggle diagnostics in the given buffer. ---@param bufnr integer|nil: Buffer number (0 for current buffer, nil for all buffers. M.toggle = function(bufnr) local filter = { bufnr = bufnr or 0 } if vim.diagnostic.is_enabled(filter) then vim.diagnostic.enable(false, filter) else vim.diagnostic.enable(true, filter) end end ---Hide currently displayed diagnostics. ---@param bufnr integer|nil: Buffer number (0 for current buffer, nil for all buffers. M.hide = function(bufnr) vim.diagnostic.hide(nil, bufnr or 0) end local icons = require("fschauen.util.icons") ---Select minimum diagnostic severity for which to show virtual text. M.select_virtual_text_severity = function() if not pcall(require, "telescope") then vim.notify("Telescope not available!", vim.log.levels.ERROR) return end local display_row = require("telescope.pickers.entry_display").create { separator = "", items = { { width = 3 }, { remaining = true } }, } local make_display = function(entry) return display_row { { entry.value.icon, entry.value.highlight }, { entry.value.title, entry.value.highlight }, } end local opts = require("telescope.themes").get_dropdown() require("telescope.pickers") .new(opts, { prompt_title = "Min. severity for virtual text:", finder = require("telescope.finders").new_table { results = { { title = "Error", severity = vim.diagnostic.severity.ERROR, icon = icons.diagnostics_bold.Error, highlight = "DiagnosticError", }, { title = "Warning", severity = vim.diagnostic.severity.WARN, icon = icons.diagnostics_bold.Warn, highlight = "DiagnosticWarn", }, { title = "Info", severity = vim.diagnostic.severity.INFO, icon = icons.diagnostics_bold.Info, highlight = "DiagnosticInfo", }, { title = "Hint", severity = vim.diagnostic.severity.HINT, icon = icons.diagnostics_bold.Hint, highlight = "DiagnosticHint", }, }, entry_maker = function(entry) return { value = entry, ordinal = entry.title, display = make_display } end, }, sorter = require("telescope.config").values.generic_sorter(opts), attach_mappings = function(prompt_bufnr, _) local actions = require("telescope.actions") actions.select_default:replace(function() actions.close(prompt_bufnr) local selection = require("telescope.actions.state").get_selected_entry() M.severity = selection.value.severity or M.severity vim.diagnostic.config { virtual_text = { severity = { min = M.severity }, }, } end) return true end, }) :find() end ---Customize nvim's diagnostics display. M.setup = function() vim.diagnostic.config { underline = false, virtual_text = { spacing = 6, prefix = icons.ui.Circle, severity = { min = M.severity, }, }, float = { border = "rounded", }, severity_sort = true, } for type, icon in pairs(icons.diagnostics) do local hl = "DiagnosticSign" .. type vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl }) end end return M