dotfiles/nvim/.config/nvim/lua/lsp.lua
Sanchayan Maity 4d970ce70c nvim: lsp: Fix error in LspDetach
Some language servers like HLS take longer to attach and if we exit
soon before LSP attach had a chance to finish (may be?), server
capabilities field does not seem to be valid in client object and
we get the below error. Check if it valid first.

Error detected while processing LspDetach Autocommands for "*":
Error executing lua callback: /home/core/.config/nvim/lua/lsp.lua:215: attempt to index field 'server_capabilities' (a nil value)
stack traceback:
        /home/core/.config/nvim/lua/lsp.lua:215: in function </home/core/.config/nvim/lua/lsp.lua:209>
        [C]: in function 'nvim_exec_autocmds'
        /usr/local/share/nvim/runtime/lua/vim/lsp.lua:1140: in function </usr/local/share/nvim/runtime/lua/vim/lsp.lua:1139>
Error executing lua callback: /home/core/.config/nvim/lua/lsp.lua:215: attempt to index field 'server_capabilities' (a nil value)
stack traceback:
        /home/core/.config/nvim/lua/lsp.lua:215: in function </home/core/.config/nvim/lua/lsp.lua:209>
        [C]: in function 'nvim_exec_autocmds'
        /usr/local/share/nvim/runtime/lua/vim/lsp.lua:1140: in function </usr/local/share/nvim/runtime/lua/vim/lsp.lua:1139>
2022-11-29 20:26:28 +05:30

223 lines
7.4 KiB
Lua

local protocol = require 'vim.lsp.protocol'
local lightbulb = require 'nvim-lightbulb'
local inlay_hint = require 'lsp-inlayhints'
-- Set up inlay hints
inlay_hint.setup({
inlay_hints = {
highlight = "Hint"
}
})
vim.lsp.set_log_level("off")
local function preview_location_callback(_, result)
if result == nil or vim.tbl_isempty(result) then
return nil
end
vim.lsp.util.preview_location(result[1])
end
function PeekDefinition()
local params = vim.lsp.util.make_position_params()
return vim.lsp.buf_request(0, 'textDocument/definition', params, preview_location_callback)
end
protocol.CompletionItemKind = {
' Text' ;
' Method' ;
' Function' ;
'全Constructor' ;
' Field' ;
' Variable' ;
' Class' ;
' Interface' ;
' Module' ;
' Property' ;
' Unit' ;
' Value' ;
' Enum' ;
' Keyword' ;
' Snippet' ;
' Color' ;
' File' ;
' Reference' ;
' Folder' ;
' EnumMember' ;
' Constant' ;
' Struct' ;
' Event' ;
' Operator' ;
' TypeParameter';
}
local lsp_augroup_id = vim.api.nvim_create_augroup("LSP", { clear = true })
local lsp_key_mappings = {
{ "definitionProvider" , 'n', 'pd' , '<cmd>lua PeekDefinition()<CR>' },
{ "definitionProvider" , 'n', 'gd' , '<cmd>lua vim.lsp.buf.definition()<CR>' },
{ "declarationProvider" , 'n', 'gD' , '<cmd>lua vim.lsp.buf.declaration()<CR>' },
{ "typeDefinitionProvider" , 'n', '<C-k>' , '<cmd>lua vim.lsp.buf.type_definition()<CR>' },
{ "referencesProvider" , 'n', 'gr' , '<cmd>lua vim.lsp.buf.references()<CR>' },
{ "implementationProvider" , 'n', 'gi' , '<cmd>lua vim.lsp.buf.implementation()<CR>' },
{ "documentSymbolProvider" , 'n', '1gd' , '<cmd>lua vim.lsp.buf.document_symbol()<CR>' },
{ "workspaceSymbolProvider", 'n', '1gD' , '<cmd>lua vim.lsp.buf.workspace_symbol()<CR>' },
{ "hoverProvider" , 'n', '<Leader>k', '<cmd>lua vim.lsp.buf.hover()<CR>' },
{ "signatureHelpProvider" , 'n', '<Leader>S', '<cmd>lua vim.lsp.buf.signature_help()<CR>' },
{ "renameProvider" , 'n', 'gR' , '<cmd>lua vim.lsp.buf.rename()<CR>' },
{ "documentRangeFormattingProvider", 'x', 'gq', '<cmd>lua vim.lsp.buf.format({async=true})<CR>' },
{ "documentFormattingProvider" , 'n', 'gq', '<cmd>lua vim.lsp.buf.format({async=true})<CR>' },
{ "codeActionProvider", 'n', 'ga' , '<cmd>lua vim.lsp.buf.code_action()<CR>' },
{ "codeActionProvider", 'v', 'ga' , '<cmd>lua vim.lsp.buf.code_action()<CR>' },
{ "codeActionProvider", 'n', '<Leader>r', '<cmd>lua vim.lsp.buf.code_action{only = \'refactor\' }<CR>' },
{ "codeActionProvider", 'v', '<Leader>r', '<cmd>lua vim.lsp.buf.code_action{only = \'refactor\' }<CR>' },
}
local tsserver_setup = function(client)
if client.name == 'tsserver' then
-- Disable tsserver formatting, we want formatting via prettier
client.server_capabilities.documentFormattingProvider = false
client.server_capabilities.documentRangeFormattingProvider = false
end
end
local get_active_client_by_name = function(bufnr, servername)
for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do
if client.name == servername then
return client
end
end
end
local switch_source_header = function()
local clangd_client = get_active_client_by_name(0, 'clangd')
local params = { uri = vim.uri_from_bufnr(0) }
if clangd_client then
clangd_client.request('textDocument/switchSourceHeader', params, function(err, result)
if err then
vim.schedule(function()
vim.notify('Clangd: switchSourceHeader gave error: ' .. tostring(err), vim.log.levels.ERROR)
end)
end
if not result then
vim.schedule(function()
vim.notify('Clangd: switchSourceHeader, corresponding file not determined', vim.log.levels.ERROR)
end)
return
end
vim.cmd.edit(vim.uri_to_fname(result))
end, 0)
else
vim.schedule(function()
vim.notify('Clangd: switchSourceHeader is not supported', vim.log.levels.ERROR)
end)
end
end
local clangd_setup = function(client)
if client.name == 'clangd' then
vim.api.nvim_create_user_command("ClangdSwitchSourceHeader", switch_source_header, {desc = 'Switch between source/header'})
end
end
local clangd_cleanup = function(client)
if client.name == 'clangd' then
vim.api.nvim_del_user_command("ClangdSwitchSourceHeader")
end
end
local on_attach = function(client, bufnr)
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
if client.config.flags then
client.config.flags.allow_incremental_sync = true
client.config.flags.debounce_text_changes = 100
end
local opts = { noremap=true, silent=true }
-- This needs to be here, so we disable formatting with tsserver before
-- actually checking it below.
tsserver_setup(client)
clangd_setup(client)
for _, mappings in pairs(lsp_key_mappings) do
local capability, mode, lhs, rhs = unpack(mappings)
if client.server_capabilities[capability] then
vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts)
end
end
if client.server_capabilities.codeLensProvider or client.server_capabilities.documentHighlightProvider then
if client.server_capabilities.codeLensProvider then
vim.api.nvim_buf_set_keymap(bufnr, "n", "<Leader>l", "<cmd>lua vim.lsp.codelens.run()<CR>", opts)
vim.api.nvim_create_autocmd({"CursorHold", "CursorHoldI", "InsertLeave"}, {
group = lsp_augroup_id,
buffer = bufnr,
callback = vim.lsp.codelens.refresh,
})
vim.api.nvim_create_autocmd({"CursorHold", "CursorHoldI"}, {
group = lsp_augroup_id,
buffer = bufnr,
callback = lightbulb.update_lightbulb,
})
end
if client.server_capabilities.documentHighlightProvider then
vim.api.nvim_create_autocmd("CursorHold", {
group = lsp_augroup_id,
buffer = bufnr,
callback = vim.lsp.buf.document_highlight,
})
vim.api.nvim_create_autocmd("CursorMoved", {
group = lsp_augroup_id,
buffer = bufnr,
callback = vim.lsp.buf.clear_references,
})
end
end
inlay_hint.on_attach(client, bufnr)
end
vim.api.nvim_create_autocmd("LspAttach", {
group = lsp_augroup_id,
callback = function(args)
local bufnr = args.buf
local client = vim.lsp.get_client_by_id(args.data.client_id)
local opts = { noremap=true, silent=true }
for _, mappings in pairs(lsp_key_mappings) do
local capability, mode, lhs, rhs = unpack(mappings)
if client.server_capabilities[capability] then
vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts)
end
end
on_attach(client, bufnr)
end,
})
vim.api.nvim_create_autocmd("LspDetach", {
group = lsp_augroup_id,
callback = function(args)
local bufnr = args.buf
local client = vim.lsp.get_client_by_id(args.data.client_id)
for _, mappings in pairs(lsp_key_mappings) do
local capability, mode, lhs, _ = unpack(mappings)
if client.server_capabilities and client.server_capabilities[capability] then
vim.api.nvim_buf_del_keymap(bufnr, mode, lhs)
end
end
clangd_cleanup(client)
end,
})