return { "neovim/nvim-lspconfig", event = { "BufReadPre", "BufNewFile" }, dependencies = { "hrsh7th/cmp-nvim-lsp", }, config = function() local capabilities = require("cmp_nvim_lsp").default_capabilities() -- Load project-local LSP settings from .nvim.lua local function load_project_lsp_settings(server_name, root_dir) if not root_dir then return {} end local config_file = root_dir .. "/.nvim.lua" if vim.fn.filereadable(config_file) == 1 then local ok, project_config = pcall(dofile, config_file) if ok and project_config and project_config.lsp and project_config.lsp[server_name] then return project_config.lsp[server_name] end end return {} end -- Setup keymaps on attach local function setup_keymaps(bufnr) local map = function(mode, lhs, rhs, desc) vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, noremap = true, desc = desc }) end map('n', 'gd', vim.lsp.buf.definition, 'LSP: Go to definition') map('n', 'gr', vim.lsp.buf.references, 'LSP: References') map('n', 'gD', vim.lsp.buf.declaration, 'LSP: Go to declaration') map('n', 'gI', vim.lsp.buf.implementation, 'LSP: Go to implementation') map('n', 'K', vim.lsp.buf.hover, 'LSP: Hover') end -- Global LspAttach handler to load project settings and setup keymaps vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup('lsp_project_settings', { clear = true }), callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) if not client then return end -- Setup keymaps for this buffer setup_keymaps(args.buf) -- Load and send project-specific settings local project_settings = load_project_lsp_settings(client.name, client.root_dir) if project_settings.settings then -- Merge with existing settings client.settings = vim.tbl_deep_extend( "force", client.settings or {}, project_settings.settings ) -- Send didChangeConfiguration to update the server vim.schedule(function() client.notify("workspace/didChangeConfiguration", { settings = client.settings }) end) end end, }) -- Configure servers using vim.lsp.config (Neovim 0.11+ API) local function configure(server_name, opts) opts = opts or {} -- Merge with defaults local config = vim.tbl_deep_extend("force", { capabilities = capabilities, }, opts) -- Configure the server using the new API vim.lsp.config(server_name, config) end -- Configure all servers configure("lua_ls", { settings = { Lua = { diagnostics = { globals = { "vim" } }, }, }, }) configure("ts_ls") configure("html") configure("cssls") configure("jsonls") configure("bashls") configure("marksman") configure("intelephense", { single_file_support = false, }) -- Python: pyright for type checking, ruff for linting/formatting configure("pyright", { settings = { pyright = { -- Only use pyright for type checking disableOrganizeImports = true, -- Let ruff handle imports }, python = { analysis = { typeCheckingMode = "basic", -- Type checking only -- Let ruff handle style/formatting diagnostics diagnosticSeverityOverrides = { -- Keep type/syntax errors, warnings -- Disable style-related diagnostics (ruff handles these) }, }, }, }, }) configure("ruff") -- Ruff LSP for formatting + linting -- Enable all configured servers vim.lsp.enable({ "lua_ls", "ts_ls", "html", "cssls", "jsonls", "bashls", "marksman", "intelephense", "pyright", "ruff" }) end, }