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' , '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', 'gi' , '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()' }, { "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 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 -- Opt out of semantic highlighting client.server_capabilities.semanticTokensProvider = nil 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 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, })