aboutsummaryrefslogtreecommitdiffstats
path: root/lua
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2024-11-24 06:28:19 -0800
committerGitHub <noreply@github.com>2024-11-24 06:28:19 -0800
commitdafd61d6533bd90ecf6e2a3a972298fdddc74d82 (patch)
treeb67fb762283f9137237b226e1ffe353b904002a2 /lua
parentdocs: update configs.md (diff)
parentfeat: add silent on error option (diff)
downloadnvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.tar
nvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.tar.gz
nvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.tar.bz2
nvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.tar.lz
nvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.tar.xz
nvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.tar.zst
nvim-lspconfig-dafd61d6533bd90ecf6e2a3a972298fdddc74d82.zip
Merge #3450 from MariaSolOs/start
refactor: use vim.lsp.start instead of vim.lsp.start_client
Diffstat (limited to 'lua')
-rw-r--r--lua/lspconfig/configs.lua5
-rw-r--r--lua/lspconfig/manager.lua175
2 files changed, 59 insertions, 121 deletions
diff --git a/lua/lspconfig/configs.lua b/lua/lspconfig/configs.lua
index 77d07862..2a19991f 100644
--- a/lua/lspconfig/configs.lua
+++ b/lua/lspconfig/configs.lua
@@ -8,6 +8,7 @@ local configs = {}
--- @class lspconfig.Config : vim.lsp.ClientConfig
--- @field enabled? boolean
--- @field single_file_support? boolean
+--- @field silent? boolean
--- @field filetypes? string[]
--- @field filetype? string
--- @field on_new_config? fun(new_config: lspconfig.Config?, new_root_dir: string)
@@ -105,7 +106,7 @@ function configs.__newindex(t, config_name, config_def)
api.nvim_create_autocmd(event_conf.event, {
pattern = event_conf.pattern or '*',
callback = function(opt)
- M.manager:try_add(opt.buf)
+ M.manager:try_add(opt.buf, nil, config.silent)
end,
group = lsp_group,
desc = string.format(
@@ -176,7 +177,7 @@ function configs.__newindex(t, config_name, config_def)
return
end
local pseudo_root = #bufname == 0 and pwd or util.path.dirname(util.path.sanitize(bufname))
- M.manager:add(pseudo_root, true, bufnr)
+ M.manager:add(pseudo_root, true, bufnr, config.silent)
end
end)
end
diff --git a/lua/lspconfig/manager.lua b/lua/lspconfig/manager.lua
index 7d6fb88c..d5db2833 100644
--- a/lua/lspconfig/manager.lua
+++ b/lua/lspconfig/manager.lua
@@ -8,7 +8,7 @@ local util = require 'lspconfig.util'
---@param client vim.lsp.Client
---@param root_dir string
---@return boolean
-local function check_in_workspace(client, root_dir)
+local function is_dir_in_workspace_folders(client, root_dir)
if not client.workspace_folders then
return false
end
@@ -23,7 +23,7 @@ local function check_in_workspace(client, root_dir)
end
--- @class lspconfig.Manager
---- @field _clients table<string,integer[]>
+--- @field _clients table<string,table<string, vim.lsp.Client>> root dir -> (client name -> client)
--- @field config lspconfig.Config
--- @field make_config fun(root_dir: string): lspconfig.Config
local M = {}
@@ -42,66 +42,42 @@ function M.new(config, make_config)
end
--- @private
---- @param clients table<string,integer[]>
---- @param root_dir string
---- @param client_name string
---- @return vim.lsp.Client?
-local function get_client(clients, root_dir, client_name)
- if vim.tbl_isempty(clients) then
- return
- end
-
- if clients[root_dir] then
- for _, id in pairs(clients[root_dir]) do
- local client = lsp.get_client_by_id(id)
- if client and client.name == client_name then
- return client
- end
- end
- end
-
- for _, ids in pairs(clients) do
- for _, id in ipairs(ids) do
- local client = lsp.get_client_by_id(id)
- if client and client.name == client_name then
- return client
- end
- end
- end
-end
-
---- @private
---- @param bufnr integer
--- @param root string
---- @param client_id integer
-function M:_attach_and_cache(bufnr, root, client_id)
+--- @param client vim.lsp.Client
+function M:_cache_client(root, client)
local clients = self._clients
- lsp.buf_attach_client(bufnr, client_id)
if not clients[root] then
clients[root] = {}
end
- if not vim.tbl_contains(clients[root], client_id) then
- clients[root][#clients[root] + 1] = client_id
+ if not clients[root][client.name] then
+ clients[root][client.name] = client
end
end
--- @private
---- @param bufnr integer
--- @param root_dir string
--- @param client vim.lsp.Client
-function M:_register_workspace_folders(bufnr, root_dir, client)
+function M:_notify_workspace_folder_added(root_dir, client)
+ if is_dir_in_workspace_folders(client, root_dir) then
+ return
+ end
+
+ local supported = vim.tbl_get(client, 'server_capabilities', 'workspace', 'workspaceFolders', 'supported')
+ if not supported then
+ return
+ end
+
local params = {
event = {
added = { { uri = vim.uri_from_fname(root_dir), name = root_dir } },
removed = {},
},
}
- client.rpc.notify('workspace/didChangeWorkspaceFolders', params)
+ client.rpc.notify(lsp.protocol.Methods.workspace_didChangeWorkspaceFolders, params)
if not client.workspace_folders then
client.workspace_folders = {}
end
client.workspace_folders[#client.workspace_folders + 1] = params.event.added[1]
- self:_attach_and_cache(bufnr, root_dir, client.id)
end
--- @private
@@ -109,7 +85,8 @@ end
--- @param new_config lspconfig.Config
--- @param root_dir string
--- @param single_file boolean
-function M:_start_new_client(bufnr, new_config, root_dir, single_file)
+--- @param silent boolean
+function M:_start_client(bufnr, new_config, root_dir, single_file, silent)
-- do nothing if the client is not enabled
if new_config.enabled == false then
return
@@ -125,13 +102,14 @@ function M:_start_new_client(bufnr, new_config, root_dir, single_file)
return
end
- local clients = self._clients
+ new_config.on_init = util.add_hook_before(new_config.on_init, function(client)
+ self:_notify_workspace_folder_added(root_dir, client)
+ end)
new_config.on_exit = util.add_hook_before(new_config.on_exit, function()
- for index, id in pairs(clients[root_dir]) do
- local exist = assert(lsp.get_client_by_id(id))
- if exist.name == new_config.name then
- table.remove(clients[root_dir], index)
+ for name in pairs(self._clients[root_dir]) do
+ if name == new_config.name then
+ self._clients[root_dir][name] = nil
end
end
end)
@@ -150,88 +128,46 @@ function M:_start_new_client(bufnr, new_config, root_dir, single_file)
new_config.workspace_folders = nil
end
- -- TODO: Replace lsp.start_client with lsp.start
- local client_id, err = lsp.start_client(new_config)
- if not client_id then
- if err then
- vim.notify(err, vim.log.levels.WARN)
- end
- return
- end
- self:_attach_and_cache(bufnr, root_dir, client_id)
-end
+ local client_id = lsp.start(new_config, {
+ bufnr = bufnr,
+ silent = silent,
+ reuse_client = function(existing_client)
+ if (self._clients[root_dir] or {})[existing_client.name] then
+ self:_notify_workspace_folder_added(root_dir, existing_client)
+ return true
+ end
---- @private
---- @param bufnr integer
---- @param new_config lspconfig.Config
---- @param root_dir string
---- @param client vim.lsp.Client
---- @param single_file boolean
-function M:_attach_or_spawn(bufnr, new_config, root_dir, client, single_file)
- if check_in_workspace(client, root_dir) then
- return self:_attach_and_cache(bufnr, root_dir, client.id)
- end
+ for _, dir_clients in pairs(self._clients) do
+ if dir_clients[existing_client.name] then
+ self:_notify_workspace_folder_added(root_dir, existing_client)
+ return true
+ end
+ end
- local supported = vim.tbl_get(client, 'server_capabilities', 'workspace', 'workspaceFolders', 'supported')
- if supported then
- return self:_register_workspace_folders(bufnr, root_dir, client)
+ return false
+ end,
+ })
+ if client_id then
+ self:_cache_client(root_dir, assert(lsp.get_client_by_id(client_id)))
end
- self:_start_new_client(bufnr, new_config, root_dir, single_file)
-end
-
---- @private
---- @param bufnr integer
---- @param new_config lspconfig.Config
---- @param root_dir string
---- @param client vim.lsp.Client
---- @param single_file boolean
-function M:_attach_after_client_initialized(bufnr, new_config, root_dir, client, single_file)
- local timer = assert(uv.new_timer())
- timer:start(
- 0,
- 10,
- vim.schedule_wrap(function()
- if client.initialized and client.server_capabilities and not timer:is_closing() then
- self:_attach_or_spawn(bufnr, new_config, root_dir, client, single_file)
- timer:stop()
- timer:close()
- end
- end)
- )
end
---@param root_dir string
---@param single_file boolean
---@param bufnr integer
-function M:add(root_dir, single_file, bufnr)
+---@param silent boolean
+function M:add(root_dir, single_file, bufnr, silent)
root_dir = util.path.sanitize(root_dir)
local new_config = self.make_config(root_dir)
- local client = get_client(self._clients, root_dir, new_config.name)
-
- if not client then
- return self:_start_new_client(bufnr, new_config, root_dir, single_file)
- end
-
- if self._clients[root_dir] or single_file then
- lsp.buf_attach_client(bufnr, client.id)
- return
- end
-
- -- make sure neovim had exchanged capabilities from language server
- -- it's useful to check server support workspaceFolders or not
- if client.initialized and client.server_capabilities then
- self:_attach_or_spawn(bufnr, new_config, root_dir, client, single_file)
- else
- self:_attach_after_client_initialized(bufnr, new_config, root_dir, client, single_file)
- end
+ self:_start_client(bufnr, new_config, root_dir, single_file, silent)
end
--- @return vim.lsp.Client[]
function M:clients()
local res = {}
- for _, client_ids in pairs(self._clients) do
- for _, id in ipairs(client_ids) do
- res[#res + 1] = lsp.get_client_by_id(id)
+ for _, dir_clients in pairs(self._clients) do
+ for _, client in pairs(dir_clients) do
+ res[#res + 1] = client
end
end
return res
@@ -241,7 +177,8 @@ end
--- a new client if one doesn't already exist for `bufnr`.
--- @param bufnr integer
--- @param project_root? string
-function M:try_add(bufnr, project_root)
+--- @param silent boolean
+function M:try_add(bufnr, project_root, silent)
bufnr = bufnr or api.nvim_get_current_buf()
if vim.bo[bufnr].buftype == 'nofile' then
@@ -258,7 +195,7 @@ function M:try_add(bufnr, project_root)
end
if project_root then
- self:add(project_root, false, bufnr)
+ self:add(project_root, false, bufnr, silent)
return
end
@@ -281,10 +218,10 @@ function M:try_add(bufnr, project_root)
end
if root_dir then
- self:add(root_dir, false, bufnr)
+ self:add(root_dir, false, bufnr, silent)
elseif self.config.single_file_support then
local pseudo_root = #bufname == 0 and pwd or util.path.dirname(buf_path)
- self:add(pseudo_root, true, bufnr)
+ self:add(pseudo_root, true, bufnr, silent)
end
end)
end
@@ -297,7 +234,7 @@ function M:try_add_wrapper(bufnr, project_root)
local config = self.config
-- `config.filetypes = nil` means all filetypes are valid.
if not config.filetypes or vim.tbl_contains(config.filetypes, vim.bo[bufnr].filetype) then
- self:try_add(bufnr, project_root)
+ self:try_add(bufnr, project_root, config.silent)
end
end