local M = {} function M.lsp_conf() local lspconf = require('lspconfig') local on_attach = function(client, bufnr) vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end local opts = {noremap = true, silent = true} buf_set_keymap('n', 'gD', ':lua vim.lsp.buf.declaration()', opts) buf_set_keymap('n', 'gd', ':lua vim.lsp.buf.definition()', opts) buf_set_keymap('n', 'K', ':lua vim.lsp.buf.hover()', opts) buf_set_keymap('n', 'gi', ':lua vim.lsp.buf.implementation()', opts) buf_set_keymap('n', 'lx', ':lua vim.lsp.buf.signature_help()', opts) buf_set_keymap('n', 'la', ':lua vim.lsp.buf.add_workspace_folder()', opts) buf_set_keymap('n', 'lr', ':lua vim.lsp.buf.remove_workspace_folder()', opts) buf_set_keymap('n', 'lw', ':lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))', opts) buf_set_keymap('n', 'ld', ':lua vim.lsp.buf.type_definition()', opts) buf_set_keymap('n', 'ln', ':lua vim.lsp.buf.rename()', opts) buf_set_keymap('n', 'gr', ':lua vim.lsp.buf.references()', opts) buf_set_keymap('n', 'le', ':lua vim.lsp.diagnostic.show_line_diagnostics()', opts) buf_set_keymap('n', '[d', ':lua vim.lsp.diagnostic.goto_prev()', opts) buf_set_keymap('n', ']d', ':lua vim.lsp.diagnostic.goto_next()', opts) buf_set_keymap('n', 'll', ':lua vim.lsp.diagnostic.set_loclist()', opts) if client.resolved_capabilities.document_formatting then buf_set_keymap('n', 'lo', ':lua vim.lsp.buf.formatting()', opts) -- vim.api.nvim_command('autocmd BufWritePre lua vim.lsp.buf.formatting_sync()') elseif client.resolved_capabilities.document_range_formatting then buf_set_keymap('n', 'lo', ':lua vim.lsp.buf.range_formatting({},{0,0},{vim.fn.line("$"),0})', opts) buf_set_keymap('v', 'lo', ':lua vim.lsp.buf.range_formatting()', opts) -- vim.api.nvim_command('autocmd BufWritePre lua vim.lsp.buf.range_formatting({},{0,0},{vim.fn.line("$"),0})') end -- Attach lsp_signature.nvim require('lsp_signature').on_attach({ bind = true, -- This is mandatory, otherwise border config doesn't work floating_window = true, fix_pos = true, hint_prefix = ' ', transpancy = 5, handler_opts = {border = 'none'}, zindex = 50, -- set to 200 to make the float window on top of others toggle_key = '' }, bufnr) end local capabilities = vim.lsp.protocol.make_client_capabilities() -- Add additional capabilities supported by nvim-cmp local completionItem = capabilities.textDocument.completion.completionItem completionItem.documentationFormat = {'markdown', 'plaintext'} completionItem.snippetSupport = true completionItem.preselectSupport = true completionItem.insertReplaceSupport = true completionItem.labelDetailsSupport = true completionItem.deprecatedSupport = true completionItem.commitCharactersSupport = true completionItem.tagSupport = {valueSet = {1}} completionItem.resolveSupport = { properties = { 'documentation', 'detail', 'additionalTextEdits', } } -- Replace the default lsp diagnostic letters with prettier symbols vim.fn.sign_define('LspDiagnosticsSignError', {text = ''}) vim.fn.sign_define('LspDiagnosticsSignWarning', {text = ''}) vim.fn.sign_define('LspDiagnosticsSignInformation', {text = ''}) vim.fn.sign_define('LspDiagnosticsSignHint', {text = ''}) --------------------------- -- Server configurations -- --------------------------- -- https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md local servers_path = vim.fn.stdpath('data') .. '/lsp' -- C/C++ lspconf.clangd.setup { on_attach = on_attach, capabilities = capabilities, filetypes = {'c', 'cpp'}, init_options = { usePlaceholders = true, completeUnimported = true, clangdFileStatus = true }, cmd = { 'clangd', '-j=2', '--background-index', '--clang-tidy', '--completion-style=detailed', '--pch-storage=memory', '--header-insertion=iwyu', '--header-insertion=decorators' } } -- Lua local lua_lib_path = {} local lua_runtime_path = {} -- lua_lib_path[vim.fn.expand('~/.luarocks/share/lua/5.3')] = true -- lua_lib_path[vim.fn.expand('/usr/share/lua/5.3')] = true lua_lib_path[os.getenv('VIMRUNTIME') .. '/lua'] = true -- local function add(lib) -- for _, p in pairs(vim.fn.expand(lib .. '/lua', false, true)) do -- p = vim.loop.fs_realpath(p) -- if p then lua_lib_path[p] = true end -- end -- end -- for _, site in pairs(vim.split(vim.opt.packpath:get(), ',')) do -- add(site .. '/pack/*/opt/*') -- add(site .. '/pack/*/start/*') -- end table.insert(lua_runtime_path, 'lua/?.lua') table.insert(lua_runtime_path, 'lua/?/init.lua') -- table.insert(lua_runtime_path, '?.lua') -- table.insert(lua_runtime_path, '?/?.lua') -- table.insert(lua_runtime_path, '?/init.lua') for lib, _ in pairs(lua_lib_path) do table.insert(lua_runtime_path, lib .. '/?.lua') table.insert(lua_runtime_path, lib .. '/?/init.lua') end lspconf.sumneko_lua.setup { on_attach = on_attach, capabilities = capabilities, cmd = { servers_path .. '/sumneko_lua/bin/Linux/lua-language-server', '-E', '-e', 'LANG=en', servers_path .. '/sumneko_lua/main.lua' }, settings = { Lua = { diagnostics = {globals = {'vim'}}, runtime = {version = 'LuaJIT', path = lua_runtime_path}, workspace = { library = lua_lib_path, maxPreload = 1000, preloadFileSize = 150 }, completion = {callSnippet = 'Replace'}, hint = {enable = true}, telemetry = {enable = false} } } } -- Go lspconf.gopls.setup { on_attach = on_attach, capabilities = capabilities, cmd = {servers_path .. '/gopls/gopls', '--remote=auto'}, init_options = { usePlaceholders = true, completeUnimported = true } } -- Yaml lspconf.yamlls.setup { on_attach = on_attach, capabilities = capabilities, cmd = {servers_path .. '/yamlls/node_modules/.bin/yaml-language-server', '--stdio'}, settings = { redhat = {telemetry = {enabled = false}}, yaml = { format = { bracketSpacing = true, printWidth = 80, -- proseWrap = 'always', -- default is 'preserve' -- singleQuote = true, -- editor.formatOnType = true } } } } -- Ansible lspconf.ansiblels.setup { on_attach = on_attach, capabilities = capabilities, cmd = {'node', servers_path .. '/ansiblels/out/server/src/server.js', '--stdio'}, filetypes = {'yaml', 'yaml.ansible'}, settings = { -- python = {interpreterPath = 'python3'}, executionEnvironment = {enabled = false} } } -- Tailwind -- lspconf.tailwindcss.setup { -- on_attach = on_attach, -- capabilities = capabilities, -- cmd = {servers_path .. '/tailwindcss/node_modules/.bin/tailwindcss-language-server', '--stdio'}, -- settings = { -- tailwindCSS = { -- emmetCompletions = true -- } -- } -- } -- Emmet lspconf.emmet_ls.setup { cmd = {servers_path .. '/emmet_ls/node_modules/.bin/emmet-ls', '--stdio'}, filetypes = { 'html', 'xml', 'css', 'scss', 'sass', 'javascript', 'javascriptreact' }, capabilities = capabilities } -- HTML lspconf.html.setup { on_attach = on_attach, capabilities = capabilities, cmd = {servers_path .. '/vscode/node_modules/.bin/vscode-html-language-server', '--stdio'}, filetypes = {'html', 'markdown'} } -- JSON lspconf.jsonls.setup { on_attach = on_attach, capabilities = capabilities, cmd = {servers_path .. '/vscode/node_modules/.bin/vscode-json-language-server', '--stdio'}, settings = { json = { -- Schema catalog: https://www.schemastore.org/api/json/catalog.json schemas = { { fileMatch = {'package.json'}, url = 'https://json.schemastore.org/package.json' }, { fileMatch = {'tsconfig*.json'}, url = 'https://json.schemastore.org/tsconfig.json' }, { fileMatch = { '.prettierrc', '.prettierrc.json', 'prettier.config.json' }, url = 'https://json.schemastore.org/prettierrc.json' }, { fileMatch = {'.eslintrc', '.eslintrc.json'}, url = 'https://json.schemastore.org/eslintrc.json' }, { fileMatch = { '.babelrc', '.babelrc.json', 'babel.config.json' }, url = 'https://json.schemastore.org/babelrc.json' }, { fileMatch = {'lerna.json'}, url = 'https://json.schemastore.org/lerna.json' }, { fileMatch = {'now.json', 'vercel.json'}, url = 'https://json.schemastore.org/now.json' }, { fileMatch = { '.stylelintrc', '.stylelintrc.json', 'stylelint.config.json' }, url = 'http://json.schemastore.org/stylelintrc.json' } } } } } -- Others local servers = { rust_analyzer = {'rust-analyzer'}, sqls = {servers_path .. '/sqls/sqls'}, cmake = {servers_path .. '/cmake/venv/bin/cmake-language-server'}, bashls = {servers_path .. '/bashls/node_modules/.bin/bash-language-server', 'start'}, dockerls = {servers_path .. '/dockerls/node_modules/.bin/docker-langserver', '--stdio'}, cssls = {servers_path .. '/vscode/node_modules/.bin/vscode-css-language-server', '--stdio'}, pyright = {servers_path .. '/pyright/node_modules/.bin/pyright-langserver', '--stdio'}, -- vimls = {servers_path .. '/vimls/node_modules/.bin/vim-language-server', '--stdio'}, tsserver = {servers_path .. '/tsserver/node_modules/.bin/typescript-language-server', '--stdio'} } for server, _ in pairs(servers) do lspconf[server].setup { on_attach = on_attach, capabilities = capabilities, cmd = servers[server] } end ------------------------ -- Linters/Formatters -- ------------------------ -- TODO: efm-langserver as another option local null_ls = require('null-ls') -- Register sources null_ls.config { sources = { -- Formatters null_ls.builtins.formatting.stylua.with { condition = function(utils) return utils.root_has_file('stylua.toml') end }, null_ls.builtins.formatting.clang_format.with { filetypes = {'c', 'cpp'} } -- Linters } } lspconf['null-ls'].setup { on_attach = on_attach } end function M.sqls_conf() require('sqls').setup { picker = 'telescope' } end function M.lightbulb_conf() vim.api.nvim_command [[ autocmd CursorHold * lua require('nvim-lightbulb').update_lightbulb({sign = {enabled = false}, status_text = {enabled = true, text = ' Code action', text_unavailable = ''}}) ]] end function M.trouble_conf() require('trouble').setup { mode = 'lsp_workspace_diagnostics', fold_open = ' ', fold_closed = '', action_keys = { open_split = {''}, open_vsplit = {''}, open_tab = {''} }, signs = { error = '', warning = '', information = '', hint = '', other = '' } } end -- function M.comments_conf() -- require('todo-comments').setup { -- signs = false, -- -- sign_priority = 8, -- keywords = { -- FIX = { -- icon = ' ', -- icon used for the sign, and in search results -- color = 'error', -- can be a hex color, or a named color (see below) -- alt = {'FIXME', 'BUG', 'FIXIT', 'ISSUE'}, -- a set of other keywords that all map to this FIX keywords -- -- signs = false, -- configure signs for some keywords individually -- }, -- TODO = {icon = ' ', color = 'info'}, -- HACK = {icon = ' ', color = 'warning'}, -- WARN = {icon = ' ', color = 'warning', alt = {'WARNING', 'XXX'}}, -- PERF = {icon = ' ', alt = {'OPTIM', 'PERFORMANCE', 'OPTIMIZE'}}, -- NOTE = {icon = ' ', color = 'hint', alt = {'INFO'}}, -- }, -- merge_keywords = true, -- highlight = { -- before = '', -- 'fg' or 'bg' or empty -- keyword = 'fg', -- 'fg', 'bg', 'wide' or empty. (wide is the same as bg, but will also highlight surrounding characters) -- after = '', -- 'fg' or 'bg' or empty -- pattern = [[.*<(KEYWORDS)\s*:]], -- pattern or table of patterns, used for highlightng (vim regex) -- comments_only = true, -- uses treesitter to match keywords in comments only -- max_line_len = 400, -- ignore lines longer than this -- exclude = {'org'}, -- list of file types to exclude highlighting -- }, -- colors = { -- error = {'LspDiagnosticsDefaultError', 'TSDanger', 'Red'}, -- warning = {'LspDiagnosticsDefaultWarning', 'TSWarning', 'Yellow'}, -- info = {'LspDiagnosticsDefaultInformation', 'TSNote', 'Blue'}, -- hint = {'LspDiagnosticsDefaultHint', 'Cyan'}, -- default = {'Normal', 'White'} -- }, -- search = { -- command = 'rg', -- args = { -- '--hidden', -- '--color=never', -- '--no-heading', -- '--with-filename', -- '--line-number', -- '--column', -- }, -- -- regex that will be used to match keywords. -- -- don't replace the (KEYWORDS) placeholder -- pattern = [[\b(KEYWORDS):]] -- ripgrep regex -- -- pattern = [[\b(KEYWORDS)\b]] -- match without the extra colon. You'll likely get false positives -- } -- } -- end function M.outline_conf() vim.g.symbols_outline = { highlight_hovered_item = false, show_guides = false } end function M.dap_conf() local dap = require('dap') vim.fn.sign_define('DapBreakpoint', {text='', texthl='Orange'}) vim.fn.sign_define('DapLogPoint', {text='', texthl='Orange'}) vim.fn.sign_define('DapStopped', {text='ﱢ', texthl='Orange'}) vim.fn.sign_define('DapBreakpointRejected', {text='', texthl='Red'}) -- Mappings vim.api.nvim_command('n', 'dn', ':lua require("dap").continue()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dd', ':lua require("dap").disconnect()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'db', ':lua require("dap").toggle_breakpoint()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dB', ':lua require("dap").set_breakpoint(vim.fn.input("Breakpoint condition: "))', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dl', ':lua require("dap").list_breakpoints()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dc', ':lua require("dap").run_to_cursor()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dz', ':lua require("dap").run_last()', {noremap = true, silent = true}) vim.api.nvim_command('n', '', ':lua require("dap").step_over()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dv', ':lua require("dap").step_over()', {noremap = true, silent = true}) vim.api.nvim_command('n', '', ':lua require("dap").step_into()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'di', ':lua require("dap").step_into()', {noremap = true, silent = true}) vim.api.nvim_command('n', '', ':lua require("dap").step_out()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'do', ':lua require("dap").step_out()', {noremap = true, silent = true}) vim.api.nvim_command('n', 'dr', ':lua require("dap").repl.open()', {noremap = true, silent = true}) end function M.dapui_conf() local dap, dapui = require('dap'), require('dapui') dap.listeners.after.event_initialized['dapui_config'] = function() dapui.open() end dap.listeners.before.event_terminated['dapui_config'] = function() dapui.close() end dap.listeners.before.event_exited['dapui_config'] = function() dapui.close() end require('dapui').setup { icons = {expanded = '', collapsed = ''}, mappings = { expand = {'', '<2-LeftMouse>'}, open = 'o', remove = 'd', edit = 'e', repl = 'r' }, sidebar = { elements = { -- Provide as ID strings or tables with 'id' and 'size' keys -- 'size' can be float or integer > 1 {id = 'scopes', size = 0.25}, {id = 'breakpoints', size = 0.25}, {id = 'stacks', size = 0.25}, {id = 'watches', size = 0.25}, }, size = 40, position = 'left' }, tray = { elements = {'repl'}, size = 10, position = 'bottom' }, floating = { max_height = nil, -- These can be integers or a float between 0 and 1. max_width = nil, -- Floats will be treated as percentage of your screen. mappings = { close = {'q', ''} } }, windows = {indent = 1} } -- Mappings vim.api.nvim_set_keymap('n', 'de', ':lua require("dapui").eval()', {noremap = true, silent = true}) vim.api.nvim_set_keymap('v', 'de', ':lua require("dapui").eval()', {noremap = true, silent = true}) vim.api.nvim_set_keymap('n', 'df', ':lua require("dapui").float_element()', {noremap = true, silent = true}) vim.api.nvim_set_keymap('n', 'dt', ':lua require("dapui").toggle()', {noremap = true, silent = true}) end return M