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

243 lines
8.1 KiB
Lua

local nvim_lsp = require 'lspconfig'
local protocol = require 'vim.lsp.protocol'
local util = require 'lspconfig/util'
local lightbulb = require 'nvim-lightbulb'
-- https://github.com/neovim/nvim-lspconfig/wiki/User-contributed-tips
function FormatRangeOperator()
local old_func = vim.go.operatorfunc
_G.op_func_formatting = function()
local start = vim.api.nvim_buf_get_mark(0, '[')
local finish = vim.api.nvim_buf_get_mark(0, ']')
vim.lsp.buf.range_formatting({}, start, finish)
vim.go.operatorfunc = old_func
_G.op_func_formatting = nil
end
vim.go.operatorfunc = 'v:lua.op_func_formatting'
vim.api.nvim_feedkeys('g@', 'n', false)
end
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_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 FormatRangeOperator()<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.range_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.range_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 on_attach = function(client, bufnr)
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
vim.lsp.set_log_level('warn')
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)
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
local lsp_augroup_id = vim.api.nvim_create_augroup("LSP", {clear = true})
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 = function ()
vim.lsp.codelens.refresh()
end,
})
vim.api.nvim_create_autocmd({"CursorHold", "CursorHoldI"}, {
group = lsp_augroup_id,
buffer = bufnr,
callback = function ()
lightbulb.update_lightbulb()
end,
})
end
if client.server_capabilities.documentHighlightProvider then
vim.api.nvim_create_autocmd("CursorHold", {
group = lsp_augroup_id,
buffer = bufnr,
callback = function ()
vim.lsp.buf.document_highlight()
end,
})
vim.api.nvim_create_autocmd("CursorMoved", {
group = lsp_augroup_id,
buffer = bufnr,
callback = function ()
vim.lsp.buf.clear_references()
end,
})
end
end
end
local on_init = function(client)
if client.config.settings then
client.notify('workspace/didChangeConfiguration', { settings = client.config.settings })
end
end
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.workspace.configuration = true
capabilities.textDocument.completion.completionItem.snippetSupport = true
capabilities.textDocument.completion.completionItem.resolveSupport = {
properties = { 'documentation', 'detail', 'additionalTextEdits', }
}
local rust_tool_opts = {
tools = {
autoSetHints = true,
hover_with_actions = false,
runnables = { use_telescope = false },
debuggables = { use_telescope = false },
inlay_hints = {
only_current_line = false,
only_current_line_autocmd = "CursorHold",
show_parameter_hints = true,
parameter_hints_prefix = "<- ",
other_hints_prefix = "=> ",
highlight = "Hint",
},
hover_actions = {
auto_focus = true
},
},
server = {
on_init = on_init,
on_attach = on_attach,
capabilities = capabilities,
settings = {
["rust-analyzer"] = {
checkOnSave = {
command = "clippy"
},
}
}
},
}
require('rust-tools').setup(rust_tool_opts)
local servers = {
clangd = {
default_config = {
cmd = { "clangd", "--background-index", "--pch-storage=memory", "--clang-tidy", "--suggest-missing-includes", "--header-insertion=never" },
filetypes = { 'c', 'cpp' },
root_dir = function(fname)
-- We specify build/compile_commands.json as that is where the compile_commands.json
-- gets generated automatically for meson projects.
local root_pattern = util.root_pattern('build/compile_commands.json', 'compile_commands.json', 'compile_flags.txt', '.git')
local filename = util.path.is_absolute(fname) and fname or util.path.join(vim.loop.cwd(), fname)
return root_pattern(filename) or util.path.dirname(filename)
end,
}
},
eslint = {},
hls = {},
jedi_language_server = {
init_options = {
completion = {
resolveEagerly = true,
},
jediSettings = {
caseInsensitiveCompletion = false,
},
workspace = {
symbols = {
maxSymbols = 50
},
},
},
},
tsserver = {},
}
for client, config in pairs(servers) do
config.on_init = on_init
config.on_attach = on_attach
config.capabilities = vim.tbl_deep_extend(
'keep',
config.capabilities or {},
capabilities
)
nvim_lsp[client].setup(config)
end