mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(lsp): reuse client if configs match and no root dir
Problem:
An LSP configuration that creates client with no root_dir or
workspace_folders can result in vim.lsp.enable attaching to it multiple
times.
Solution:
When checking existing clients, reuse a client if it wasn't initially
configured have any workspace_folders. This more closely matches the
behaviour we had prior to d9235ef
			
			
This commit is contained in:
		 Lewis Russell
					Lewis Russell
				
			
				
					committed by
					
						 Lewis Russell
						Lewis Russell
					
				
			
			
				
	
			
			
			 Lewis Russell
						Lewis Russell
					
				
			
						parent
						
							7940ec6913
						
					
				
				
					commit
					9c20342297
				
			| @@ -201,23 +201,28 @@ local function reuse_client_default(client, config) | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   local config_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir) |   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 |   if not config_folders or not next(config_folders) then | ||||||
|     return false |     -- 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) | ||||||
|  |     return not client_config_folders or not next(client_config_folders) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   for _, config_folder in ipairs(config_folders) do |   for _, config_folder in ipairs(config_folders) do | ||||||
|  |     local found = false | ||||||
|     for _, client_folder in ipairs(client.workspace_folders) do |     for _, client_folder in ipairs(client.workspace_folders) do | ||||||
|       if config_folder.uri == client_folder.uri then |       if config_folder.uri == client_folder.uri then | ||||||
|         config_folders_included = config_folders_included + 1 |         found = true | ||||||
|         break |         break | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |     if not found then | ||||||
|  |       return false | ||||||
|  |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   return config_folders_included == #config_folders |   return true | ||||||
| end | end | ||||||
|  |  | ||||||
| --- Reset defaults set by `set_defaults`. | --- Reset defaults set by `set_defaults`. | ||||||
|   | |||||||
| @@ -731,9 +731,10 @@ describe('vim.lsp.completion: item conversion', function() | |||||||
|   ) |   ) | ||||||
| end) | end) | ||||||
|  |  | ||||||
|  | --- @param name string | ||||||
| --- @param completion_result lsp.CompletionList | --- @param completion_result lsp.CompletionList | ||||||
| --- @return integer | --- @return integer | ||||||
| local function create_server(completion_result) | local function create_server(name, completion_result) | ||||||
|   return exec_lua(function() |   return exec_lua(function() | ||||||
|     local server = _G._create_server({ |     local server = _G._create_server({ | ||||||
|       capabilities = { |       capabilities = { | ||||||
| @@ -751,7 +752,7 @@ local function create_server(completion_result) | |||||||
|     local bufnr = vim.api.nvim_get_current_buf() |     local bufnr = vim.api.nvim_get_current_buf() | ||||||
|     vim.api.nvim_win_set_buf(0, bufnr) |     vim.api.nvim_win_set_buf(0, bufnr) | ||||||
|     return vim.lsp.start({ |     return vim.lsp.start({ | ||||||
|       name = 'dummy', |       name = name, | ||||||
|       cmd = server.cmd, |       cmd = server.cmd, | ||||||
|       on_attach = function(client, bufnr0) |       on_attach = function(client, bufnr0) | ||||||
|         vim.lsp.completion.enable(true, client.id, bufnr0, { |         vim.lsp.completion.enable(true, client.id, bufnr0, { | ||||||
| @@ -800,7 +801,7 @@ describe('vim.lsp.completion: protocol', function() | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   it('fetches completions and shows them using complete on trigger', function() |   it('fetches completions and shows them using complete on trigger', function() | ||||||
|     create_server({ |     create_server('dummy', { | ||||||
|       isIncomplete = false, |       isIncomplete = false, | ||||||
|       items = { |       items = { | ||||||
|         { |         { | ||||||
| @@ -892,7 +893,7 @@ describe('vim.lsp.completion: protocol', function() | |||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('merges results from multiple clients', function() |   it('merges results from multiple clients', function() | ||||||
|     create_server({ |     create_server('dummy1', { | ||||||
|       isIncomplete = false, |       isIncomplete = false, | ||||||
|       items = { |       items = { | ||||||
|         { |         { | ||||||
| @@ -900,7 +901,7 @@ describe('vim.lsp.completion: protocol', function() | |||||||
|         }, |         }, | ||||||
|       }, |       }, | ||||||
|     }) |     }) | ||||||
|     create_server({ |     create_server('dummy2', { | ||||||
|       isIncomplete = false, |       isIncomplete = false, | ||||||
|       items = { |       items = { | ||||||
|         { |         { | ||||||
| @@ -933,7 +934,7 @@ describe('vim.lsp.completion: protocol', function() | |||||||
|         }, |         }, | ||||||
|       }, |       }, | ||||||
|     } |     } | ||||||
|     local client_id = create_server(completion_list) |     local client_id = create_server('dummy', completion_list) | ||||||
|  |  | ||||||
|     exec_lua(function() |     exec_lua(function() | ||||||
|       _G.called = false |       _G.called = false | ||||||
| @@ -970,7 +971,7 @@ describe('vim.lsp.completion: protocol', function() | |||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('enable(…,{convert=fn}) custom word/abbr format', function() |   it('enable(…,{convert=fn}) custom word/abbr format', function() | ||||||
|     create_server({ |     create_server('dummy', { | ||||||
|       isIncomplete = false, |       isIncomplete = false, | ||||||
|       items = { |       items = { | ||||||
|         { |         { | ||||||
| @@ -1012,7 +1013,7 @@ describe('vim.lsp.completion: integration', function() | |||||||
|     exec_lua(function() |     exec_lua(function() | ||||||
|       vim.o.completeopt = 'menuone,noselect' |       vim.o.completeopt = 'menuone,noselect' | ||||||
|     end) |     end) | ||||||
|     create_server(completion_list) |     create_server('dummy', completion_list) | ||||||
|     feed('i world<esc>0ih<c-x><c-o>') |     feed('i world<esc>0ih<c-x><c-o>') | ||||||
|     retry(nil, nil, function() |     retry(nil, nil, function() | ||||||
|       eq( |       eq( | ||||||
|   | |||||||
| @@ -5184,8 +5184,8 @@ describe('LSP', function() | |||||||
|         local win = vim.api.nvim_get_current_win() |         local win = vim.api.nvim_get_current_win() | ||||||
|         vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' }) |         vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' }) | ||||||
|         vim.api.nvim_win_set_cursor(win, { 3, 6 }) |         vim.api.nvim_win_set_cursor(win, { 3, 6 }) | ||||||
|         local client_id1 = assert(vim.lsp.start({ name = 'dummy', cmd = server1.cmd })) |         local client_id1 = assert(vim.lsp.start({ name = 'dummy1', cmd = server1.cmd })) | ||||||
|         local client_id2 = assert(vim.lsp.start({ name = 'dummy', cmd = server2.cmd })) |         local client_id2 = assert(vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })) | ||||||
|         local response |         local response | ||||||
|         vim.lsp.buf.definition({ |         vim.lsp.buf.definition({ | ||||||
|           on_list = function(r) |           on_list = function(r) | ||||||
| @@ -6203,5 +6203,33 @@ describe('LSP', function() | |||||||
|         end) |         end) | ||||||
|       ) |       ) | ||||||
|     end) |     end) | ||||||
|  |  | ||||||
|  |     it('does not attach to buffers more than once if no root_dir', function() | ||||||
|  |       exec_lua(create_server_definition) | ||||||
|  |  | ||||||
|  |       local tmp1 = t.tmpname(true) | ||||||
|  |  | ||||||
|  |       eq( | ||||||
|  |         1, | ||||||
|  |         exec_lua(function() | ||||||
|  |           local server = _G._create_server({ | ||||||
|  |             handlers = { | ||||||
|  |               initialize = function(_, _, callback) | ||||||
|  |                 callback(nil, { capabilities = {} }) | ||||||
|  |               end, | ||||||
|  |             }, | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |           vim.lsp.config('foo', { cmd = server.cmd, filetypes = { 'foo' } }) | ||||||
|  |           vim.lsp.enable('foo') | ||||||
|  |  | ||||||
|  |           vim.cmd.edit(assert(tmp1)) | ||||||
|  |           vim.bo.filetype = 'foo' | ||||||
|  |           vim.bo.filetype = 'foo' | ||||||
|  |  | ||||||
|  |           return #vim.lsp.get_clients({ bufnr = vim.api.nvim_get_current_buf() }) | ||||||
|  |         end) | ||||||
|  |       ) | ||||||
|  |     end) | ||||||
|   end) |   end) | ||||||
| end) | end) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user