diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 228bbafdd2..deb7e06f9e 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1317,9 +1317,10 @@ Lua module: vim.lsp.client *lsp-client* request before sending kill -15. If set to false, nvim exits immediately after sending the "shutdown" request to the server. - • {root_dir}? (`string`) Directory where the LSP server will - base its workspaceFolders, rootUri, and rootPath - on initialization. + • {root_dir}? (`string|fun():string`) Directory (or a function + which returns a directory) where the LSP server + will base its workspaceFolders, rootUri, and + rootPath on initialization. Client:cancel_request({id}) *Client:cancel_request()* diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 5a93da4298..6d8389b160 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -200,12 +200,17 @@ local function reuse_client_default(client, config) return false end - local config_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir) + local root_dir = config.root_dir + if type(root_dir) == 'function' then + root_dir = root_dir() + end + + local config_folders = lsp._get_workspace_folders(config.workspace_folders or root_dir) if not config_folders or not next(config_folders) then -- Reuse if the client was configured with no workspace folders local client_config_folders = - lsp._get_workspace_folders(client.config.workspace_folders or client.config.root_dir) + lsp._get_workspace_folders(client.config.workspace_folders or client.root_dir) return not client_config_folders or not next(client_config_folders) end diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index d51a45b473..03a22842e5 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -130,8 +130,9 @@ local validate = vim.validate --- A table with flags for the client. The current (experimental) flags are: --- @field flags? vim.lsp.Client.Flags --- ---- Directory where the LSP server will base its workspaceFolders, rootUri, and rootPath on initialization. ---- @field root_dir? string +--- Directory (or a function which returns a directory) where the LSP server will base its +--- workspaceFolders, rootUri, and rootPath on initialization. +--- @field root_dir? string|fun():string --- @class vim.lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> --- @field pending table @@ -373,6 +374,11 @@ function Client.create(config) local id = client_index local name = get_name(id, config) + local root_dir = config.root_dir + if type(root_dir) == 'function' then + root_dir = root_dir() + end + --- @class vim.lsp.Client local self = { id = id, @@ -390,8 +396,8 @@ function Client.create(config) flags = config.flags or {}, get_language_id = config.get_language_id or default_get_language_id, capabilities = config.capabilities, - workspace_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir), - root_dir = config.root_dir, + workspace_folders = lsp._get_workspace_folders(config.workspace_folders or root_dir), + root_dir = root_dir, _before_init_cb = config.before_init, _on_init_cbs = vim._ensure_list(config.on_init), _on_exit_cbs = vim._ensure_list(config.on_exit), diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 1f246b0914..1dfed9c2d6 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -271,6 +271,33 @@ describe('LSP', function() } end) + it('supports a function for root_dir', function() + clear() + exec_lua(create_server_definition) + local result = exec_lua(function() + local server = _G._create_server({}) + + local client_id = vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + root_dir = function() + return 'some_directory' + end + }) + + if not client_id then + return 'vim.lsp.start did not return client_id' + end + + local client = vim.lsp.get_client_by_id(client_id) + if not client then + return 'No client found with id ' .. client_id + end + return client.root_dir + end) + eq('some_directory', result) + end) + it('should send didChangeConfiguration after initialize if there are settings', function() test_rpc_server({ test_name = 'basic_init_did_change_configuration',