aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lsp/biome.lua40
-rw-r--r--lsp/eslint.lua92
-rw-r--r--lsp/svelte.lua2
-rw-r--r--lsp/ts_ls.lua36
-rw-r--r--lsp/tsgo.lua36
-rw-r--r--lsp/vtsls.lua35
6 files changed, 200 insertions, 41 deletions
diff --git a/lsp/biome.lua b/lsp/biome.lua
index d58ae46f..5adc379a 100644
--- a/lsp/biome.lua
+++ b/lsp/biome.lua
@@ -6,6 +6,10 @@
--- ```sh
--- npm install [-g] @biomejs/biome
--- ```
+---
+--- ### Monorepo support
+---
+--- `biome` supports monorepos by default. It will automatically find the `biome.json` corresponding to the package you are working on, as described in the [documentation](https://biomejs.dev/guides/big-projects/#monorepo). This works without the need of spawning multiple instances of `biome`, saving memory.
local util = require 'lspconfig.util'
@@ -34,13 +38,33 @@ return {
'vue',
},
workspace_required = true,
- root_dir = function(_, on_dir)
- -- To support monorepos, biome recommends starting the search for the root from cwd
- -- https://biomejs.dev/guides/big-projects/#use-multiple-configuration-files
- local cwd = vim.fn.getcwd()
- local root_files = { 'biome.json', 'biome.jsonc' }
- root_files = util.insert_package_json(root_files, 'biome', cwd)
- local root_dir = vim.fs.dirname(vim.fs.find(root_files, { path = cwd, upward = true })[1])
- on_dir(root_dir)
+ root_dir = function(bufnr, on_dir)
+ -- The project root is where the LSP can be started from
+ -- As stated in the documentation above, this LSP supports monorepos and simple projects.
+ -- We select then from the project root, which is identified by the presence of a package
+ -- manager lock file.
+ local project_root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb' }
+ local project_root = vim.fs.root(bufnr, project_root_markers)
+ if not project_root then
+ return nil
+ end
+
+ -- We know that the buffer is using Biome if it has a config file
+ -- in its directory tree.
+ local filename = vim.api.nvim_buf_get_name(bufnr)
+ local biome_config_files = { 'biome.json', 'biome.jsonc' }
+ biome_config_files = util.insert_package_json(biome_config_files, 'biome', filename)
+ local is_buffer_using_biome = vim.fs.find(biome_config_files, {
+ path = filename,
+ type = 'file',
+ limit = 1,
+ upward = true,
+ stop = vim.fs.dirname(project_root),
+ })[1]
+ if not is_buffer_using_biome then
+ return nil
+ end
+
+ on_dir(project_root)
end,
}
diff --git a/lsp/eslint.lua b/lsp/eslint.lua
index 183343b2..30c7eb4d 100644
--- a/lsp/eslint.lua
+++ b/lsp/eslint.lua
@@ -30,10 +30,33 @@
--- Messages handled in lspconfig: `eslint/openDoc`, `eslint/confirmESLintExecution`, `eslint/probeFailed`, `eslint/noLibrary`
---
--- Additional messages you can handle: `eslint/noConfig`
+---
+--- ### Monorepo support
+---
+--- `vscode-eslint-language-server` supports monorepos by default. It will automatically find the config file corresponding to the package you are working on. You can use different configs in different packages.
+--- This works without the need of spawning multiple instances of `vscode-eslint-language-server`.
+--- You can use a different version of ESLint in each package, but it is recommended to use the same version of ESLint in all packages. The location of the ESLint binary will be determined automatically.
+---
+--- /!\ When using flat config files, you need to use them across all your packages in your monorepo, as it's a global setting for the server.
local util = require 'lspconfig.util'
local lsp = vim.lsp
+local eslint_config_files = {
+ '.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',
+}
+
return {
cmd = { 'vscode-eslint-language-server', '--stdio' },
filetypes = {
@@ -62,26 +85,37 @@ return {
}, nil, bufnr)
end, {})
end,
- -- https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats
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',
- }
+ -- The project root is where the LSP can be started from
+ -- As stated in the documentation above, this LSP supports monorepos and simple projects.
+ -- We select then from the project root, which is identified by the presence of a package
+ -- manager lock file.
+ local project_root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb' }
+ local project_root = vim.fs.root(bufnr, project_root_markers)
+ if not project_root then
+ return nil
+ end
+
+ -- We know that the buffer is using ESLint if it has a config file
+ -- in its directory tree.
+ --
+ -- Eslint used to support package.json files as config files, but it doesn't anymore.
+ -- We keep this for backward compatibility.
+ local filename = vim.api.nvim_buf_get_name(bufnr)
+ local eslint_config_files_with_package_json =
+ util.insert_package_json(eslint_config_files, 'eslintConfig', filename)
+ local is_buffer_using_eslint = vim.fs.find(eslint_config_files_with_package_json, {
+ path = filename,
+ type = 'file',
+ limit = 1,
+ upward = true,
+ stop = vim.fs.dirname(project_root),
+ })[1]
+ if not is_buffer_using_eslint then
+ return nil
+ end
- local fname = vim.api.nvim_buf_get_name(bufnr)
- root_file_patterns = util.insert_package_json(root_file_patterns, 'eslintConfig', fname)
- on_dir(vim.fs.dirname(vim.fs.find(root_file_patterns, { path = fname, upward = true })[1]))
+ on_dir(project_root)
end,
-- Refer to https://github.com/Microsoft/vscode-eslint#settings-options for documentation.
settings = {
@@ -107,7 +141,7 @@ return {
-- 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' },
+ workingDirectory = { mode = 'auto' },
codeAction = {
disableRuleComment = {
enable = true,
@@ -131,18 +165,18 @@ return {
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',
- }
+ -- Support flat config files
+ -- They contain 'config' in the file name
+ local flat_config_files = vim.tbl_filter(function(file)
+ return file:match('config')
+ end, eslint_config_files)
for _, file in ipairs(flat_config_files) do
- if vim.fn.filereadable(root_dir .. '/' .. file) == 1 then
+ local found_files = vim.fs.find(function(name, path)
+ return name == file and not path:match('[/\\]node_modules[/\\]')
+ end, { path = root_dir, type = 'file', limit = 1 })
+
+ if #found_files > 0 then
config.settings.experimental = config.settings.experimental or {}
config.settings.experimental.useFlatConfig = true
break
diff --git a/lsp/svelte.lua b/lsp/svelte.lua
index f18baf1d..abb09e2b 100644
--- a/lsp/svelte.lua
+++ b/lsp/svelte.lua
@@ -13,7 +13,7 @@ return {
cmd = { 'svelteserver', '--stdio' },
filetypes = { 'svelte' },
root_dir = function(bufnr, on_dir)
- local root_files = { 'package.json', '.git' }
+ local root_files = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb' }
local fname = vim.api.nvim_buf_get_name(bufnr)
-- Svelte LSP only supports file:// schema. https://github.com/sveltejs/language-tools/issues/2777
if vim.uv.fs_stat(fname) ~= nil then
diff --git a/lsp/ts_ls.lua b/lsp/ts_ls.lua
index e3cc99bc..4626adf0 100644
--- a/lsp/ts_ls.lua
+++ b/lsp/ts_ls.lua
@@ -32,6 +32,14 @@
--- Use the `:LspTypescriptSourceAction` command to see "whole file" ("source") code-actions such as:
--- - organize imports
--- - remove unused code
+---
+--- ### Monorepo support
+---
+--- `ts_ls` supports monorepos by default. It will automatically find the `tsconfig.json` or `jsconfig.json` corresponding to the package you are working on.
+--- This works without the need of spawning multiple instances of `ts_ls`, saving memory.
+---
+--- It is recommended to use the same version of TypeScript in all packages, and therefore have it available in your workspace root. The location of the TypeScript binary will be determined automatically, but only once.
+---
return {
init_options = { hostInfo = 'neovim' },
@@ -44,7 +52,33 @@ return {
'typescriptreact',
'typescript.tsx',
},
- root_markers = { 'tsconfig.json', 'jsconfig.json', 'package.json', '.git' },
+ root_dir = function(bufnr, on_dir)
+ -- The project root is where the LSP can be started from
+ -- As stated in the documentation above, this LSP supports monorepos and simple projects.
+ -- We select then from the project root, which is identified by the presence of a package
+ -- manager lock file.
+ local project_root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb' }
+ local project_root = vim.fs.root(bufnr, project_root_markers)
+ if not project_root then
+ return nil
+ end
+
+ -- We know that the buffer is using Typescript if it has a config file
+ -- in its directory tree.
+ local ts_config_files = { 'tsconfig.json', 'jsconfig.json' }
+ local is_buffer_using_typescript = vim.fs.find(ts_config_files, {
+ path = vim.api.nvim_buf_get_name(bufnr),
+ type = 'file',
+ limit = 1,
+ upward = true,
+ stop = vim.fs.dirname(project_root),
+ })[1]
+ if not is_buffer_using_typescript then
+ return nil
+ end
+
+ on_dir(project_root)
+ end,
handlers = {
-- handle rename request for certain code actions like extracting functions / types
['_typescript.rename'] = function(_, result, ctx)
diff --git a/lsp/tsgo.lua b/lsp/tsgo.lua
index 14774487..a644581f 100644
--- a/lsp/tsgo.lua
+++ b/lsp/tsgo.lua
@@ -5,6 +5,14 @@
--- `typescript-go` is experimental port of the TypeScript compiler (tsc) and language server (tsserver) to the Go programming language.
---
--- `tsgo` can be installed via npm `npm install @typescript/native-preview`.
+---
+--- ### Monorepo support
+---
+--- `tsgo` supports monorepos by default. It will automatically find the `tsconfig.json` or `jsconfig.json` corresponding to the package you are working on.
+--- This works without the need of spawning multiple instances of `tsgo`, saving memory.
+---
+--- It is recommended to use the same version of TypeScript in all packages, and therefore have it available in your workspace root. The location of the TypeScript binary will be determined automatically, but only once.
+---
return {
cmd = { 'tsgo', '--lsp', '--stdio' },
filetypes = {
@@ -15,5 +23,31 @@ return {
'typescriptreact',
'typescript.tsx',
},
- root_markers = { 'tsconfig.json', 'jsconfig.json', 'package.json', '.git' },
+ root_dir = function(bufnr, on_dir)
+ -- The project root is where the LSP can be started from
+ -- As stated in the documentation above, this LSP supports monorepos and simple projects.
+ -- We select then from the project root, which is identified by the presence of a package
+ -- manager lock file.
+ local project_root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb' }
+ local project_root = vim.fs.root(bufnr, project_root_markers)
+ if not project_root then
+ return nil
+ end
+
+ -- We know that the buffer is using Typescript if it has a config file
+ -- in its directory tree.
+ local ts_config_files = { 'tsconfig.json', 'jsconfig.json' }
+ local is_buffer_using_typescript = vim.fs.find(ts_config_files, {
+ path = vim.api.nvim_buf_get_name(bufnr),
+ type = 'file',
+ limit = 1,
+ upward = true,
+ stop = vim.fs.dirname(project_root),
+ })[1]
+ if not is_buffer_using_typescript then
+ return nil
+ end
+
+ on_dir(project_root)
+ end,
}
diff --git a/lsp/vtsls.lua b/lsp/vtsls.lua
index 7b8c0b30..226fc5c0 100644
--- a/lsp/vtsls.lua
+++ b/lsp/vtsls.lua
@@ -57,6 +57,13 @@
--- ```
---
--- See `vue_ls` section and https://github.com/vuejs/language-tools/wiki/Neovim for more information.
+---
+--- ### Monorepo support
+---
+--- `vtsls` supports monorepos by default. It will automatically find the `tsconfig.json` or `jsconfig.json` corresponding to the package you are working on.
+--- This works without the need of spawning multiple instances of `vtsls`, saving memory.
+---
+--- It is recommended to use the same version of TypeScript in all packages, and therefore have it available in your workspace root. The location of the TypeScript binary will be determined automatically, but only once.
return {
cmd = { 'vtsls', '--stdio' },
@@ -68,5 +75,31 @@ return {
'typescriptreact',
'typescript.tsx',
},
- root_markers = { 'tsconfig.json', 'package.json', 'jsconfig.json', '.git' },
+ root_dir = function(bufnr, on_dir)
+ -- The project root is where the LSP can be started from
+ -- As stated in the documentation above, this LSP supports monorepos and simple projects.
+ -- We select then from the project root, which is identified by the presence of a package
+ -- manager lock file.
+ local project_root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb' }
+ local project_root = vim.fs.root(bufnr, project_root_markers)
+ if not project_root then
+ return nil
+ end
+
+ -- We know that the buffer is using Typescript if it has a config file
+ -- in its directory tree.
+ local ts_config_files = { 'tsconfig.json', 'jsconfig.json' }
+ local is_buffer_using_typescript = vim.fs.find(ts_config_files, {
+ path = vim.api.nvim_buf_get_name(bufnr),
+ type = 'file',
+ limit = 1,
+ upward = true,
+ stop = vim.fs.dirname(project_root),
+ })[1]
+ if not is_buffer_using_typescript then
+ return nil
+ end
+
+ on_dir(project_root)
+ end,
}