`:LspRestart eslint` results in 'Unable to find ESLint library' when using Yarn PnP (using lua/lspconfig/ with Nvim 0.11.2)
Description
(I'm using Neovim v0.11.2 + LazyVim + Mason pinned to v1. IIRC there are still some unresolved issues with the new vim.lsp ecosystem, so first, sorry if this issue doesn't belong here.)
lspconfig correctly adds yarn exec upon first start https://github.com/neovim/nvim-lspconfig/blob/036885e8e5456d3907626b634693234f628afef6/lua/lspconfig/configs/eslint.lua#L129:
> vim.lsp.get_clients({ name = 'eslint' })[1].config.cmd
< { "yarn", "exec", "vscode-eslint-language-server", "--stdio" }
> vim.lsp._enabled_configs
< {}
And I could confirm the command with ps aux.
However after executing :LspRestart eslint,
> vim.lsp.get_clients({ name = 'eslint' })[1].config.cmd
< { "yarn", "exec", "vscode-eslint-language-server", "--stdio" }
> vim.lsp._enabled_configs.eslint.resolved_config.cmd
< { "vscode-eslint-language-server", "--stdio" }
vim.lsp._enabled_configs somehow got populated with an eslint.resolved_config, where cmd didn't have the yarn exec prefix. I'd see an '[lspconfig] Unable to find ESLint library.' notification, and ps aux also said the vscode-eslint-language-server was executed with node directly.
I understand 'The configs in this repo are UNSUPPORTED and provided only as a starting point', but this might be some more generic issue with built-in LSP and config modifications in on_new_config?
I'm also aware of https://github.com/neovim/nvim-lspconfig/issues/3705 and https://github.com/neovim/neovim/issues/32287, but I'm not entirely sure if it's something that'll resolve this problem and whether there's anything we can do in the interim?
is this the same as https://github.com/neovim/nvim-lspconfig/issues/3858 ?
anything in nvim-lspconfig/lua/lspconfig/* is deprecated. so it's more useful to discussion the lsp/* case, which based on that issue has the same problem.
is this the same as #3858 ?
I saw #3858 too but I don't think it's the same issue. In #3858, they couldn't get eslint running at all without the tweaks they mentioned, while I only have issue restarting eslint. It also seems that their issue only happens with the new vim.lsp.config API.
I can use the config below and my playground project at https://github.com/Frederick888/playground/tree/eslint-yarn4 to reproduce both:
-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify('./.repro', ':p')
-- set stdpaths to use .repro
for _, name in ipairs({ 'config', 'data', 'state', 'cache' }) do
vim.env[('XDG_%s_HOME'):format(name:upper())] = root .. '/' .. name
end
-- bootstrap lazy
local lazypath = root .. '/plugins/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({ 'git', 'clone', '--filter=blob:none', 'https://github.com/folke/lazy.nvim.git', lazypath })
end
vim.opt.runtimepath:prepend(lazypath)
-- install plugins
local plugins = {
"folke/tokyonight.nvim",
-- add any other plugins here
"neovim/nvim-lspconfig"
}
require("lazy").setup(plugins, {
root = root .. "/plugins",
})
vim.cmd.colorscheme("tokyonight")
-- add anything else here
-- reproduce https://github.com/neovim/nvim-lspconfig/issues/3858 with:
-- vim.lsp.enable('eslint')
-- reproduce https://github.com/neovim/nvim-lspconfig/issues/3889 with:
require('lspconfig').eslint.setup({})
Clone the playground project, set up corepack, run yarn install, and finally nvim -u repro.lua packages/shared/src/index.ts.
I also did a bisect for my own issue, and e4d1c8bf9077ecf617ce18f27738658a7d76ac95 was the first bad commit. Perhaps it's not a good idea to use Neovim v0.11.2+ with the legacy API.
Perhaps it's not a good idea to use Neovim v0.11.2+ with the legacy API.
It should work just fine. But everything in lua/lspconfig/* will be deleted, so fixing any issues there is low-priority, though PR welcome.
I just spent a bit more time on this and realised actually both this and #3858 were caused by the fact that before_init cannot modify config.cmd, which is already part of the discussion at https://github.com/neovim/neovim/issues/32287 (code ref: https://github.com/neovim/neovim/blob/93925fe0208fcd640eb6c5f2822f994a427f3795/runtime/lua/vim/lsp/client.lua#L456-L466).
I could add a few hacky lines into that file and both issues would go away:
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index 1f88524..533ff6b 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -453,8 +453,11 @@ function Client.create(config)
end,
}
-- Start the RPC client.
+ if type(config.before_init) == 'function' then
+ config.before_init({}, config)
+ end
local config_cmd = config.cmd
if type(config_cmd) == 'function' then
self.rpc = config_cmd(dispatchers)
else
As per the discussion, the Yarn PnP detection should be made part of config.cmd using its function form. However that can't be easily done as it needs the root_dir in string, which is only resolved later through vim.lsp.start()'s FileType autocmd by calling the root_dir function in lsp/eslint.lua.
The best remedy I have right now is to always use cwd or something here:
diff --git a/lsp/eslint.lua b/lsp/eslint.lua
index 61c00e0..d925ba0 100644
--- a/lsp/eslint.lua
+++ b/lsp/eslint.lua
@@ -34,9 +34,21 @@
local util = require 'lspconfig.util'
local lsp = vim.lsp
return {
- cmd = { 'vscode-eslint-language-server', '--stdio' },
+ cmd = function(dispatchers)
+ local eslint_cmd = { 'vscode-eslint-language-server', '--stdio' }
+ local root_dir = vim.uv.cwd()
+
+ -- 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
+ eslint_cmd = { 'yarn', 'exec', unpack(eslint_cmd) }
+ end
+
+ return vim.lsp.rpc.start(eslint_cmd, dispatchers)
+ end,
filetypes = {
'javascript',
'javascriptreact',
'javascript.jsx',
@@ -146,16 +158,8 @@ return {
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)
I'm not sure if we should do this or wait for a potentially better option from https://github.com/neovim/neovim/issues/32287.
The best remedy I have right now is to always use cwd or something here:
Using CWD is fragile, but if the eslint LS requires a CLI arg then there is no other way to handle this. So, your patch LGTM, pr welcome.