Sanchayan Maity
95bbaa2b97
K is mapped to hover by default now. So let's drop our own mapping and just use K.
281 lines
9.3 KiB
Lua
281 lines
9.3 KiB
Lua
local protocol = require 'vim.lsp.protocol'
|
|
local lsp_util = vim.lsp.util
|
|
|
|
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 = {
|
|
{ "textDocument/definition" , 'n', 'pd' , '<cmd>lua PeekDefinition()<CR>' },
|
|
{ "textDocument/definition" , 'n', 'gd' , '<cmd>lua vim.lsp.buf.definition()<CR>' },
|
|
--{ "textDocument/declaration" , 'n', 'gD' , '<cmd>lua vim.lsp.buf.declaration()<CR>' },
|
|
{ "textDocument/typeDefinition" , 'n', '<C-k>' , '<cmd>lua vim.lsp.buf.type_definition()<CR>' },
|
|
{ "textDocument/references" , 'n', 'gr' , '<cmd>lua vim.lsp.buf.references()<CR>' },
|
|
{ "textDocument/implementation" , 'n', 'gD' , '<cmd>lua vim.lsp.buf.implementation()<CR>' },
|
|
{ "textDocument/documentSymbol" , 'n', '1gd' , '<cmd>lua vim.lsp.buf.document_symbol()<CR>' },
|
|
{ "workspace/symbol" , 'n', '1gD' , '<cmd>lua vim.lsp.buf.workspace_symbol()<CR>' },
|
|
{ "textDocument/signatureHelp" , 'n', '<Leader>S', '<cmd>lua vim.lsp.buf.signature_help()<CR>' },
|
|
{ "textDocument/rename" , 'n', 'gR' , '<cmd>lua vim.lsp.buf.rename()<CR>' },
|
|
{ "textDocument/inlayHint" , 'n', 'gi' , '<cmd>lua vim.lsp.inlay_hint(0, nil)<CR>' },
|
|
|
|
{ "textDocument/rangeFormatting", 'x', 'gq', '<cmd>lua vim.lsp.buf.format({async=true})<CR>' },
|
|
{ "textDocument/formatting" , 'n', 'gq', '<cmd>lua vim.lsp.buf.format({async=true})<CR>' },
|
|
|
|
{ "textDocument/codeAction", 'n', 'ga' , '<cmd>lua vim.lsp.buf.code_action()<CR>' },
|
|
{ "textDocument/codeAction", 'v', 'ga' , '<cmd>lua vim.lsp.buf.code_action()<CR>' },
|
|
{ "textDocument/codeAction", 'n', '<Leader>r', '<cmd>lua vim.lsp.buf.code_action{only = \'refactor\' }<CR>' },
|
|
{ "textDocument/codeAction", 'v', '<Leader>r', '<cmd>lua vim.lsp.buf.code_action{only = \'refactor\' }<CR>' },
|
|
|
|
{ "textDocument/codeLens", 'n', '<LocalLeader>l', '<cmd>lua vim.lsp.codelens.run()<CR>' },
|
|
{ "textDocument/codeLens", 'n', '<LocalLeader>L', '<cmd>lua vim.lsp.codelens.clear()<CR>' },
|
|
}
|
|
|
|
local CODE_ACTION_AVAILABLE = "CodeActionAvailable"
|
|
local CODE_ACTION_GROUP = "code-action-group"
|
|
|
|
if vim.tbl_isempty(vim.fn.sign_getdefined(CODE_ACTION_AVAILABLE)) then
|
|
vim.fn.sign_define(CODE_ACTION_AVAILABLE, { text = "💡", texthl = "DiagnosticSignInfo" })
|
|
end
|
|
|
|
local code_action_update_sign = function(old_line, new_line, bufnr)
|
|
bufnr = bufnr or "%"
|
|
|
|
if old_line then
|
|
vim.fn.sign_unplace(
|
|
CODE_ACTION_GROUP, { id = old_line, buffer = bufnr }
|
|
)
|
|
vim.b.code_action_line = nil
|
|
end
|
|
|
|
if new_line and (vim.b.code_action_line ~= new_line) then
|
|
vim.fn.sign_place(
|
|
new_line, CODE_ACTION_GROUP, CODE_ACTION_AVAILABLE, bufnr,
|
|
{ lnum = new_line, priority = 10 }
|
|
)
|
|
vim.b.code_action_line = new_line
|
|
end
|
|
end
|
|
|
|
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.supports_method(capability) then
|
|
vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts)
|
|
end
|
|
end
|
|
|
|
if client.supports_method('textDocument/codeAction') then
|
|
vim.api.nvim_create_autocmd({"CursorHold", "CursorHoldI"}, {
|
|
group = lsp_augroup_id,
|
|
buffer = bufnr,
|
|
callback = function()
|
|
-- Taken from https://github.com/neovim/nvim-lspconfig/wiki/Code-Actions
|
|
local context = { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() }
|
|
local params = lsp_util.make_range_params()
|
|
params.context = context
|
|
vim.lsp.buf_request(0, 'textDocument/codeAction', params, function(err, result, ctx, config)
|
|
if result and not vim.tbl_isempty(result) then
|
|
local line = params.range.start.line
|
|
code_action_update_sign(vim.b.code_action_line, line + 1, bufnr)
|
|
else
|
|
code_action_update_sign(vim.b.code_action_line, nil, bufnr)
|
|
end
|
|
end)
|
|
end
|
|
})
|
|
end
|
|
|
|
if client.supports_method('textDocument/codeLens') then
|
|
vim.api.nvim_create_autocmd({"CursorHold", "CursorHoldI", "InsertLeave"}, {
|
|
group = lsp_augroup_id,
|
|
buffer = bufnr,
|
|
callback = vim.lsp.codelens.refresh,
|
|
})
|
|
end
|
|
|
|
if client.supports_method('textDocument/documentHighlight') 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.supports_method('textDocument/inlayHint') 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.supports_method(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.supports_method(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"
|
|
})
|