-- LSP stack: -- mason → installs language servers automatically -- lspconfig → configures them -- nvim-cmp → completion popup -- LuaSnip → snippet engine (required by cmp) -- -- LSP keymaps (active when a file has an attached language server): -- K → hover documentation -- gd → go to definition -- gr → list references -- rn → rename symbol -- ca → code actions (quick fixes, imports, etc.) -- d → show line diagnostics -- [d / ]d → jump to prev/next diagnostic return { -- ── Mason: auto-installs language servers ────────────────────────────────── { "williamboman/mason.nvim", config = function() require("mason").setup() end, }, { "williamboman/mason-lspconfig.nvim", dependencies = { "williamboman/mason.nvim" }, config = function() require("mason-lspconfig").setup({ ensure_installed = { "bashls", -- Bash "pyright", -- Python "omnisharp", -- C# }, automatic_installation = true, }) end, }, -- ── Completion ───────────────────────────────────────────────────────────── { "hrsh7th/nvim-cmp", dependencies = { "hrsh7th/cmp-nvim-lsp", -- LSP completions "hrsh7th/cmp-buffer", -- words from current buffer "hrsh7th/cmp-path", -- file paths "L3MON4D3/LuaSnip", -- snippet engine "saadparwaiz1/cmp_luasnip", }, config = function() local cmp = require("cmp") local luasnip = require("luasnip") cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.complete(), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() 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" }, }, { { name = "buffer" }, { name = "path" }, }), }) end, }, -- ── LSP config ───────────────────────────────────────────────────────────── { "neovim/nvim-lspconfig", dependencies = { "williamboman/mason-lspconfig.nvim", "hrsh7th/cmp-nvim-lsp", }, config = function() local lspconfig = require("lspconfig") local capabilities = require("cmp_nvim_lsp").default_capabilities() -- Keymaps applied whenever an LSP attaches to a buffer vim.api.nvim_create_autocmd("LspAttach", { callback = function(ev) local map = vim.keymap.set local opts = function(desc) return { buffer = ev.buf, desc = desc } end map("n", "K", vim.lsp.buf.hover, opts("Hover docs")) map("n", "gd", vim.lsp.buf.definition, opts("Go to definition")) map("n", "gr", vim.lsp.buf.references, opts("References")) map("n", "rn", vim.lsp.buf.rename, opts("Rename symbol")) map("n", "ca", vim.lsp.buf.code_action, opts("Code action")) map("n", "d", vim.diagnostic.open_float, opts("Line diagnostics")) map("n", "[d", vim.diagnostic.goto_prev, opts("Prev diagnostic")) map("n", "]d", vim.diagnostic.goto_next, opts("Next diagnostic")) end, }) lspconfig.bashls.setup({ capabilities = capabilities }) lspconfig.pyright.setup({ capabilities = capabilities }) lspconfig.omnisharp.setup({ capabilities = capabilities }) end, }, }