Sanchayan Maity
4d970ce70c
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>
223 lines
7.4 KiB
Lua
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,
|
|
})
|