From 3c924d13fe31d6fb9cd8b569b0454eea47773e25 Mon Sep 17 00:00:00 2001 From: jdrouhard Date: Thu, 25 Jun 2026 02:37:39 -0500 Subject: [PATCH] fix(lsp): fire LspNotify didChange autocmds after undo/redo #40404 Problem: LspNotify autocmds were not being triggered for didChange requests when being used during undo/redo (and possibly other) actions. autocmds are blocked when calling on_lines() callbacks while doing the undo/redo action. Solution: Defer firing the autocmd until after the action is complete. This is closer to what existed before, but now there's a check in the deferred function to only fire the autocmd if the client is still active and the buffer is still attached, if applicable. --- runtime/lua/vim/lsp/client.lua | 22 +++++++++++-------- .../plugin/lsp/semantic_tokens_spec.lua | 2 ++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 0297c02c3d..ae164edaed 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -858,15 +858,19 @@ function Client:notify(method, params, bufnr) local client_active = self.rpc.notify(method, params) if client_active then - api.nvim_exec_autocmds('LspNotify', { - buf = bufnr, - modeline = false, - data = { - client_id = self.id, - method = method, - params = params, - }, - }) + vim.schedule(function() + if not self:is_stopped() and (not bufnr or self.attached_buffers[bufnr]) then + api.nvim_exec_autocmds('LspNotify', { + buf = bufnr, + modeline = false, + data = { + client_id = self.id, + method = method, + params = params, + }, + }) + end + end) end return client_active diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index dabffcd639..0853abf3fe 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -335,6 +335,8 @@ describe('semantic token highlighting', function() -- modify the buffer feed('o') + n.poke_eventloop() + local messages = exec_lua('return _G.server_full.messages') local called_full = 0 local called_range = 0