-
Notifications
You must be signed in to change notification settings - Fork 34.3k
feat: add support for new LSP config API in Neovim 0.11+ #1475
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Do we really need backward compatibility with Neovim 0 10? I'd consider going with a lighter, happy-path solution. Since the project mainly targets newcomers and servers educational purposes, they'd likely prefer to avoid dealing with legacy approaches. |
I think that would be the right approach as well. The reason I intended to maintain backwards compatibility is that some parts of the code is still trying to maintain 0.10 like the |
There is also the problem new syntax not supporting all lsp configs. For example tailwindcss requires the old setup. Could be a good idea to delay this until most lsp configs migrate. |
|
Signed-off-by: Umut Sahin Onder <[email protected]>
In my opinion, we shouldn't bother with backwards compatibility since Kickstart is mostly aimed at beginners who will download the latest version of Neovim as per the instructions in the repo readme |
I have removed backwards compatibility and added useful comments for LSPs that still require the old setup |
This comment was marked as resolved.
This comment was marked as resolved.
I couldn't replicate the issue. I do not think it would be related to these changes as conform.nvim does not use an LSP. In any case If you could check your conform logs by using |
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Rory Hendrickson <[email protected]>
init.lua
Outdated
automatic_installation = false, | ||
handlers = { | ||
function(server_name) | ||
local server = servers[server_name] or {} | ||
-- This handles overriding only values explicitly passed | ||
-- by the server configuration above. Useful when disabling | ||
-- certain features of an LSP (for example, turning off formatting for ts_ls) | ||
server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {}) | ||
require('lspconfig')[server_name].setup(server) | ||
local config = servers[server_name] or {} | ||
vim.lsp.config(server_name, config) | ||
vim.lsp.enable(server_name) | ||
end, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mason-lspconfig.nvim v2.0.0 removes this now. It auto-enables installed LSPs if they're using the new vim.lsp.* API. See https://github.com/mason-org/mason-lspconfig.nvim/releases/tag/v2.0.0
init.lua
Outdated
for server, config in pairs(servers) do | ||
-- This handles overriding only values explicitly passed | ||
-- by the server configuration above. Useful when disabling | ||
-- certain features of an LSP (for example, turning off formatting for ts_ls) | ||
config.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {}) | ||
vim.lsp.config(name, config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the original hunk of the patch is relevant (and should be used?) now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I don't know how to mention lines, but shouldn't it be vim.lsp.config(server, config)
? As well as vim.lsp.enable(server)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that was fixed in a later commit in this PR, I was quoting from an earlier one.
AFAIK
I've been updating my old neovim configs with the latest kickstart but the LSP settings weren't reflected in |
If we were to move LSP configs to their own file, I don't know how mason-tool-installer would work without the servers table maybe by iterating over file names? In your config I see that you still have the servers table. If It is still gonna be preset wouldn't be better to use vim.lsp.config with a loop (like my first hunk) rather than having 2 separate places for LSP servers? |
As mentioned in previous conversations, Mason v2 has started introducing a significant delay during startup. For now, I’ve pinned the Mason version to avoid this issue. From my testing, the problem appears to be related to mason-tool-installer; without it, I don’t experience any delays. It would be helpful to hear from someone with more insight into this before proceeding further with Mason v2. |
My personal temporary solution is to set |
After the recent updates mason-tool-installer seems to not have this issue anymore. I will commit a change for Mason V2 |
-- Installed LSPs are configured and enabled automatically with mason-lspconfig | ||
-- The loop below is for overriding the default configuration of LSPs with the ones in the servers table | ||
for server_name, config in pairs(servers) do | ||
vim.lsp.config(server_name, config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, before all the servers work, should we just use require("lspconfig").server_name.setup{}
? since that currently works for everything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DanWlker - In my testing, the lsp server configs do not get merged with the defaults from lspconfig
:
for server_name, server_config in pairs(servers) do
require("lspconfig")[server_name].setup(server_config)
end
Unless I am missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently I'm using the handlers in mason-lspconfig like this: handlers = {
function(server_name)
if server_name == "standardrb" or server_name == "rubocop" then
local personal_path = vim.fn.expand("~") .. "/programming/me"
local current_dir = vim.fn.getcwd()
local in_personal_project = string.find(current_dir, "^" .. personal_path) ~= nil
if
(server_name == "standardrb" and not in_personal_project)
or (server_name == "rubocop" and in_personal_project)
then
return
end
end
local server = servers[server_name] or {}
server.capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {})
require("lspconfig")[server_name].setup(server)
end,
}, The purpose is to load |
Mason-lspconfig enables all installed LSPs by default, You can disable individual LSPs with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe you should only enable lsps that were installed using ensure_installed
.
This way you will mirror the original behaviour.
i.e.
---@type MasonLspconfigSettings
---@diagnostic disable-next-line: missing-fields
require('mason-lspconfig').setup {
automatic_enable = vim.tbl_keys(servers or {}),
}
---@type MasonLspconfigSettings | ||
---@diagnostic disable-next-line: missing-fields | ||
require('mason-lspconfig').setup { | ||
automatic_enable = vim.tbl_keys(servers or {}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into the source code of mason-lspconfig. When the keys of servers
are passed as a table to automatic_enable
, it causes mason-lspconfig to ignore any LSPs that are installed via Mason but not explicitly listed in servers
.
In the mason-lspconfig.nvim\doc\mason-lspconfig.txtmason-lspconfig.nvim\doc\mason-lspconfig.txt
document, it mentions that doing this will only start certain servers:
-- To only enable certain servers to be automatically enabled:
-- ```lua
-- automatic_enable = {
-- "lua_ls",
-- "vimls"
-- }
-- ```
In the setup
that in the mason-lspconfig.nvim\lua\mason-lspconfig\init.lua
,if automatic_enable
is not set to false, both enable_all
and init
will be executed:
function M.setup(config)
if config then
settings.set(config)
end
--- ...
local registry = require "mason-registry"
registry.refresh(vim.schedule_wrap(function(success, updated_registries)
if success and #updated_registries > 0 and settings.current.automatic_enable ~= false then
require("mason-lspconfig.features.automatic_enable").enable_all()
end
end))
if settings.current.automatic_enable ~= false then
require("mason-lspconfig.features.automatic_enable").init()
end
-- ...
end
In mason-lspconfig\features\automatic_enable.lua
, The logic for enabling servers in init
and enable_all
is the same:
return {
init = function()
enabled_servers = {}
_.each(enable_server, registry.get_installed_package_names())
-- We deregister the event handler primarily for testing purposes where .setup() is called multiple times in the
-- same instance.
registry:off("package:install:success", enable_server_scheduled)
registry:on("package:install:success", enable_server_scheduled)
end,
enable_all = function()
_.each(enable_server, registry.get_installed_package_names())
end,
}
However, in enable_server
, if automatic_enable
is a table and an LSP installed by Mason is not listed in automatic_enable
, it will not execute vim.lsp.config
and vim.lsp.enable
.
local function enable_server(mason_pkg)
-- ...
local lspconfig_name = mappings.get_mason_map().package_to_lspconfig[mason_pkg]
-- ...
local automatic_enable = settings.current.automatic_enable
if type(automatic_enable) == "table" then
local exclude = automatic_enable.exclude
if exclude then
if _.any(_.equals(lspconfig_name), exclude) then
-- This server is explicitly excluded.
return
end
else
if not _.any(_.equals(lspconfig_name), automatic_enable) then
-- This server is not explicitly enabled.
return
end
end
elseif automatic_enable == false then
return
end
-- ...
vim.lsp.enable(lspconfig_name)
-- ...
end
In other words, even if I’ve already installed the LSPs via Mason, I still have to list all the LSPs I use in servers
or in or {}
. Isn't that kind of ... not very "lazy"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems you are right about automatic_enable
.
If set to true it will enable all the LSPs, but when given a table it will only enable those LSPs.
After looking into it more, enabling all the LSPs also seems to be the old behaviour mason.
Despite that , I still prefer declarativly specifying all the LSPs in the config file, instead of downloading them using the mason interface.
This way I can commit those LSPs and have a reproducible setup.
This is the same reason I commit the lazy-lock.json
file.
Though I guess this is a matter of taste, and could break setups for people that were used to the old way, so I'm ok with both options :)
@umutondersu @SetsuikiHyoryu what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I prefer the more “lazy” approach, but I tend to follow the method recommended by the Neovim official because I feel it’s more native. That means the operational habits won’t differ too much even when I have to work in a barebones environment. However, I’m not entirely sure what the official philosophy is on this. Judging from the existence of the vim.lsp.enable
interface, it seems that the official intent is for LSP to be explicitly enabled.
Perhaps, if Mason provides an interface to retrieve the list of installed packages, a compromise could be to merge that list into the loop that calls vim.lsp.enable
(the table passed to automatic_enable
).
Sorry, it seems that
_.each(enable_server, registry.get_installed_package_names())
is already configuring only the installed packages. Setting automatic_enable = true
doesn't appear to enable LSPs that haven't been installed.
Summary