dotfiles/nvim/.config/nvim/lua/lsp.lua

241 lines
7.9 KiB
Lua

local protocol = require 'vim.lsp.protocol'
local lightbulb = require 'nvim-lightbulb'
vim.lsp.set_log_level("off")
local preview_location_callback = function(_, result)
if result == nil or vim.tbl_isempty(result) then
return nil
end
vim.lsp.util.preview_location(result[1])
end
local peek_definition = function()
local params = vim.lsp.util.make_position_params()
return vim.lsp.buf_request(0, 'textDocument/definition', params, preview_location_callback)
end
_G.PeekDefinition = peek_definition
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', 'gD' , '<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>' },
{ "inlayHintProvider" , 'n', 'gi' , '<cmd>lua vim.lsp.inlay_hint(0, nil)<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>' },
{ "codeLensProvider", 'n', '<LocalLeader>l', '<cmd>lua vim.lsp.codelens.run()<CR>' },
{ "codeLensProvider", 'n', '<LocalLeader>L', '<cmd>lua vim.lsp.codelens.clear()<CR>' },
}
local cargo_reload_workspace = function()
vim.lsp.buf_request(0, 'rust-analyzer/reloadWorkspace', nil, function(err)
if err then
vim.schedule(function()
vim.notify('Cargo reload workspace gave error: ' .. tostring(err), vim.log.levels.ERROR)
end)
else
vim.schedule(function()
vim.notify 'Cargo workspace reloaded'
end)
end
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 client_custom_setup = function(client)
if client.name == 'clangd' then
vim.api.nvim_create_user_command("ClangdSwitchSourceHeader", switch_source_header, {desc = 'Switch between source/header'})
end
if client.name == 'rust-analyzer' then
vim.api.nvim_create_user_command("CargoReload", cargo_reload_workspace, {desc = 'Reload current cargo workspace'})
end
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 client_custom_cleanup = function(client)
if client.name == 'clangd' then
vim.api.nvim_del_user_command("ClangdSwitchSourceHeader")
end
if client.name == 'rust-analyzer' then
vim.api.nvim_del_user_command("CargoReload")
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 }
client_custom_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 then
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
if client.server_capabilities.inlayHintProvider then
vim.lsp.inlay_hint(bufnr, false)
end
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
client_custom_cleanup(client)
end,
})
vim.api.nvim_create_autocmd("LspProgress", {
group = lsp_augroup_id,
command = "redrawstatus"
})