Hello everyone!
One problem I’ve been having since I switched to the builtin lsp coc a few months ago is that I haven’t found a way to get the diagnostics only on my current line. Today I thought that since I started to learn Lua I could try to do it myself with a little bit of tweaking. I know it doesn’t bring enough features to be a plugin by itself, it’s more like a small functionality in a config but I thought it would be a good opportunity to make my first plugin anyway. I don’t plan to post a maintained version at all, it’s just for my configuration and my “curiosity”. Since I’ve never made a plugin I have absolutely no idea what the project structure should be, should I split it into several files etc… I would also be interested in opinions about the code itself! Please be kind, I begin (:
Just a quick look is more than enough, thank you very much for your time and have a nice day!
--[[
To configure the feature, simply call the `require "vtcurr".setup` function this way:
vim.diagnostic.config({
...
virtual_text = {
severity = require('vtcurr').setup {
min = vim.diagnostic.severity.ERROR
},
},
...
})
]]
local VT = {}
local ns = nvim.create_namespace("VT")
VT.sev = {}
VT.setup = function(config)
local sev = vim.diagnostic.severity
local max = config.max
local min = config.min
for k, v in pairs(sev) do
if type(v) == "string" or #k <= 1 then
goto continue
end
if (min and v > min) or (max and v < max) then
if not VT.sev.max or
v < sev[VT.sev.max] then
VT.sev.max = k
end
if not VT.sev.min or
v > sev[VT.sev.min] then
VT.sev.min = k
end
end
::continue::
end
-- I have absolutely no idea which events I should use
vim.api.nvim_create_autocmd(
{ "CursorMoved", "CursorHold",
"CursorHoldI", "InsertEnter",
"InsertLeave", "BufEnter" }, {
callback = function()
local ln = vim.fn.line('.') - 1
VT.clear()
if VT.cond(ln) then
VT.print(ln, VT.get(ln))
end
end
})
VT.lsp = config
return config
end
-- @description allows to display a virtual line which
-- content and line are given
--
-- @param ln -> int: line 0-indexed
-- @param content -> string: content of the virtuel text.
VT.print = function(ln, content)
local col = string.len(nvim.buf_get_lines(
0, ln, ln + 1, false
)[1])
nvim.buf_set_extmark(0, ns, ln, col, {
virt_text = VT.fmt(content)
})
end
-- @description retrieves all diagnostics attached to
-- the current buffer and on the line given as argument
--
-- @param ln -> int: line 0-indexed
VT.get = function(ln)
return vim.diagnostic.get(0, {
lnum = ln,
severity = VT.sev
})
end
-- @description Clear all virtual texts previously
-- displayed by the VT.print() function
-- @see VT.print()
VT.clear = function()
local buflst = vim.tbl_filter(function(nr)
return nvim.buf_is_loaded(nr)
end, nvim.list_bufs())
for _, bufnr in ipairs(buflst) do
nvim.buf_clear_namespace(bufnr, ns, 0, -1)
end
end
-- @description Format a diagnostic list into a
-- string that can be displayed as a virtual line.
--
-- @param diagnostic -> lst: list of all the
-- diagnostic to print
VT.fmt = function(diagnostics)
local colors = {
"Error",
"Warn",
"Info",
"Hint"
}
local content = {}
local max
for c, di in pairs(diagnostics) do
if max == nil or di.severity >= max then
max = di.severity
end
table.insert(content, {
string.rep(c == 1 and " " or "", 4) .. "■",
"Diagnostic" .. colors[di.severity]
})
end
table.insert(
content,
{ " " .. diagnostics[1].message, "Diagnostic" .. colors[max] }
)
return content
end
-- @description Conditions the display of a virtual line on the
-- given line of the current buffer. If no virtual line is already
-- displayed of a severity not supported by vtcurr and a line
-- of a supported severity is to be displayed then return true.
VT.cond = function(ln)
return #vim.diagnostic.get(0, {
lnum = ln,
severity = VT.lsp
}) == 0 and #VT.get(ln) > 0
end
return VT