Eglot: prevent showDocument disruption of sync requests (bug#81538)

This couldn't be reproduced here, but seems nevertheless possible.  The
previous (run-at-time 0...) technique for the window/showDocument
handling never really avoided the fact that that timer could kick during
the accept-process-output of jsonrpc-request, thus happening before the
response to the original request.  Since the handling evolves a lot of
output to send to the process, it could be interrupted by the 'throw'
that's meant to exit abort 'accept-process-output' (and only that).

This commit should ensure the sequence is always this one.

a1. -> adals/ff-thingy sync client request
b1.   <- window/showDocument server request
b2.   -> window/showDocument client response (after scheduling 'c')
a2. <- ada/ff-thingy server response
c.  -> f-f-no-select, Eglot sends the large didOpen notification

* lisp/progmodes/eglot.el (eglot-handle-request): Maybe use
"post command" once trick.
This commit is contained in:
João Távora 2026-08-09 22:37:34 +01:00
parent 27ea7e6c1e
commit 83ec0fd8f3

View file

@ -2962,19 +2962,22 @@ THINGS are either registrations or unregisterations (sic)."
(cond
((eq external t) (browse-url uri))
((file-readable-p (setq filename (eglot-uri-to-path uri)))
;; Use run-with-timer to avoid nested client requests like the
;; "synchronous imenu" floated in bug#62116 presumably caused by
;; which-func-mode.
(run-with-timer
0 nil
(lambda ()
(with-current-buffer (find-file-noselect filename)
(cond (takeFocus
(pop-to-buffer (current-buffer))
(select-frame-set-input-focus (selected-frame)))
((display-buffer (current-buffer))))
(when selection
(eglot--goto selection))))))
;; Really ensure this runs when it is safe to run it.
;; run-with-timer avoid nested client requests like the
;; "synchronous imenu" floated in bug#62116, while the
;; "post-command once" trick is for bug#81538.
(cl-labels ((findit ()
(remove-hook 'post-command-hook #'findit)
(with-current-buffer (find-file-noselect filename)
(cond (takeFocus
(pop-to-buffer (current-buffer))
(select-frame-set-input-focus (selected-frame)))
((display-buffer (current-buffer))))
(when selection
(eglot--goto selection)))))
(if this-command
(add-hook 'post-command-hook #'findit)
(run-at-time 0 nil #'findit))))
(t (setq success :json-false)))
`(:success ,success)))