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() -- import lspconfig plugin 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 } -- set keybinds opts.desc = "Show LSP references" keymap.set("n", "gr", "Telescope lsp_references", opts) -- show definition, references opts.desc = "Go to declaration" keymap.set("n", "gD", vim.lsp.buf.declaration, opts) -- go to declaration opts.desc = "Show LSP definitions" keymap.set("n", "gd", "Telescope lsp_definitions", opts) -- show lsp definitions opts.desc = "Show LSP implementations" keymap.set("n", "gi", "Telescope lsp_implementations", opts) -- show lsp implementations opts.desc = "Show LSP type definitions" keymap.set("n", "gt", "Telescope lsp_type_definitions", opts) -- show lsp type definitions opts.desc = "See available code actions" keymap.set({ "n", "v" }, "ca", vim.lsp.buf.code_action, opts) -- see available code actions, in visual mode will apply to selection opts.desc = "Smart rename" keymap.set("n", "rn", vim.lsp.buf.rename, opts) -- smart rename opts.desc = "Show buffer diagnostics" keymap.set("n", "D", "Telescope diagnostics bufnr=0", opts) -- show diagnostics for file opts.desc = "Show line diagnostics" keymap.set("n", "d", vim.diagnostic.open_float, opts) -- show diagnostics for line opts.desc = "Go to previous diagnostic" keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) -- jump to previous diagnostic in buffer opts.desc = "Go to next diagnostic" keymap.set("n", "]d", vim.diagnostic.goto_next, opts) -- jump to next diagnostic in buffer 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) -- show documentation for what is under cursor opts.desc = "Show documentation for what is under cursor" keymap.set("n", "K", vim.lsp.buf.hover, opts) -- show documentation for what is under cursor 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 servers = { tsserver = { 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, }, }, } 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, }