diff --git a/nvim/lsp/eslint.lua b/nvim/lsp/eslint.lua new file mode 100644 index 0000000..8133a96 --- /dev/null +++ b/nvim/lsp/eslint.lua @@ -0,0 +1,153 @@ +local function root_markers_with_field(root_files, new_names, field, fname) + local path = vim.fn.fnamemodify(fname, ":h") + local found = vim.fs.find(new_names, { path = path, upward = true }) + + for _, f in ipairs(found or {}) do + -- Match the given `field`. + for line in io.lines(f) do + if line:find(field) then + root_files[#root_files + 1] = vim.fs.basename(f) + break + end + end + end + + return root_files +end + +local function insert_package_json(root_files, field, fname) + return root_markers_with_field(root_files, { "package.json", "package.json5" }, field, fname) +end + +return { + cmd = { "vscode-eslint-language-server", "--stdio" }, + filetypes = { + "javascript", + "javascriptreact", + "javascript.jsx", + "typescript", + "typescriptreact", + "typescript.tsx", + "vue", + "svelte", + "astro", + "htmlangular", + }, + root_dir = function(bufnr, on_dir) + local root_file_patterns = { + ".eslintrc", + ".eslintrc.js", + ".eslintrc.cjs", + ".eslintrc.yaml", + ".eslintrc.yml", + ".eslintrc.json", + "eslint.config.js", + "eslint.config.mjs", + "eslint.config.cjs", + "eslint.config.ts", + "eslint.config.mts", + "eslint.config.cts", + } + + local fname = vim.api.nvim_buf_get_name(bufnr) + root_file_patterns = insert_package_json(root_file_patterns, "eslintConfig", fname) + on_dir(vim.fs.dirname(vim.fs.find(root_file_patterns, { path = fname, upward = true })[1])) + end, + workspace_required = true, + settings = { + validate = "on", + packageManager = nil, + useESLintClass = false, + experimental = { + useFlatConfig = false, + }, + codeActionOnSave = { + enable = false, + mode = "all", + }, + format = true, + quiet = false, + onIgnoredFiles = "off", + rulesCustomizations = {}, + run = "onType", + problems = { + shortenToSingleLine = false, + }, + -- nodePath configures the directory in which the eslint server should start its node_modules resolution. + -- This path is relative to the workspace folder (root dir) of the server instance. + nodePath = "", + -- use the workspace folder location or the file location (if no workspace folder is open) as the working directory + workingDirectory = { mode = "location" }, + codeAction = { + disableRuleComment = { + enable = true, + location = "separateLine", + }, + showDocumentation = { + enable = true, + }, + }, + }, + before_init = function(_, config) + -- The "workspaceFolder" is a VSCode concept. It limits how far the + -- server will traverse the file system when locating the ESLint config + -- file (e.g., .eslintrc). + local root_dir = config.root_dir + + if root_dir then + config.settings = config.settings or {} + config.settings.workspaceFolder = { + uri = root_dir, + name = vim.fn.fnamemodify(root_dir, ":t"), + } + + -- Support flat config + local flat_config_files = { + "eslint.config.js", + "eslint.config.mjs", + "eslint.config.cjs", + "eslint.config.ts", + "eslint.config.mts", + "eslint.config.cts", + } + + for _, file in ipairs(flat_config_files) do + if vim.fn.filereadable(root_dir .. "/" .. file) == 1 then + config.settings.experimental = config.settings.experimental or {} + config.settings.experimental.useFlatConfig = true + break + end + end + + -- Support Yarn2 (PnP) projects + local pnp_cjs = root_dir .. "/.pnp.cjs" + local pnp_js = root_dir .. "/.pnp.js" + if vim.uv.fs_stat(pnp_cjs) or vim.uv.fs_stat(pnp_js) then + local cmd = config.cmd + config.cmd = vim.list_extend({ "yarn", "exec" }, cmd) + end + end + end, + handlers = { + ["eslint/openDoc"] = function(_, result) + if result then + vim.ui.open(result.url) + end + return {} + end, + ["eslint/confirmESLintExecution"] = function(_, result) + if not result then + return + end + return 4 -- approved + end, + ["eslint/probeFailed"] = function() + vim.notify("[lspconfig] ESLint probe failed.", vim.log.levels.WARN) + return {} + end, + ["eslint/noLibrary"] = function() + vim.notify("[lspconfig] Unable to find ESLint library.", vim.log.levels.WARN) + return {} + end, + }, +} diff --git a/nvim/lsp/tailwindcss-language-server.lua b/nvim/lsp/tailwindcss-language-server.lua index 7a7ab90..f09eafd 100644 --- a/nvim/lsp/tailwindcss-language-server.lua +++ b/nvim/lsp/tailwindcss-language-server.lua @@ -9,7 +9,11 @@ return { "javascript", "javascriptreact", "typescript", - "typescriptreact" + "typescriptreact", + "vue", + "svelte", + "astro", + "htmlangular", }, root_markers = { "tailwind.config.js", diff --git a/nvim/lsp/typescript-language-server.lua b/nvim/lsp/typescript-language-server.lua index d142e7b..dc8a1c9 100644 --- a/nvim/lsp/typescript-language-server.lua +++ b/nvim/lsp/typescript-language-server.lua @@ -8,6 +8,10 @@ return { "typescript", "typescriptreact", "typescript.tsx", + "vue", + "svelte", + "astro", + "htmlangular", }, root_markers = { "tsconfig.json",