From d55a455ec282aef56ee083b5197ea8f769735808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 5 Jan 2026 17:41:01 +0000 Subject: [PATCH] Eglot: prevent textDocument/diagnostic from being sent before didOpen Set eglot--docver to -1 in LSP documents not yet 'didOpen'ed, then add a check for this in the jsonrpc-connection-ready-p predicate. We do this because the call to eglot-flymake-backend may come in so fast that textDocument/diagnostic actually makes it into the jsonrpc queue before the didOpen. Much like, say, completions before didChange, some servers don't like that, understandibly. So use the existing "deferred" mechanism checks to make sure, as usual, that requests targetting a specific LSP document come after the didOpen/didChange informing the server of the actual state of the buffer. I _could_ have used nil instead of -1, and it would probably be cleaner. But -1 is safer, we never know if a version comparison won't slip outside the didOpen period. Might change my mind about this. * lisp/progmodes/eglot.el (eglot--docver): Init to -1. (eglot--managed-mode): Set eglot--docver to -1 when unmanaging. (jsonrpc-connection-ready-p): Check eglot--docver non-negative. (eglot--signal-textDocument/didClose): Set eglot--docver to -1. --- lisp/progmodes/eglot.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 94e6c175be2..00f549937d5 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1309,7 +1309,7 @@ If optional MARKERS, make markers instead." (cl-defmethod initialize-instance :before ((_server eglot-lsp-server) &optional args) (cl-remf args :initializationOptions)) -(defvar-local eglot--docver 0 +(defvar-local eglot--docver -1 "LSP document version. Bumped on `eglot--after-change'.") (defvar eglot--servers-by-project (make-hash-table :test #'equal) @@ -2286,6 +2286,7 @@ LSP Document version reported for DIAGNOSTICS (comparable to (eldoc-mode 1)) (cl-pushnew (current-buffer) (eglot--managed-buffers (eglot-current-server)))) (t + (setq eglot--docver -1) (eglot-inlay-hints-mode -1) (eglot-semantic-tokens-mode -1) (eglot--delete-overlays 'eglot--overlay) @@ -2952,7 +2953,7 @@ buffer." (cl-defmethod jsonrpc-connection-ready-p ((_server eglot-lsp-server) _what) "Tell if SERVER is ready for WHAT in current buffer." - (and (cl-call-next-method) (not eglot--recent-changes))) + (and (cl-call-next-method) (not (cl-minusp eglot--docver)) (not eglot--recent-changes))) (defvar-local eglot--change-idle-timer nil "Idle timer for didChange signals.") @@ -3158,6 +3159,7 @@ When called interactively, use the currently active server" (defun eglot--signal-textDocument/didClose () "Send textDocument/didClose to server." + (setq eglot--docver -1) (with-demoted-errors "[eglot] error sending textDocument/didClose: %s" (jsonrpc-notify