local nvim_lsp = require('lspconfig') local protocol = require('vim.lsp.protocol') local signature = require('lsp_signature') local ts_utils = require("nvim-lsp-ts-utils") local null_ls = require("null-ls") local util = require("lspconfig/util") -- https://github.com/neovim/nvim-lspconfig/wiki/User-contributed-tips function format_range_operator() 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 local on_attach = function(client, bufnr) signature.on_attach({ bind = true, hint_enable = true, hint_prefix = "đŸŧ ", hint_scheme = "String", handler_opts = { border = "single" }, decorator = {"`", "`"} }) 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 = 500 end local opts = { noremap=true, silent=true } vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gd' , 'lua vim.lsp.buf.definition()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gD' , 'lua vim.lsp.buf.declaration()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'k', 'lua vim.lsp.buf.hover()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gr' , 'lua vim.lsp.buf.references()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ga' , 'lua vim.lsp.buf.code_action()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gi' , 'lua vim.lsp.buf.implementation()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', '' , 'lua vim.lsp.buf.type_definition()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', '1gd' , 'lua vim.lsp.buf.document_symbol()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', '1gD' , 'lua vim.lsp.buf.workspace_symbol()', opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gR' , 'lua vim.lsp.buf.rename()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'pd' , 'lua PeekDefinition()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', '[d', 'lua vim.lsp.diagnostic.goto_prev { wrap = false }', opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', ']d', 'lua vim.lsp.diagnostic.goto_next { wrap = false }', opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', '[D', 'lua vim.lsp.diagnostic.goto_prev()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', ']D', 'lua vim.lsp.diagnostic.goto_next()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'do', 'lua vim.lsp.diagnostic.set_loclist()' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', ',d', 'lua vim.lsp.diagnostic.show_line_diagnostics()' , opts) if client.resolved_capabilities.document_range_formatting then vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gq', 'lua format_range_operator()', opts) elseif client.resolved_capabilities.document_formatting then vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gq', 'lua vim.lsp.buf.formatting()', opts) end if client.resolved_capabilities.code_lens then vim.api.nvim_buf_set_keymap(bufnr, "n", "gl", "lua vim.lsp.codelens.run()", opts) vim.api.nvim_command [[autocmd CursorHold,CursorHoldI,InsertLeave lua vim.lsp.codelens.refresh()]] end protocol.CompletionItemKind = { 'īžƒ '; -- text 'īž” '; -- method 'īž” '; -- function 'īŠ˛'; -- ctor 'ī‘„ '; -- field 'ī†’ '; -- variable 'īƒŠ '; -- class 'ī— '; -- interface 'īŖ– '; -- module 'ī‘„ '; -- property 'ī‡Ž '; -- unit 'ī›— '; -- value 'ī¤‘'; -- enum 'ī Š '; -- keyword 'īœ˜ '; -- snippet 'ī € '; -- color 'ī‡‰ '; -- file 'ī”Ŋ '; -- reference 'î—ŋ '; -- folder 'ī”Ģ '; -- enum member 'ī€Ŗ '; -- constant 'īƒŠ '; -- struct 'ī”Ŋ '; -- event 'īĻ”'; -- operator ' '; -- type parameter } if client.name == 'tsserver' then -- Disable tsserver formatting as we plan on formatting via null-ls client.resolved_capabilities.document_formatting = false ts_utils.setup { debug = false, disable_commands = false, enable_import_on_completion = false, import_all_timeout = 5000, import_all_scan_buffers = 100, import_all_select_source = false, import_all_priorities = { buffers = 4, -- loaded buffer names buffer_content = 3, -- loaded buffer content local_files = 2, -- git files or files with relative path markers same_file = 1, -- add to existing import statement }, eslint_enable_code_actions = true, eslint_bin = "eslint", eslint_enable_disable_comments = true, eslint_enable_diagnostics = true, eslint_config_fallback = nil, eslint_show_rule_id = false, enable_formatting = true, formatter = "prettier", formatter_config_fallback = nil, update_imports_on_move = false, require_confirmation_on_move = false, watch_dir = nil, filter_out_diagnostics_by_severity = {}, filter_out_diagnostics_by_code = {}, } ts_utils.setup_client(client) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'go', ':TSLspOrganize' , opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gf', ':TSLspFixCurrent', opts) vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gI', ':TSLspImportAll' , opts) end vim.cmd [[autocmd CursorHold,CursorHoldI lua require'nvim-lightbulb'.update_lightbulb()]] end function set_snippet_capabilities() local capabilities = vim.lsp.protocol.make_client_capabilities() capabilities.textDocument.completion.completionItem.snippetSupport = true capabilities.textDocument.completion.completionItem.resolveSupport = { properties = { 'documentation', 'detail', 'additionalTextEdits', } } return capabilities end -- This should be called only once, so cannot be in on_attach as earlier. -- See https://github.com/jose-elias-alvarez/null-ls.nvim/issues/38 -- Required by nvim-lsp-ts-utils to provide ESLint code actions, diagnostics -- and formatting. null_ls.config {} nvim_lsp["null-ls"].setup {} local servers = { 'hls', 'pylsp', 'tsserver' } for _, lsp in ipairs(servers) do nvim_lsp[lsp].setup { on_attach = on_attach, capabilities = set_snippet_capabilities(), } end nvim_lsp.clangd.setup { on_attach = on_attach, default_config = { cmd = { "clangd", "--background-index", "--pch-storage=memory", "--clang-tidy", "--suggest-missing-includes" }, 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, } } 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 = "=> ", other_hints_prefix = "", highlight = "Hint", }, hover_actions = { auto_focus = true }, crate_graph = { backend = "svg", output = "crates_graph.svg", full = false, } }, server = { on_attach = on_attach, capabilities = set_snippet_capabilities(), settings = { ["rust-analyzer"] = { checkOnSave = { command = "clippy" }, } } }, } require('rust-tools').setup(rust_tool_opts) -- See https://github.com/sumneko/lua-language-server/wiki/Setting-without-VSCode#neovim-with-built-in-lsp-client -- on why we do this library thing -- Idea taken from https://gist.github.com/folke/fe5d28423ea5380929c3f7ce674c41d8 local library = {} local function add_to_library(lib_path) for _, p in pairs(vim.fn.expand(lib_path, false, true)) do p = vim.loop.fs_realpath(p) library[p] = true end end local function add_libraries() local cwd = vim.fn.getcwd() if string.find(cwd, "neovim") then add_to_library("$VIMRUNTIME") elseif string.find(cwd, "dotfiles") then add_to_library("$VIMRUNTIME") add_to_library("~/.config/nvim") add_to_library("~/.local/share/nvim/site/pack/packer/opt/*") add_to_library("~/.local/share/nvim/site/pack/packer/start/*") else add_to_library(cwd .. "/*") end end local function determine_lua_version() local cwd = vim.fn.getcwd() if string.find(cwd, "neovim") or string.find(cwd, "dotfiles") then return "LuaJIT" else return "Lua 5.4" end end add_libraries() local runtime_path = vim.split(package.path, ';') table.insert(runtime_path, "lua/?.lua") table.insert(runtime_path, "lua/?/init.lua") nvim_lsp.sumneko_lua.setup { cmd = { "/usr/bin/lua-language-server" }; on_attach = on_attach, settings = { Lua = { runtime = { version = determine_lua_version(), path = runtime_path, }, completion = { callSnippet = "Both" }, diagnostics = { globals = {'vim'}, }, workspace = { library = library, maxPreload = 2000, preloadFileSize = 50000 }, telemetry = { enable = false, }, }, }, }