mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(lsp): send textDocument/didChange for each buffer (#16431)
Co-authored-by: Mathias Fussenegger <f.mathias@zignar.net>
This commit is contained in:
		 Michael Lingelbach
					Michael Lingelbach
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							102e7e7929
						
					
				
				
					commit
					3451121a4e
				
			| @@ -320,7 +320,8 @@ do | |||||||
|   --- |   --- | ||||||
|   ---   state |   ---   state | ||||||
|   ---     pending_change?: function that the timer starts to trigger didChange |   ---     pending_change?: function that the timer starts to trigger didChange | ||||||
|   ---     pending_changes: list of tables with the pending changesets; for incremental_sync only |   ---     pending_changes: table (uri -> list of pending changeset tables)); | ||||||
|  |   --                       Only set if incremental_sync is used | ||||||
|   ---     use_incremental_sync: bool |   ---     use_incremental_sync: bool | ||||||
|   ---     buffers?: table (bufnr → lines); for incremental sync only |   ---     buffers?: table (bufnr → lines); for incremental sync only | ||||||
|   ---     timer?: uv_timer |   ---     timer?: uv_timer | ||||||
| @@ -348,14 +349,12 @@ do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   function changetracking.reset_buf(client, bufnr) |   function changetracking.reset_buf(client, bufnr) | ||||||
|  |     changetracking.flush(client) | ||||||
|     local state = state_by_client[client.id] |     local state = state_by_client[client.id] | ||||||
|     if state then |     if state and state.buffers then | ||||||
|       changetracking._reset_timer(state) |  | ||||||
|       if state.buffers then |  | ||||||
|       state.buffers[bufnr] = nil |       state.buffers[bufnr] = nil | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|   end |  | ||||||
|  |  | ||||||
|   function changetracking.reset(client_id) |   function changetracking.reset(client_id) | ||||||
|     local state = state_by_client[client_id] |     local state = state_by_client[client_id] | ||||||
| @@ -365,7 +364,7 @@ do | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   function changetracking.prepare(bufnr, firstline, lastline, new_lastline, changedtick) |   function changetracking.prepare(bufnr, firstline, lastline, new_lastline) | ||||||
|     local incremental_changes = function(client) |     local incremental_changes = function(client) | ||||||
|       local cached_buffers = state_by_client[client.id].buffers |       local cached_buffers = state_by_client[client.id].buffers | ||||||
|       local curr_lines = nvim_buf_get_lines(bufnr, 0, -1, true) |       local curr_lines = nvim_buf_get_lines(bufnr, 0, -1, true) | ||||||
| @@ -392,7 +391,7 @@ do | |||||||
|         client.notify("textDocument/didChange", { |         client.notify("textDocument/didChange", { | ||||||
|           textDocument = { |           textDocument = { | ||||||
|             uri = uri; |             uri = uri; | ||||||
|             version = changedtick; |             version = util.buf_versions[bufnr]; | ||||||
|           }; |           }; | ||||||
|           contentChanges = { changes, } |           contentChanges = { changes, } | ||||||
|         }) |         }) | ||||||
| @@ -402,28 +401,37 @@ do | |||||||
|       if state.use_incremental_sync then |       if state.use_incremental_sync then | ||||||
|         -- This must be done immediately and cannot be delayed |         -- This must be done immediately and cannot be delayed | ||||||
|         -- The contents would further change and startline/endline may no longer fit |         -- The contents would further change and startline/endline may no longer fit | ||||||
|         table.insert(state.pending_changes, incremental_changes(client)) |         if not state.pending_changes[uri] then | ||||||
|  |           state.pending_changes[uri] = {} | ||||||
|  |         end | ||||||
|  |         table.insert(state.pending_changes[uri], incremental_changes(client)) | ||||||
|       end |       end | ||||||
|       state.pending_change = function() |       state.pending_change = function() | ||||||
|         state.pending_change = nil |         state.pending_change = nil | ||||||
|         if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then |         if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then | ||||||
|           return |           return | ||||||
|         end |         end | ||||||
|         local contentChanges |  | ||||||
|         if state.use_incremental_sync then |         if state.use_incremental_sync then | ||||||
|           contentChanges = state.pending_changes |           for change_uri, content_changes in pairs(state.pending_changes) do | ||||||
|  |             client.notify("textDocument/didChange", { | ||||||
|  |               textDocument = { | ||||||
|  |                 uri = change_uri; | ||||||
|  |                 version = util.buf_versions[vim.uri_to_bufnr(change_uri)]; | ||||||
|  |               }; | ||||||
|  |               contentChanges = content_changes, | ||||||
|  |             }) | ||||||
|  |           end | ||||||
|           state.pending_changes = {} |           state.pending_changes = {} | ||||||
|         else |         else | ||||||
|           contentChanges = { full_changes(), } |  | ||||||
|         end |  | ||||||
|           client.notify("textDocument/didChange", { |           client.notify("textDocument/didChange", { | ||||||
|             textDocument = { |             textDocument = { | ||||||
|               uri = uri; |               uri = uri; | ||||||
|             version = changedtick; |               version = util.buf_versions[bufnr]; | ||||||
|             }; |             }; | ||||||
|           contentChanges = contentChanges |             contentChanges = { full_changes() }, | ||||||
|           }) |           }) | ||||||
|         end |         end | ||||||
|  |       end | ||||||
|       state.timer = vim.loop.new_timer() |       state.timer = vim.loop.new_timer() | ||||||
|       -- Must use schedule_wrap because `full_changes()` calls nvim_buf_get_lines |       -- Must use schedule_wrap because `full_changes()` calls nvim_buf_get_lines | ||||||
|       state.timer:start(debounce, 0, vim.schedule_wrap(state.pending_change)) |       state.timer:start(debounce, 0, vim.schedule_wrap(state.pending_change)) | ||||||
| @@ -1103,7 +1111,7 @@ do | |||||||
|       return |       return | ||||||
|     end |     end | ||||||
|     util.buf_versions[bufnr] = changedtick |     util.buf_versions[bufnr] = changedtick | ||||||
|     local compute_change_and_notify = changetracking.prepare(bufnr, firstline, lastline, new_lastline, changedtick) |     local compute_change_and_notify = changetracking.prepare(bufnr, firstline, lastline, new_lastline) | ||||||
|     for_each_buffer_client(bufnr, compute_change_and_notify) |     for_each_buffer_client(bufnr, compute_change_and_notify) | ||||||
|   end |   end | ||||||
| end | end | ||||||
| @@ -1162,6 +1170,7 @@ function lsp.buf_attach_client(bufnr, client_id) | |||||||
|       on_reload = function() |       on_reload = function() | ||||||
|         local params = { textDocument = { uri = uri; } } |         local params = { textDocument = { uri = uri; } } | ||||||
|         for_each_buffer_client(bufnr, function(client, _) |         for_each_buffer_client(bufnr, function(client, _) | ||||||
|  |           changetracking.reset_buf(client, bufnr) | ||||||
|           if client.resolved_capabilities.text_document_open_close then |           if client.resolved_capabilities.text_document_open_close then | ||||||
|             client.notify('textDocument/didClose', params) |             client.notify('textDocument/didClose', params) | ||||||
|           end |           end | ||||||
| @@ -1171,10 +1180,10 @@ function lsp.buf_attach_client(bufnr, client_id) | |||||||
|       on_detach = function() |       on_detach = function() | ||||||
|         local params = { textDocument = { uri = uri; } } |         local params = { textDocument = { uri = uri; } } | ||||||
|         for_each_buffer_client(bufnr, function(client, _) |         for_each_buffer_client(bufnr, function(client, _) | ||||||
|  |           changetracking.reset_buf(client, bufnr) | ||||||
|           if client.resolved_capabilities.text_document_open_close then |           if client.resolved_capabilities.text_document_open_close then | ||||||
|             client.notify('textDocument/didClose', params) |             client.notify('textDocument/didClose', params) | ||||||
|           end |           end | ||||||
|           changetracking.reset_buf(client, bufnr) |  | ||||||
|         end) |         end) | ||||||
|         util.buf_versions[bufnr] = nil |         util.buf_versions[bufnr] = nil | ||||||
|         all_buffer_active_clients[bufnr] = nil |         all_buffer_active_clients[bufnr] = nil | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user