diff options
| author | Raphael <glepnir@neovim.pro> | 2022-12-26 20:50:30 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-26 20:50:30 +0800 |
| commit | a63d2c75c6880d45209baff596939343e8a431fd (patch) | |
| tree | 480d0b99b721f266a9352c35d3a133a2a3d95a69 /lua | |
| parent | fix: use client config capabilities to check server support workspae (#2354) (diff) | |
| download | nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.tar nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.tar.gz nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.tar.bz2 nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.tar.lz nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.tar.xz nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.tar.zst nvim-lspconfig-a63d2c75c6880d45209baff596939343e8a431fd.zip | |
fix: check workspace after client initial (#2356)
* fix: some server need restart
* fix: improve
* fix: async start client
* fix: remove session file
* fix: improve logic
* fix: improve logic
* fix: check the root already in workspace
* fix: improve check
* fix: add start_new_client into the if branch
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/lspconfig/configs.lua | 12 | ||||
| -rw-r--r-- | lua/lspconfig/util.lua | 163 |
2 files changed, 110 insertions, 65 deletions
diff --git a/lua/lspconfig/configs.lua b/lua/lspconfig/configs.lua index 71d553c9..a4eb8351 100644 --- a/lua/lspconfig/configs.lua +++ b/lua/lspconfig/configs.lua @@ -132,8 +132,7 @@ function configs.__newindex(t, config_name, config_def) return end local pseudo_root = #bufname == 0 and uv.cwd() or util.path.dirname(util.path.sanitize(bufname)) - local client_id = M.manager.add(pseudo_root, true) - lsp.buf_attach_client(api.nvim_get_current_buf(), client_id) + M.manager.add(pseudo_root, true, api.nvim_get_current_buf()) end end @@ -235,7 +234,6 @@ function configs.__newindex(t, config_name, config_def) return end - local id local root_dir local bufname = api.nvim_buf_get_name(bufnr) @@ -253,14 +251,10 @@ function configs.__newindex(t, config_name, config_def) end if root_dir then - id = manager.add(root_dir, false) + manager.add(root_dir, false, bufnr) elseif config.single_file_support then local pseudo_root = #bufname == 0 and uv.cwd() or util.path.dirname(buf_path) - id = manager.add(pseudo_root, true) - end - - if id then - lsp.buf_attach_client(bufnr, id) + manager.add(pseudo_root, true, bufnr) end end diff --git a/lua/lspconfig/util.lua b/lua/lspconfig/util.lua index cc9d9956..92594077 100644 --- a/lua/lspconfig/util.lua +++ b/lua/lspconfig/util.lua @@ -234,20 +234,14 @@ function M.server_per_root_dir_manager(make_config) local clients = {} local manager = {} - function manager.add(root_dir, single_file) + function manager.add(root_dir, single_file, bufnr) local client_id root_dir = M.path.sanitize(root_dir) local client_id_iterator = function(client_ids, conf) for _, id in ipairs(client_ids) do local client = lsp.get_client_by_id(id) - if - client - and client.name == conf.name - and client.config - and client.config.capabilities - and client.config.capabilities.workspace - then + if client and client.name == conf.name then return client end end @@ -277,67 +271,124 @@ function M.server_per_root_dir_manager(make_config) local new_config = make_config(root_dir) local client = get_client_from_cache(new_config) - if client then - -- if in single file mode just return this client id don't insert the new - -- root dir into the workspace_folders + local start_new_client = function() + -- do nothing if the client is not enabled + if new_config.enabled == false then + return + end + if not new_config.cmd then + vim.notify( + string.format( + '[lspconfig] cmd not defined for %q. Manually set cmd in the setup {} call according to server_configurations.md, see :help lspconfig-index.', + new_config.name + ), + vim.log.levels.ERROR + ) + return + end + new_config.on_exit = M.add_hook_before(new_config.on_exit, function() + clients[root_dir] = nil + end) + + -- Launch the server in the root directory used internally by lspconfig, if otherwise unset + -- also check that the path exist + if not new_config.cmd_cwd and uv.fs_realpath(root_dir) then + new_config.cmd_cwd = root_dir + end + + -- Sending rootDirectory and workspaceFolders as null is not explicitly + -- codified in the spec. Certain servers crash if initialized with a NULL + -- root directory. if single_file then - return client.id + new_config.root_dir = nil + new_config.workspace_folders = nil end - local params = lsp.util.make_workspace_params({ { uri = vim.uri_from_fname(root_dir), name = root_dir } }, { {} }) - client.rpc.notify('workspace/didChangeWorkspaceFolders', params) - if not client.workspace_folders then - client.workspace_folders = {} + client_id = lsp.start_client(new_config) + + -- Handle failures in start_client + if not client_id then + return end - table.insert(client.workspace_folders, params.event.added[1]) + + lsp.buf_attach_client(bufnr, client_id) + if not clients[root_dir] then clients[root_dir] = {} end - table.insert(clients[root_dir], client.id) - return client.id + table.insert(clients[root_dir], client_id) end - -- do nothing if the client is not enabled - if new_config.enabled == false then - return - end - if not new_config.cmd then - vim.notify( - string.format( - '[lspconfig] cmd not defined for %q. Manually set cmd in the setup {} call according to server_configurations.md, see :help lspconfig-index.', - new_config.name - ), - vim.log.levels.ERROR - ) - return - end - new_config.on_exit = M.add_hook_before(new_config.on_exit, function() - clients[root_dir] = nil - end) + if client then + local register_workspace_folders = function(client_instance) + local params = lsp.util.make_workspace_params( + { { uri = vim.uri_from_fname(root_dir), name = root_dir } }, + { {} } + ) + for _, schema in ipairs(client_instance.workspace_folders or {}) do + if schema.name == params.event.added[1].name then + return + end + end + client_instance.rpc.notify('workspace/didChangeWorkspaceFolders', params) + if not client_instance.workspace_folders then + client.workspace_folders = {} + end + table.insert(client_instance.workspace_folders, params.event.added[1]) + if not clients[root_dir] then + clients[root_dir] = {} + end + table.insert(clients[root_dir], client_instance.id) + end - -- Launch the server in the root directory used internally by lspconfig, if otherwise unset - -- also check that the path exist - if not new_config.cmd_cwd and uv.fs_realpath(root_dir) then - new_config.cmd_cwd = root_dir - end + local server_support_workspace = function(client_instance) + if + client_instance.server_capabilities and client_instance.server_capabilities.workspace + -- according the lsp spec doc the server capability is optional + -- some servers not add this field. so use the workspace to check is enough? + -- and client_instance.server_capabilities.workspace.workspaceFolders + then + return true + end + return false + end - -- Sending rootDirectory and workspaceFolders as null is not explicitly - -- codified in the spec. Certain servers crash if initialized with a NULL - -- root directory. - if single_file then - new_config.root_dir = nil - new_config.workspace_folders = nil - end - client_id = lsp.start_client(new_config) + -- if in single file mode just return this client id don't insert the new + -- root dir into the workspace_folders + if single_file then + lsp.buf_attach_client(bufnr, client.id) + return + end - -- Handle failures in start_client - if not client_id then - return - end + if not client.initialized then + local timer = vim.loop.new_timer() + timer:start( + 0, + 10, + vim.schedule_wrap(function() + if client.initialized and not timer:is_closing() then + if server_support_workspace(client) then + lsp.buf_attach_client(bufnr, client.id) + register_workspace_folders(client) + else + -- if not support workspace spawn a new one + start_new_client() + end + timer:stop() + timer:close() + end + end) + ) + return + end - if not clients[root_dir] then - clients[root_dir] = {} + if server_support_workspace(client) then + lsp.buf_attach_client(bufnr, client.id) + register_workspace_folders(client) + return + end end - table.insert(clients[root_dir], client_id) + + start_new_client() return client_id end |
