return { { "neovim/nvim-lspconfig", dependencies = { "williamboman/mason.nvim", "williamboman/mason-lspconfig.nvim", "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-buffer", "hrsh7th/cmp-path", "hrsh7th/cmp-cmdline", "hrsh7th/nvim-cmp", "L3MON4D3/LuaSnip", "saadparwaiz1/cmp_luasnip", "nvim-telescope/telescope-ui-select.nvim", "nvimtools/none-ls.nvim", "nvimdev/lspsaga.nvim", 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons', }, config = function() -- setup -- local capabilities = vim.tbl_deep_extend( "force", {}, vim.lsp.protocol.make_client_capabilities() ) -- mason -- require("mason").setup({ PATH = "append", ui = { border = "rounded", icons = { package_installed = "✔", package_pending = "➜", package_uninstalled = "✘" } } }) -- mason lspconfig -- require("mason-lspconfig").setup({ ensure_installed = { "lua_ls", "clangd", "rust_analyzer", }, handlers = { -- The first entry (without a key) will be the default handler -- and will be called for each installed server that doesn't have -- a dedicated handler. function(server_name) -- default handler (optional) require("lspconfig")[server_name].setup { capabilities = capabilities } end, } }) -- telescope ui for null-ls require("telescope").setup { extensions = { ["ui-select"] = { -- require("telescope.themes").get_dropdown { -- -- even more opts -- } } } } require("telescope").load_extension("ui-select") -- null-ls (none-ls) local null_ls = require('null-ls') require("null-ls").setup({ sources = { null_ls.builtins.diagnostics.trail_space.with { disabled_filetypes = { "lua" } }, null_ls.builtins.code_actions.gitrebase, null_ls.builtins.diagnostics.checkmake, null_ls.builtins.diagnostics.cmake_lint, null_ls.builtins.diagnostics.yamllint, null_ls.builtins.diagnostics.sqlfluff.with({ extra_args = { "--dialect", "sqlite" }, }), null_ls.builtins.formatting.sqlfluff.with({ extra_args = { "--dialect", "sqlite" }, }), null_ls.builtins.formatting.asmfmt, null_ls.builtins.formatting.cmake_format, null_ls.builtins.formatting.yamlfmt, null_ls.builtins.formatting.shfmt, null_ls.builtins.formatting.shellharden, }, }) -- lspsaga (pretty lsp-windows) require('lspsaga').setup({ symbol_in_winbar = { enable = false, show_file = false }, finder = { keys = { toggle_or_open = "", quit = { '', 'q' } } }, outline = { win_position = 'right', win_width = 32, auto_preview = true, }, lightbulb = { enable = false }, ui = { code_action = '', title = true, border = 'rounded', }, rename = { in_select = false, keys = { quit = { '', 'q' }, select = '' } }, hover_doc = { open_cmd = '!firefox' }, code_action = { keys = { quit = { '', 'q' } }, extend_gitsigns = false, }, definition = { keys = { quit = { '', 'q' }, }, }, diagnostic = { border_follow = true, extend_relatedInformation = true, keys = { quit = { '', 'q' }, quit_in_show = { '', 'q' }, } } }) -- autocomplete -- local kind_icons = { 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 has_words_before = function() unpack = unpack or table.unpack local line, col = unpack(vim.api.nvim_win_get_cursor(0)) return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil end local luasnip = require("luasnip") local cmp = require("cmp") cmp.setup({ formatting = { format = function(entry, vim_item) -- Kind icons vim_item.kind = string.format('%s %s', kind_icons[vim_item.kind], vim_item.kind) -- This concatonates the icons with the name of the item kind -- Source vim_item.menu = ({ buffer = "", nvim_lsp = "", luasnip = "", nvim_lua = "", latex_symbols = "", })[entry.source.name] return vim_item end }, snippet = { expand = function(args) require('luasnip').lsp_expand(args.body) -- For `luasnip` users. end, }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, mapping = cmp.mapping.preset.insert({ [''] = cmp.mapping.scroll_docs(-4), [''] = cmp.mapping.scroll_docs(4), [''] = cmp.mapping(function(fallback) if cmp.visible() then cmp.abort() else cmp.complete() end end), [''] = cmp.mapping.confirm({ select = false }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() -- You could replace the expand_or_jumpable() calls with expand_or_locally_jumpable() -- they way you will only jump inside the snippet region elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() elseif has_words_before() then cmp.complete() else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), }), sources = cmp.config.sources({ { name = 'nvim_lsp' }, { name = 'luasnip' }, -- For luasnip users. { name = 'buffer', option = { get_bufnrs = function() return vim.api.nvim_list_bufs() end }, }, }, { }), -- Set configuration for specific filetype. -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). cmp.setup.cmdline({ '/', '?' }, { mapping = cmp.mapping.preset.cmdline(), sources = { { name = 'buffer' } } }), -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). cmp.setup.cmdline(':', { mapping = cmp.mapping.preset.cmdline(), sources = cmp.config.sources({ { name = 'path' } }, { { name = 'cmdline' } }) }) }) -- config -- vim.diagnostic.config({ update_in_insert = true, signs = { text = { [vim.diagnostic.severity.ERROR] = "✘ ", [vim.diagnostic.severity.WARN] = " ", [vim.diagnostic.severity.HINT] = " ", [vim.diagnostic.severity.INFO] = " " } }, float = { focusable = false, style = "minimal", border = "rounded", source = "always", header = "", prefix = "", }, virtual_text = { prefix = '●', -- Could be '●', '■', 'x', '▎', or anything else }, }) -- keymaps -- local opts = { noremap = true, silent = true } vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) vim.keymap.set('n', 'K', function() vim.lsp.buf.hover { border = "rounded" } end, opts) vim.keymap.set('n', 'k', function() vim.lsp.buf.hover { border = "rounded" } end, opts) vim.keymap.set('n', 'cl', "LspInfo", opts) vim.keymap.set('n', 'cd', vim.diagnostic.open_float, opts) vim.keymap.set('n', '[n', vim.diagnostic.goto_prev, opts) vim.keymap.set('n', ']n', vim.diagnostic.goto_next, opts) vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) vim.keymap.set('n', 'cf', function() vim.lsp.buf.format { async = true } end, opts) vim.keymap.set('v', 'cf', function() vim.lsp.buf.format { async = true } end, opts) vim.keymap.set("n", "fws", function() vim.lsp.buf.workspace_symbol() end, opts) vim.keymap.set("i", "", function() vim.lsp.buf.signature_help() end, opts) vim.keymap.set('n', '', "Lspsaga term_toggle", opts) vim.keymap.set('t', '', "Lspsaga term_toggle", opts) vim.keymap.set('n', 'so', 'Lspsaga outline', opts) vim.keymap.set('n', 'sf', 'Lspsaga finder', opts) vim.keymap.set('n', 'sd', 'Lspsaga peek_definition', opts) vim.keymap.set('n', 'cw', "Lspsaga rename mode=n", opts) vim.keymap.set('n', 'cA', vim.lsp.buf.code_action, opts) vim.keymap.set('n', 'ca', 'Lspsaga code_action', opts) end, } }