return { { "VonHeikemen/lsp-zero.nvim", branch = "v4.x", lazy = true, config = false, }, { "williamboman/mason.nvim", lazy = false, config = true, }, -- Autocompletion { "hrsh7th/nvim-cmp", event = { "InsertEnter", "CmdlineEnter" }, dependencies = { "L3MON4D3/LuaSnip", -- Snippet engine "onsails/lspkind.nvim", -- Pretty formatting in the completion menu -- Completion sources "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-nvim-lsp-signature-help", "hrsh7th/cmp-buffer", "hrsh7th/cmp-path", "saadparwaiz1/cmp_luasnip", }, config = function() local cmp = require("cmp") local luasnip = require("luasnip") cmp.setup({ completion = { -- See :help completeopt completeopt = "menu,menuone,noinsert,preview", }, snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), -- Ctrl+Space does not currently work in Neovim core on Windows -- https://github.com/neovim/neovim/issues/8435 -- [""] = cmp.mapping.complete(), [""] = cmp.mapping.complete(), [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ -- Accept currently selected item behavior = cmp.ConfirmBehavior.Insert, select = true, }), [""] = cmp.mapping.confirm({ -- Accept currently selected item, replacing stuff as needed behavior = cmp.ConfirmBehavior.Replace, select = true, }), [""] = cmp.mapping({ -- https://github.com/hrsh7th/nvim-cmp/wiki/Example-mappings#safely-select-entries-with-cr i = function(fallback) -- In insert mode, only use Enter to complete something if cmp -- is active and the user has explicitly selected an item if cmp.visible() and cmp.get_active_entry() then cmp.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = false }) else fallback() end end, s = cmp.mapping.confirm({ select = true }), c = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true }), }), }), sorting = { priority_weight = 2, comparators = { cmp.config.compare.exact, -- Mostly default sort order from cmp cmp.config.compare.offset, -- cmp.config.compare.scopes, --this is commented in nvim-cmp too cmp.config.compare.score, cmp.config.compare.recently_used, cmp.config.compare.locality, cmp.config.compare.kind, cmp.config.compare.sort_text, cmp.config.compare.length, cmp.config.compare.order, }, }, sources = { -- LSP results should be first priority { name = "nvim_lsp", group_index = 1 }, { name = "nvim_lsp_signature_help", group_index = 2 }, { name = "lazydev", group_index = 2 }, { name = "luasnip", group_index = 2 }, { name = "path", group_index = 2 }, { name = "buffer", group_index = 2, keyword_length = 5 }, }, ---@diagnostic disable-next-line: missing-fields formatting = { format = require("lspkind").cmp_format({ mode = "symbol_text", maxwidth = function() return math.floor(0.45 * vim.o.columns) end, ellipsis_char = "...", show_labelDetails = true, }), }, experimental = { ghost_text = { hl_group = "LspCodeLens", }, }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, }) end, }, -- LSP { "neovim/nvim-lspconfig", cmd = { "LspInfo", "LspInstall", "LspStart" }, event = { "BufReadPre", "BufNewFile" }, dependencies = { { "hrsh7th/cmp-nvim-lsp" }, { "williamboman/mason.nvim" }, { "williamboman/mason-lspconfig.nvim" }, }, config = function() local lsp_zero = require("lsp-zero") lsp_zero.extend_lspconfig({ sign_text = true, capabilities = require("cmp_nvim_lsp").default_capabilities(), }) local border = { { "🭽", "FloatBorder" }, { "▔", "FloatBorder" }, { "🭾", "FloatBorder" }, { "▕", "FloatBorder" }, { "🭿", "FloatBorder" }, { "▁", "FloatBorder" }, { "🭼", "FloatBorder" }, { "▏", "FloatBorder" }, } local border_handlers = { ["textDocument/hover"] = vim.lsp.buf.hover({ border = border }), ["textDocument/signatureHelp"] = vim.lsp.buf.signature_help({ border = border }) } require("mason-lspconfig").setup({ automatic_enable = { "basedpyright", "ruff", "lua_ls" }, handlers = { -- this first function is the "default handler" -- it applies to every language server without a "custom handler" function(server_name) require("lspconfig")[server_name].setup({ handlers = border_handlers }) end, ["basedpyright"] = function() local lspconfig = require("lspconfig") lspconfig.basedpyright.setup({ settings = { basedpyright = { typeCheckingMode = "standard", }, }, }) end, }, }) vim.lsp.inlay_hint.enable() end, }, -- Formatting { "stevearc/conform.nvim", config = function() local conform = require("conform") local prettier = { "prettierd", "prettier" } conform.setup({ formatters_by_ft = { lua = { "stylua" }, python = { "ruff_format", lsp_format = "fallback" }, go = { "gopls" }, rust = { "clippy", lsp_format = "fallback" }, markdown = prettier, }, format_after_save = { async = true, stop_after_first = true, lsp_format = "fallback", }, }) local function format() conform.format({ async = true, lsp_fallback = true }) end vim.keymap.set({ "n", "v" }, "rf", format, { desc = "Reformat" }) vim.api.nvim_create_user_command("Format", format, {}) end, }, -- Lint { "mfussenegger/nvim-lint", dependencies = { -- Additional lua configuration, makes nvim stuff amazing! "folke/neodev.nvim", }, event = { "BufReadPre", "BufNewFile", }, opts = { autocmd = { events = { "BufEnter", "BufWritePost" }, pattern = { "*.py", "*.lua", "*.js", "*.ts", }, linters_by_ft = { python = { "mypy" }, }, }, on_demand = { linters_by_ft = { python = { "mypy", "pylint" }, }, }, }, config = function(_, opts) local lint = require("lint") lint.linters_by_ft = { javascript = { "eslint_d" }, typescript = { "eslint_d" }, } local function lint_autocmd() local filetype = vim.bo.filetype local linter_names = opts.autocmd.linters_by_ft[filetype] or {} require("lint").try_lint(linter_names) end local function lint_on_demand() local filetype = vim.bo.filetype local linter_names = opts.on_demand.linters_by_ft[filetype] or {} require("lint").try_lint(linter_names) end local lint_augroup = vim.api.nvim_create_augroup("user-nvim-lint", { clear = true }) vim.api.nvim_create_autocmd(opts.autocmd.events, { group = lint_augroup, pattern = opts.autocmd.pattern, callback = lint_autocmd, }) vim.keymap.set("n", "cl", lint_on_demand, { desc = "[C]ode [l]int" }) -- Hate to remove this because I was pretty proud of it, but I'm removing -- Pylint altogether. Since this is just my code, I'm leaving it here -- as a reference if I want to mess with it again later. -- -- I use Pylint consistently, and I have some projects that enforce -- -- that Pylint must be passing. However, I don't always want to see -- -- low-severity Pylint warnings like "missing docstring" for things -- -- I'm still actively writing. They can be distracting. -- -- -- -- Build out a simple behavior that switches the Pylint arguments -- -- to include or exclude Pylint's complexity (C) and conventions (R) -- -- messages. -- -- -- -- I intentionally make this a global user command instead of a -- -- buffer-specific one. -- -- local default_pylint_args = vim.deepcopy(lint.linters.pylint.args) -- local simple_pylint_args = vim.deepcopy(lint.linters.pylint.args) -- table.insert(simple_pylint_args, "--disable=C,R") -- -- local disable_pylint_low_severity = false -- local function toggle_pylint_severity_mode() -- disable_pylint_low_severity = not disable_pylint_low_severity -- if disable_pylint_low_severity then -- lint.linters.pylint.args = simple_pylint_args -- print("Pylint mode changed to error/warning only") -- else -- lint.linters.pylint.args = default_pylint_args -- print("Pylint mode reset to default") -- end -- -- Run the linter again to remove leftover messages or restore -- -- newly added ones -- lint.try_lint() -- end -- -- vim.api.nvim_create_user_command("PylintSeverityToggle", toggle_pylint_severity_mode, {}) end, }, -- Code actions { "aznhe21/actions-preview.nvim", config = function() vim.keymap.set({ "v", "n" }, "ca", require("actions-preview").code_actions) end, }, -- Cool neovim dev stuff { "folke/lazydev.nvim", ft = "lua", -- only load on lua files opts = { library = { -- See the configuration section for more details -- Load luvit types when the `vim.uv` word is found { path = "luvit-meta/library", words = { "vim%.uv" } }, }, }, }, { "Bilal2453/luvit-meta", lazy = true }, -- optional `vim.uv` typings }