navigator.lua/lua/navigator/codeAction.lua

225 lines
6.6 KiB
Lua
Raw Normal View History

2022-01-18 06:14:47 +00:00
local util = require('navigator.util')
2021-04-19 02:56:32 +00:00
local log = util.log
local trace = util.trace
2021-04-19 02:56:32 +00:00
local code_action = {}
2022-06-01 15:41:26 +00:00
-- local gui = require('navigator.gui')
2022-01-18 06:14:47 +00:00
local config = require('navigator').config_values()
2021-04-19 02:56:32 +00:00
local api = vim.api
2022-01-18 06:14:47 +00:00
local sign_name = 'NavigatorLightBulb'
2021-09-30 11:10:35 +00:00
--- `codeAction/resolve`
-- from neovim buf.lua, change vim.ui.select to gui
local diagnostic = vim.diagnostic or vim.lsp.diagnostic
2021-04-19 02:56:32 +00:00
-- https://github.com/glepnir/lspsaga.nvim/blob/main/lua/lspsaga/codeaction.lua
-- lspsaga has a clever design to inject code action indicator
2022-01-18 06:14:47 +00:00
local sign_group = 'nvcodeaction'
2021-04-19 02:56:32 +00:00
local get_namespace = function()
return api.nvim_create_namespace(sign_group)
end
local get_current_winid = function()
return api.nvim_get_current_win()
end
local function _update_virtual_text(line, actions)
2021-04-19 02:56:32 +00:00
local namespace = get_namespace()
2021-04-23 04:21:22 +00:00
pcall(api.nvim_buf_clear_namespace, 0, namespace, 0, -1)
2021-04-19 02:56:32 +00:00
if line then
2021-09-24 01:54:03 +00:00
trace(line, actions)
2022-01-18 06:14:47 +00:00
local icon_with_indent = ' ' .. config.icons.code_action_icon
2021-04-19 02:56:32 +00:00
local title = actions[1].title
pcall(api.nvim_buf_set_extmark, 0, namespace, line, -1, {
2022-01-18 06:14:47 +00:00
virt_text = { { icon_with_indent .. title, 'LspDiagnosticsSignHint' } },
virt_text_pos = 'overlay',
hl_mode = 'combine',
})
2021-04-19 02:56:32 +00:00
end
end
local function _update_sign(line)
if vim.tbl_isempty(vim.fn.sign_getdefined(sign_name)) then
2021-11-03 04:00:30 +00:00
vim.fn.sign_define(sign_name, {
text = config.icons.code_action_icon,
2022-01-18 06:14:47 +00:00
texthl = 'LspDiagnosticsSignHint',
2021-11-03 04:00:30 +00:00
})
end
2021-04-19 02:56:32 +00:00
local winid = get_current_winid()
2021-04-25 11:49:47 +00:00
if code_action[winid] == nil then
code_action[winid] = {}
end
2022-06-02 09:24:55 +00:00
-- only show code action on the current line, remove all others
if code_action[winid].lightbulb_line and code_action[winid].lightbulb_line > 0 then
2022-01-18 06:14:47 +00:00
vim.fn.sign_unplace(sign_group, { id = code_action[winid].lightbulb_line, buffer = '%' })
2022-06-02 09:24:55 +00:00
log('sign removed', line)
2021-04-19 02:56:32 +00:00
end
if line then
-- log("updatasign", line, sign_group, sign_name)
2022-06-02 09:24:55 +00:00
local id = vim.fn.sign_place(
2022-01-18 06:14:47 +00:00
line,
sign_group,
sign_name,
'%',
{ lnum = line + 1, priority = config.lsp.code_action.sign_priority }
)
2022-06-02 09:24:55 +00:00
code_action[winid].lightbulb_line = id
log('sign updated', id)
2021-04-19 02:56:32 +00:00
end
end
-- local need_check_diagnostic = {["go"] = true, ["python"] = true}
2022-01-18 06:14:47 +00:00
local need_check_diagnostic = { ['python'] = true }
2021-04-19 02:56:32 +00:00
function code_action:render_action_virtual_text(line, diagnostics)
return function(err, actions, context)
2022-06-02 09:24:55 +00:00
trace(actions, context)
if context and context.client_id then
local cname = vim.lsp.get_active_clients({ id = context.client_id })[1].name
if cname == 'null-ls' and _NgConfigValues.lsp.disable_nulls_codeaction_sign then
return
end
end
-- if nul-ls enabled, some of the lsp may not send valid code action,
2022-01-18 06:14:47 +00:00
if actions == nil or type(actions) ~= 'table' or vim.tbl_isempty(actions) then
-- no actions cleanup
if config.lsp.code_action.virtual_text then
2021-04-19 02:56:32 +00:00
_update_virtual_text(nil)
end
if config.lsp.code_action.sign then
2021-04-19 02:56:32 +00:00
_update_sign(nil)
end
else
2021-09-24 01:54:03 +00:00
trace(err, line, diagnostics, actions, context)
2022-06-02 09:24:55 +00:00
if config.lsp.code_action.sign then
2021-04-19 02:56:32 +00:00
if need_check_diagnostic[vim.bo.filetype] then
if next(diagnostics) == nil then
2022-06-02 09:24:55 +00:00
-- no diagnostic, no code action sign..
2021-04-19 02:56:32 +00:00
_update_sign(nil)
else
_update_sign(line)
end
else
_update_sign(line)
end
end
if config.lsp.code_action.virtual_text then
2021-04-19 02:56:32 +00:00
if need_check_diagnostic[vim.bo.filetype] then
if next(diagnostics) == nil then
_update_virtual_text(nil)
else
_update_virtual_text(line, actions)
2021-04-19 02:56:32 +00:00
end
else
_update_virtual_text(line, actions)
2021-04-19 02:56:32 +00:00
end
end
end
end
end
local special_buffers = {
2022-01-18 06:14:47 +00:00
['lspsagafinder'] = true,
['NvimTree'] = true,
['vista'] = true,
['guihua'] = true,
['lspinfo'] = true,
['markdown'] = true,
['text'] = true,
2021-04-19 02:56:32 +00:00
}
-- local action_call_back = function (_,_)
-- return Action:action_callback()
-- end
local action_virtual_call_back = function(line, diagnostics)
2021-04-23 04:21:22 +00:00
return code_action:render_action_virtual_text(line, diagnostics)
2021-04-19 02:56:32 +00:00
end
local code_action_req = function(_call_back_fn, diagnostics)
2022-01-18 06:14:47 +00:00
local context = { diagnostics = diagnostics }
2021-04-19 02:56:32 +00:00
local params = vim.lsp.util.make_range_params()
params.context = context
local line = params.range.start.line
local callback = _call_back_fn(line, diagnostics)
2022-01-18 06:14:47 +00:00
vim.lsp.buf_request(0, 'textDocument/codeAction', params, callback)
2021-04-19 02:56:32 +00:00
end
2022-02-24 08:03:28 +00:00
local function sort_select(action_tuples, opts, on_user_choice)
if action_tuples ~= nil and action_tuples[1][2] ~= nil and action_tuples[1][2].command then
table.sort(action_tuples, function(a, b)
return a[1] > b[1]
end)
end
trace(action_tuples)
2022-02-24 08:03:28 +00:00
require('guihua.gui').select(action_tuples, opts, on_user_choice)
end
2021-09-30 11:10:35 +00:00
code_action.code_action = function()
local original_select = vim.ui.select
2022-02-24 08:03:28 +00:00
vim.ui.select = sort_select
vim.lsp.buf.code_action()
2022-01-18 06:14:47 +00:00
vim.defer_fn(function()
vim.ui.select = original_select
end, 1000)
2021-09-30 11:10:35 +00:00
end
code_action.range_code_action = function(startpos, endpos)
local context = {}
context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
local bufnr = vim.api.nvim_get_current_buf()
startpos = startpos or api.nvim_buf_get_mark(bufnr, '<')
endpos = endpos or api.nvim_buf_get_mark(bufnr, '>')
log(startpos, endpos)
local params = vim.lsp.util.make_given_range_params(startpos, endpos)
2021-09-30 11:10:35 +00:00
params.context = context
local original_select = vim.ui.select
2022-01-18 06:14:47 +00:00
vim.ui.select = require('guihua.gui').select
local original_input = vim.ui.input
vim.ui.input = require('guihua.input').input
if vim.fn.has('nvim-0.8') then
vim.lsp.buf.code_action({context=context ,range={start = startpos, ['end'] = endpos}})
else
vim.lsp.buf.range_code_action(context, startpos, endpos)
end
vim.defer_fn(function()
vim.ui.select = original_select
vim.ui.input = original_input
end, 1000)
2021-09-30 11:10:35 +00:00
end
2021-04-19 02:56:32 +00:00
2022-07-31 05:49:00 +00:00
code_action.code_action_prompt = function(bufnr)
2021-04-19 02:56:32 +00:00
if special_buffers[vim.bo.filetype] then
2021-09-30 11:10:35 +00:00
log('skip buffer', vim.bo.filetype)
2021-04-19 02:56:32 +00:00
return
end
local diagnostics
if diagnostic.get_line_diagnostics then
-- old version
diagnostics = diagnostic.get_line_diagnostics()
else
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1
2022-01-18 06:14:47 +00:00
diagnostics = diagnostic.get(vim.api.nvim_get_current_buf(), { lnum = lnum })
end
2021-04-19 02:56:32 +00:00
local winid = get_current_winid()
code_action[winid] = code_action[winid] or {}
code_action[winid].lightbulb_line = code_action[winid].lightbulb_line or 0
code_action_req(action_virtual_call_back, diagnostics)
2021-04-19 02:56:32 +00:00
end
return code_action