return { "neovim/nvim-lspconfig", event = { "BufReadPre", "BufNewFile" }, dependencies = { { "hrsh7th/cmp-nvim-lsp" }, { "antosha417/nvim-lsp-file-operations", config = true }, { "williamboman/mason.nvim", config = true }, { "williamboman/mason-lspconfig.nvim" }, { "WhoIsSethDaniel/mason-tool-installer.nvim" }, { "j-hui/fidget.nvim", opts = {} }, { "folke/neodev.nvim", opts = {} }, }, config = function() local lspconfig = require("lspconfig") local util = require("lspconfig.util") local keymap = vim.keymap vim.api.nvim_create_autocmd("LspAttach", { group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }), callback = function(event) local opts = { noremap = true, silent = true } opts.desc = "Show LSP references" keymap.set("n", "gr", "Telescope lsp_references", opts) opts.desc = "Go to declaration" keymap.set("n", "gD", vim.lsp.buf.declaration, opts) opts.desc = "Show LSP definitions" keymap.set("n", "gd", "Telescope lsp_definitions", opts) opts.desc = "Show LSP implementations" keymap.set("n", "gi", "Telescope lsp_implementations", opts) opts.desc = "Show LSP type definitions" keymap.set("n", "gt", "Telescope lsp_type_definitions", opts) opts.desc = "See available code actions" keymap.set({ "n", "v" }, "ca", vim.lsp.buf.code_action, opts) opts.desc = "Smart rename" keymap.set("n", "rn", vim.lsp.buf.rename, opts) opts.desc = "Show buffer diagnostics" keymap.set("n", "D", "Telescope diagnostics bufnr=0", opts) opts.desc = "Show line diagnostics" keymap.set("n", "d", vim.diagnostic.open_float, opts) opts.desc = "Go to previous diagnostic" keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) opts.desc = "Go to next diagnostic" keymap.set("n", "]d", vim.diagnostic.goto_next, opts) opts.desc = "Go to previous diagnostic (error only)" keymap.set("n", "[e", function() vim.diagnostic.goto_prev({ severity = vim.diagnostic.severity.ERROR }) end, opts) opts.desc = "Go to next diagnostic (error only)" keymap.set("n", "]e", function() vim.diagnostic.goto_next({ severity = vim.diagnostic.severity.ERROR }) end, opts) opts.desc = "Show documentation for what is under cursor" keymap.set("n", "ld", vim.diagnostic.setqflist, opts) opts.desc = "Show documentation for what is under cursor" keymap.set("n", "K", vim.lsp.buf.hover, opts) local client = vim.lsp.get_client_by_id(event.data.client_id) if client and client.server_capabilities.documentHighlightProvider then vim.api.nvim_create_autocmd("LspDetach", { group = vim.api.nvim_create_augroup("lsp-detach", { clear = true }), callback = function(event2) vim.lsp.buf.clear_references() end, }) end -- The following autocommand is used to enable inlay hints in your -- code, if the language server you are using supports them -- -- This may be unwanted, since they displace some of your code if client and client.server_capabilities.inlayHintProvider and vim.lsp.inlay_hint then opts.desc = "Toggle Inlay Hints" keymap.set("n", "th", function() vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({})) end, opts) end end, }) local capabilities = vim.lsp.protocol.make_client_capabilities() capabilities = vim.tbl_deep_extend("force", capabilities, require("cmp_nvim_lsp").default_capabilities()) -- Function to detect the operating system local function get_os() local handle = io.popen("uname") if not handle then return error("Failed to detect operating system") end local result = handle:read("*a") handle:close() return result:lower():gsub("%s+", "") end -- Set the base path based on the operating system local os = get_os() local base_path = "" if os == "darwin" then base_path = "/opt/homebrew/lib/node_modules" elseif os == "linux" then base_path = "/usr/local/lib/node_modules" end local function get_typescript_server_path(root_dir) local global_ts = base_path .. "/typescript/lib" local found_ts = "" local function check_dir(path) found_ts = util.path.join(path, "node_modules", "typescript", "lib") if util.path.exists(found_ts) then return path end end if util.search_ancestors(root_dir, check_dir) then return found_ts else return global_ts end end local path = util.path local function get_python_path(workspace) -- Use activated virtualenv. if vim.env.VIRTUAL_ENV then return path.join(vim.env.VIRTUAL_ENV, 'bin', 'python') end -- Find and use virtualenv in workspace directory. for _, pattern in ipairs({'*', '.*'}) do local match = vim.fn.glob(path.join(workspace, pattern, 'pyvenv.cfg')) if match ~= '' then return path.join(path.dirname(match), 'bin', 'python') end end -- Fallback to system Python. return exepath('python3') or exepath('python') or 'python' end local servers = { ts_ls = { init_options = { plugins = { { name = "@vue/typescript-plugin", location = base_path .. "/@vue/typescript-plugin", languages = { "javascript", "typescript", "vue" }, }, }, }, filetypes = { "javascript", "typescript", "vue", }, }, volar = { filetypes = { "javascript", "typescript", "vue", }, on_new_config = function(new_config, new_root_dir) new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir) end, }, cssls = {}, intelephense = { root_dir = function(pattern) ---@diagnostic disable-next-line: undefined-field local cwd = vim.loop.cwd() local root = util.root_pattern("composer.json")(pattern) -- prefer cwd if root is a descendant return util.path.is_descendant(cwd, root) and cwd or root end, init_options = { licenceKey = vim.fn.expand("$HOME/.local/share/nvim/intelephense-licence.txt"), }, settings = { intelephense = { format = { enable = true, sortUseStatements = false, }, }, }, }, gopls = { cmd = { "gopls" }, filetypes = { "go", "gomod", "gowork", "gotmpl" }, root_dir = util.root_pattern("go.work", "go.mod", ".git"), settings = { gopls = { completeUnimported = true, usePlaceholders = true, analyses = { unusedparams = true, }, }, }, }, lua_ls = { settings = { -- custom settings for lua Lua = { -- make the language server recognize "vim" global diagnostics = { globals = { "vim" }, }, workspace = { -- make language server aware of runtime files library = { [vim.fn.expand("$VIMRUNTIME/lua")] = true, [vim.fn.stdpath("config") .. "/lua"] = true, }, }, }, }, }, dartls = { cmd = { "dart", "language-server", "--protocol=lsp" }, }, rust_analyzer = { diagnostics = { enable = false, }, }, pyright = { before_init = function(_, config) config.settings.python.pythonpath = get_python_path(config.root_dir) end }, yamlls = { settings = { yaml = { keyOrdering = false, }, }, }, } require("mason").setup() local ensure_installed = vim.tbl_keys(servers or {}) vim.list_extend(ensure_installed, { "stylua", "prettier", "prettierd", "eslint", "eslint_d", "jsonlint", "markdownlint", "phpcbf", "phpcs", "golangci-lint", "hadolint", "gofumpt", "goimports", }) require("mason-tool-installer").setup({ ensure_installed = ensure_installed, run_on_start = false, }) require("mason-lspconfig").setup() for server_name, server in pairs(servers) do server.capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {}) require("lspconfig")[server_name].setup(server) end end, }