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' , 'lua PeekDefinition()' }, { "definitionProvider" , 'n', 'gd' , 'lua vim.lsp.buf.definition()' }, --{ "declarationProvider" , 'n', 'gD' , 'lua vim.lsp.buf.declaration()' }, { "typeDefinitionProvider" , 'n', '' , 'lua vim.lsp.buf.type_definition()' }, { "referencesProvider" , 'n', 'gr' , 'lua vim.lsp.buf.references()' }, { "implementationProvider" , 'n', 'gD' , 'lua vim.lsp.buf.implementation()' }, { "documentSymbolProvider" , 'n', '1gd' , 'lua vim.lsp.buf.document_symbol()' }, { "workspaceSymbolProvider", 'n', '1gD' , 'lua vim.lsp.buf.workspace_symbol()' }, { "hoverProvider" , 'n', 'k', 'lua vim.lsp.buf.hover()' }, { "signatureHelpProvider" , 'n', 'S', 'lua vim.lsp.buf.signature_help()' }, { "renameProvider" , 'n', 'gR' , 'lua vim.lsp.buf.rename()' }, { "inlayHintProvider" , 'n', 'gi' , 'lua vim.lsp.buf.inlay_hint(0, nil)' }, { "documentRangeFormattingProvider", 'x', 'gq', 'lua vim.lsp.buf.format({async=true})' }, { "documentFormattingProvider" , 'n', 'gq', 'lua vim.lsp.buf.format({async=true})' }, { "codeActionProvider", 'n', 'ga' , 'lua vim.lsp.buf.code_action()' }, { "codeActionProvider", 'v', 'ga' , 'lua vim.lsp.buf.code_action()' }, { "codeActionProvider", 'n', 'r', 'lua vim.lsp.buf.code_action{only = \'refactor\' }' }, { "codeActionProvider", 'v', 'r', 'lua vim.lsp.buf.code_action{only = \'refactor\' }' }, { "codeLensProvider", 'n', 'l', 'lua vim.lsp.codelens.run()' }, { "codeLensProvider", 'n', 'L', 'lua vim.lsp.codelens.clear()' }, } 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.buf.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, })