aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria José Solano <majosolano99@gmail.com>2024-11-24 13:43:27 -0800
committerLewis Russell <me@lewisr.dev>2024-12-07 09:43:45 +0000
commitc2bf09ddff4994f901350dd02412087a8abfde0a (patch)
treef75375a9e1e1d57800a005c916df9ebb27a7e54e
parent9c278af7cc96e5b7f07cd9fdec27951651063a76 (diff)
downloadrneovim-c2bf09ddff4994f901350dd02412087a8abfde0a.tar.gz
rneovim-c2bf09ddff4994f901350dd02412087a8abfde0a.tar.bz2
rneovim-c2bf09ddff4994f901350dd02412087a8abfde0a.zip
fix(lsp): check for configuration workspace folders when reusing clients
-rw-r--r--runtime/doc/lsp.txt4
-rw-r--r--runtime/lua/vim/lsp.lua46
-rw-r--r--runtime/lua/vim/lsp/client.lua21
3 files changed, 40 insertions, 31 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 2654d7f14f..1607f3492c 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -872,7 +872,9 @@ start({config}, {opts}) *vim.lsp.start()*
(`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
Predicate used to decide if a client should be re-used.
Used on all running clients. The default implementation
- re-uses a client if name and root_dir matches.
+ re-uses a client if it has the same name and if the given
+ workspace folders (or root_dir) are all included in the
+ client's workspace folders.
• {bufnr}? (`integer`) Buffer handle to attach to if
starting or re-using a client (0 for current).
• {attach}? (`boolean`) Whether to attach the client to a
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 4717d7995a..b67b2d6988 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -114,6 +114,22 @@ function lsp._unsupported_method(method)
return msg
end
+---@private
+---@param workspace_folders string|lsp.WorkspaceFolder[]?
+---@return lsp.WorkspaceFolder[]?
+function lsp._get_workspace_folders(workspace_folders)
+ if type(workspace_folders) == 'table' then
+ return workspace_folders
+ elseif type(workspace_folders) == 'string' then
+ return {
+ {
+ uri = vim.uri_from_fname(workspace_folders),
+ name = workspace_folders,
+ },
+ }
+ end
+end
+
local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'error' }
local format_line_ending = {
@@ -196,19 +212,24 @@ local function reuse_client_default(client, config)
return false
end
- if config.root_dir then
- local root = vim.uri_from_fname(config.root_dir)
- for _, dir in ipairs(client.workspace_folders or {}) do
- -- note: do not need to check client.root_dir since that should be client.workspace_folders[1]
- if root == dir.uri then
- return true
+ local config_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir)
+ or {}
+ local config_folders_included = 0
+
+ if not next(config_folders) then
+ return false
+ end
+
+ for _, config_folder in ipairs(config_folders) do
+ for _, client_folder in ipairs(client.workspace_folders) do
+ if config_folder.uri == client_folder.uri then
+ config_folders_included = config_folders_included + 1
+ break
end
end
end
- -- TODO(lewis6991): also check config.workspace_folders
-
- return false
+ return config_folders_included == #config_folders
end
--- Reset defaults set by `set_defaults`.
@@ -311,9 +332,10 @@ end
--- @inlinedoc
---
--- Predicate used to decide if a client should be re-used. Used on all
---- running clients. The default implementation re-uses a client if name and
---- root_dir matches.
---- @field reuse_client? (fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean)
+--- running clients. The default implementation re-uses a client if it has the
+--- same name and if the given workspace folders (or root_dir) are all included
+--- in the client's workspace folders.
+--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
---
--- Buffer handle to attach to if starting or re-using a client (0 for current).
--- @field bufnr? integer
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index a83d75bf75..7eb023da39 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -365,21 +365,6 @@ local function get_name(id, config)
return tostring(id)
end
---- @param workspace_folders string|lsp.WorkspaceFolder[]?
---- @return lsp.WorkspaceFolder[]?
-local function get_workspace_folders(workspace_folders)
- if type(workspace_folders) == 'table' then
- return workspace_folders
- elseif type(workspace_folders) == 'string' then
- return {
- {
- uri = vim.uri_from_fname(workspace_folders),
- name = workspace_folders,
- },
- }
- end
-end
-
--- @generic T
--- @param x elem_or_list<T>?
--- @return T[]
@@ -417,7 +402,7 @@ function Client.create(config)
flags = config.flags or {},
get_language_id = config.get_language_id or default_get_language_id,
capabilities = config.capabilities or lsp.protocol.make_client_capabilities(),
- workspace_folders = get_workspace_folders(config.workspace_folders or config.root_dir),
+ workspace_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir),
root_dir = config.root_dir,
_before_init_cb = config.before_init,
_on_init_cbs = ensure_list(config.on_init),
@@ -1174,7 +1159,7 @@ function Client:_add_workspace_folder(dir)
end
end
- local wf = assert(get_workspace_folders(dir))
+ local wf = assert(lsp._get_workspace_folders(dir))
self:notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = wf, removed = {} },
@@ -1189,7 +1174,7 @@ end
--- Remove a directory to the workspace folders.
--- @param dir string?
function Client:_remove_workspace_folder(dir)
- local wf = assert(get_workspace_folders(dir))
+ local wf = assert(lsp._get_workspace_folders(dir))
self:notify(ms.workspace_didChangeWorkspaceFolders, {
event = { added = {}, removed = wf },