178 lines
4.7 KiB
Lua
178 lines
4.7 KiB
Lua
-- The MIT License (MIT)
|
|
--
|
|
-- Copyright © 2026 Scott E. Graves <scott.e.graves@protonmail.com>
|
|
--
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
-- and associated documentation files (the “Software”), to deal in the Software without restriction,
|
|
-- including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
-- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
|
-- furnished to do so, subject to the following conditions:
|
|
--
|
|
-- The above copyright notice and this permission notice shall be included in all copies or
|
|
-- substantial portions of the Software.
|
|
--
|
|
-- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
-- BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
-- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
--
|
|
local M = {}
|
|
|
|
local namespace = vim.api.nvim_create_namespace("DarculaLightbulb")
|
|
local requests = {}
|
|
local revisions = {}
|
|
|
|
local config = {
|
|
priority = 10,
|
|
sign = {
|
|
enabled = true,
|
|
text = "💡",
|
|
hl = "DiagnosticSignInfo"
|
|
},
|
|
virtual_text = {
|
|
enabled = false,
|
|
text = "💡",
|
|
hl = "DiagnosticVirtualTextInfo"
|
|
}
|
|
}
|
|
|
|
local function cancel_request(bufnr)
|
|
local cancel = requests[bufnr]
|
|
requests[bufnr] = nil
|
|
if cancel then
|
|
pcall(cancel)
|
|
end
|
|
end
|
|
|
|
local function clear_indicator(bufnr)
|
|
if vim.api.nvim_buf_is_valid(bufnr) then
|
|
vim.api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
|
|
end
|
|
end
|
|
|
|
local function render(bufnr, line)
|
|
clear_indicator(bufnr)
|
|
if not vim.api.nvim_buf_is_valid(bufnr) then
|
|
return
|
|
end
|
|
|
|
line = math.max(0, math.min(line, vim.api.nvim_buf_line_count(bufnr) - 1))
|
|
|
|
vim.api.nvim_buf_set_extmark(
|
|
bufnr,
|
|
namespace,
|
|
line,
|
|
0,
|
|
{
|
|
strict = false,
|
|
priority = config.priority,
|
|
sign_text = config.sign.enabled and config.sign.text or nil,
|
|
sign_hl_group = config.sign.enabled and config.sign.hl or nil,
|
|
virt_text = config.virtual_text.enabled and
|
|
{{config.virtual_text.text, config.virtual_text.hl}} or
|
|
nil,
|
|
virt_text_pos = config.virtual_text.enabled and "eol" or nil,
|
|
hl_mode = config.virtual_text.enabled and "combine" or nil
|
|
}
|
|
)
|
|
end
|
|
|
|
function M.clear(bufnr)
|
|
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
|
revisions[bufnr] = (revisions[bufnr] or 0) + 1
|
|
cancel_request(bufnr)
|
|
clear_indicator(bufnr)
|
|
end
|
|
|
|
function M.update()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local win = vim.api.nvim_get_current_win()
|
|
local cursor = vim.api.nvim_win_get_cursor(win)
|
|
local line = cursor[1] - 1
|
|
local revision = (revisions[bufnr] or 0) + 1
|
|
revisions[bufnr] = revision
|
|
|
|
cancel_request(bufnr)
|
|
|
|
local clients = vim.lsp.get_clients(
|
|
{bufnr = bufnr, method = "textDocument/codeAction"}
|
|
)
|
|
if #clients == 0 then
|
|
clear_indicator(bufnr)
|
|
return
|
|
end
|
|
|
|
local diagnostics = vim.lsp.diagnostic.from(
|
|
vim.diagnostic.get(bufnr, {lnum = line})
|
|
)
|
|
|
|
requests[bufnr] = vim.lsp.buf_request_all(
|
|
bufnr,
|
|
"textDocument/codeAction",
|
|
function(client)
|
|
local params = vim.lsp.util.make_range_params(win, client.offset_encoding)
|
|
params.context = {diagnostics = diagnostics}
|
|
return params
|
|
end,
|
|
function(responses)
|
|
if
|
|
revisions[bufnr] ~= revision or
|
|
not vim.api.nvim_buf_is_valid(bufnr)
|
|
then
|
|
return
|
|
end
|
|
requests[bufnr] = nil
|
|
|
|
local has_actions = false
|
|
for _, response in pairs(responses) do
|
|
if response.result ~= nil and not vim.tbl_isempty(response.result) then
|
|
has_actions = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if has_actions then
|
|
render(bufnr, line)
|
|
else
|
|
clear_indicator(bufnr)
|
|
end
|
|
end
|
|
)
|
|
end
|
|
|
|
function M.setup(opts)
|
|
config = vim.tbl_deep_extend("force", config, opts or {})
|
|
|
|
local group = vim.api.nvim_create_augroup("DarculaLightbulb", {clear = true})
|
|
vim.api.nvim_create_autocmd(
|
|
{"CursorHold", "CursorHoldI"},
|
|
{
|
|
callback = M.update,
|
|
group = group
|
|
}
|
|
)
|
|
vim.api.nvim_create_autocmd(
|
|
"WinLeave",
|
|
{
|
|
callback = function(args)
|
|
M.clear(args.buf)
|
|
end,
|
|
group = group
|
|
}
|
|
)
|
|
vim.api.nvim_create_autocmd(
|
|
"BufWipeout",
|
|
{
|
|
callback = function(args)
|
|
cancel_request(args.buf)
|
|
requests[args.buf] = nil
|
|
revisions[args.buf] = nil
|
|
end,
|
|
group = group
|
|
}
|
|
)
|
|
end
|
|
|
|
return M
|