mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(lsp): check if buffer was detached in on_init callback (#28914)
Co-authored-by: Jongwook Choi <wookayin@gmail.com>
This commit is contained in:
		| @@ -612,8 +612,11 @@ function Client:initialize() | ||||
|     self:_run_callbacks(self._on_init_cbs, lsp.client_errors.ON_INIT_CALLBACK_ERROR, self, result) | ||||
|  | ||||
|     for buf in pairs(reattach_bufs) do | ||||
|       -- The buffer may have been detached in the on_init callback. | ||||
|       if self.attached_buffers[buf] then | ||||
|         self:_on_attach(buf) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     log.info( | ||||
|       self._log_prefix, | ||||
|   | ||||
| @@ -70,8 +70,8 @@ before_each(function() | ||||
|         inlayHintProvider = true, | ||||
|       }, | ||||
|       handlers = { | ||||
|         ['textDocument/inlayHint'] = function() | ||||
|           return vim.json.decode(response) | ||||
|         ['textDocument/inlayHint'] = function(_, _, callback) | ||||
|           callback(nil, vim.json.decode(response)) | ||||
|         end, | ||||
|       } | ||||
|     }) | ||||
| @@ -106,8 +106,8 @@ describe('vim.lsp.inlay_hint', function() | ||||
|           inlayHintProvider = true, | ||||
|         }, | ||||
|         handlers = { | ||||
|           ['textDocument/inlayHint'] = function() | ||||
|             return {} | ||||
|           ['textDocument/inlayHint'] = function(_, _, callback) | ||||
|             callback(nil, {}) | ||||
|           end, | ||||
|         } | ||||
|       }) | ||||
| @@ -206,8 +206,8 @@ describe('vim.lsp.inlay_hint', function() | ||||
|             inlayHintProvider = true, | ||||
|           }, | ||||
|           handlers = { | ||||
|             ['textDocument/inlayHint'] = function() | ||||
|               return { expected2 } | ||||
|             ['textDocument/inlayHint'] = function(_, _, callback) | ||||
|               callback(nil, { expected2 }) | ||||
|             end, | ||||
|           } | ||||
|         }) | ||||
|   | ||||
| @@ -95,11 +95,11 @@ describe('semantic token highlighting', function() | ||||
|             }, | ||||
|           }, | ||||
|           handlers = { | ||||
|             ['textDocument/semanticTokens/full'] = function() | ||||
|               return vim.fn.json_decode(response) | ||||
|             ['textDocument/semanticTokens/full'] = function(_, _, callback) | ||||
|               callback(nil, vim.fn.json_decode(response)) | ||||
|             end, | ||||
|             ['textDocument/semanticTokens/full/delta'] = function() | ||||
|               return vim.fn.json_decode(edit_response) | ||||
|             ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) | ||||
|               callback(nil, vim.fn.json_decode(edit_response)) | ||||
|             end, | ||||
|           } | ||||
|         }) | ||||
| @@ -560,11 +560,11 @@ describe('semantic token highlighting', function() | ||||
|             }, | ||||
|           }, | ||||
|           handlers = { | ||||
|             ['textDocument/semanticTokens/full'] = function() | ||||
|               return nil | ||||
|             ['textDocument/semanticTokens/full'] = function(_, _, callback) | ||||
|               callback(nil, nil) | ||||
|             end, | ||||
|             ['textDocument/semanticTokens/full/delta'] = function() | ||||
|               return nil | ||||
|               callback(nil, nil) | ||||
|             end, | ||||
|           } | ||||
|         }) | ||||
| @@ -608,11 +608,11 @@ describe('semantic token highlighting', function() | ||||
|             }, | ||||
|           }, | ||||
|           handlers = { | ||||
|             ['textDocument/semanticTokens/full'] = function() | ||||
|               return vim.fn.json_decode(response) | ||||
|             ['textDocument/semanticTokens/full'] = function(_, _, callback) | ||||
|               callback(nil, vim.fn.json_decode(response)) | ||||
|             end, | ||||
|             ['textDocument/semanticTokens/full/delta'] = function() | ||||
|               return vim.fn.json_decode(edit_response) | ||||
|             ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) | ||||
|               callback(nil, vim.fn.json_decode(edit_response)) | ||||
|             end, | ||||
|           } | ||||
|         }) | ||||
| @@ -1075,8 +1075,8 @@ b = "as"]], | ||||
|               }, | ||||
|             }, | ||||
|             handlers = { | ||||
|               ['textDocument/semanticTokens/full'] = function() | ||||
|                 return vim.fn.json_decode(resp) | ||||
|               ['textDocument/semanticTokens/full'] = function(_, _, callback) | ||||
|                 callback(nil, vim.fn.json_decode(resp)) | ||||
|               end, | ||||
|             } | ||||
|           }) | ||||
| @@ -1461,11 +1461,11 @@ int main() | ||||
|               }, | ||||
|             }, | ||||
|             handlers = { | ||||
|               ['textDocument/semanticTokens/full'] = function() | ||||
|                 return vim.fn.json_decode(resp1) | ||||
|               ['textDocument/semanticTokens/full'] = function(_, _, callback) | ||||
|                 callback(nil, vim.fn.json_decode(resp1)) | ||||
|               end, | ||||
|               ['textDocument/semanticTokens/full/delta'] = function() | ||||
|                 return vim.fn.json_decode(resp2) | ||||
|               ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) | ||||
|                 callback(nil, vim.fn.json_decode(resp2)) | ||||
|               end, | ||||
|             } | ||||
|           }) | ||||
|   | ||||
| @@ -39,8 +39,7 @@ M.create_server_definition = [[ | ||||
|         }) | ||||
|         local handler = handlers[method] | ||||
|         if handler then | ||||
|           local response, err = handler(method, params) | ||||
|           callback(err, response) | ||||
|           handler(method, params, callback) | ||||
|         elseif method == 'initialize' then | ||||
|           callback(nil, { | ||||
|             capabilities = opts.capabilities or {} | ||||
|   | ||||
| @@ -501,6 +501,35 @@ describe('LSP', function() | ||||
|       eq(true, result.detach_called) | ||||
|     end) | ||||
|  | ||||
|     it('should not re-attach buffer if it was deleted in on_init #28575', function() | ||||
|       clear() | ||||
|       exec_lua(create_server_definition) | ||||
|       exec_lua([[ | ||||
|         local server = _create_server({ | ||||
|           handlers = { | ||||
|             initialize = function(method, params, callback) | ||||
|               vim.schedule(function() | ||||
|                 callback(nil, { capabilities = {} }) | ||||
|               end) | ||||
|             end | ||||
|           } | ||||
|         }) | ||||
|         local bufnr = vim.api.nvim_create_buf(false, true) | ||||
|         local on_init_called = false | ||||
|         local client_id = vim.lsp.start({ | ||||
|           name = 'detach-dummy', | ||||
|           cmd = server.cmd, | ||||
|           on_init = function() | ||||
|             vim.api.nvim_buf_delete(bufnr, {}) | ||||
|             on_init_called = true | ||||
|           end | ||||
|         }) | ||||
|         vim.lsp.buf_attach_client(bufnr, client_id) | ||||
|         local ok = vim.wait(1000, function() return on_init_called end) | ||||
|         assert(ok, "on_init was not called") | ||||
|       ]]) | ||||
|     end) | ||||
|  | ||||
|     it('client should return settings via workspace/configuration handler', function() | ||||
|       local expected_handlers = { | ||||
|         { NIL, {}, { method = 'shutdown', client_id = 1 } }, | ||||
| @@ -670,7 +699,7 @@ describe('LSP', function() | ||||
|             } | ||||
|           }, | ||||
|           handlers = { | ||||
|             ['textDocument/willSaveWaitUntil'] = function() | ||||
|             ['textDocument/willSaveWaitUntil'] = function(_, _, callback) | ||||
|               local text_edit = { | ||||
|                 range = { | ||||
|                   start = { line = 0, character = 0 }, | ||||
| @@ -678,7 +707,7 @@ describe('LSP', function() | ||||
|                 }, | ||||
|                 newText = 'Hello' | ||||
|               } | ||||
|               return { text_edit, } | ||||
|               callback(nil, { text_edit, }) | ||||
|             end | ||||
|           }, | ||||
|         }) | ||||
| @@ -4144,8 +4173,8 @@ describe('LSP', function() | ||||
|             } | ||||
|           }, | ||||
|           handlers = { | ||||
|             ["textDocument/codeAction"] = function() | ||||
|               return { | ||||
|             ["textDocument/codeAction"] = function(_, _, callback) | ||||
|               callback(nil, { | ||||
|                 { | ||||
|                   title = "Code Action 1", | ||||
|                   command = { | ||||
| @@ -4153,10 +4182,10 @@ describe('LSP', function() | ||||
|                     command = "command:1", | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|               }) | ||||
|             end, | ||||
|             ["codeAction/resolve"] = function() | ||||
|               return nil, "resolve failed" | ||||
|             ["codeAction/resolve"] = function(_, _, callback) | ||||
|               callback("resolve failed", nil) | ||||
|             end, | ||||
|           } | ||||
|         }) | ||||
| @@ -4344,7 +4373,7 @@ describe('LSP', function() | ||||
|               }, | ||||
|             }, | ||||
|             handlers = { | ||||
|               ["textDocument/codeLens"] = function(method, params) | ||||
|               ["textDocument/codeLens"] = function(method, params, callback) | ||||
|                 local lenses = { | ||||
|                   { | ||||
|                     range = { | ||||
| @@ -4357,7 +4386,7 @@ describe('LSP', function() | ||||
|                     }, | ||||
|                   }, | ||||
|                 } | ||||
|                 return lenses | ||||
|                 callback(nil, lenses) | ||||
|               end, | ||||
|             } | ||||
|           }) | ||||
| @@ -4665,13 +4694,13 @@ describe('LSP', function() | ||||
|           }, | ||||
|           handlers = { | ||||
|             ---@return lsp.Location[] | ||||
|             ['textDocument/definition'] = function() | ||||
|               return { _G.mock_locations[1] } | ||||
|             ['textDocument/definition'] = function(_, _, callback) | ||||
|               callback(nil, { _G.mock_locations[1] }) | ||||
|             end, | ||||
|             ---@return lsp.WorkspaceSymbol[] | ||||
|             ['workspace/symbol'] = function(_, request) | ||||
|             ['workspace/symbol'] = function(_, request, callback) | ||||
|               assert(request.query == 'foobar') | ||||
|               return { | ||||
|               callback(nil, { | ||||
|                 { | ||||
|                   name = 'foobar', | ||||
|                   kind = 13, ---@type lsp.SymbolKind | ||||
| @@ -4682,7 +4711,7 @@ describe('LSP', function() | ||||
|                   kind = 12, ---@type lsp.SymbolKind | ||||
|                   location = _G.mock_locations[2], | ||||
|                 } | ||||
|               } | ||||
|               }) | ||||
|             end, | ||||
|           }, | ||||
|         }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ilia Choly
					Ilia Choly