Jsonrpc: avoid redisplay_internal calls from jsonrpc-request

The 'jsonrpc-request' function, when called with non-nil CANCEL-ON-INPUT,
relies on 'sit-for' to stop immediately when the user inputs something into
Emacs.  Although this behavior is working well, it has the hitherto
undiscovered side effect of invoking 'redisplay_internal', which triggers
expensive operations such as fontification.

This bug was noticied when using the 'breadcrumb' package in conjunction
with Eglot and a narrowed buffer.  To provide breadcrumbs for the current
context, breadcrumb.el invokes 'imenu--make-index-alist' on a timer.  That
function temporarily widens the buffer and then eventually calls
'redisplay_internal' (through 'eglot-imenu', 'jsonrpc-request', and
'sit-for').  This has the effect that the temporarily widened buffer is
re-rendered and displayed to the user until the LSP server answers the
request and 'imenu--make-index-alist' restores the restriction, an effect
that lasts between 0.5 and 2 seconds usually and is annoying and confusing.

To fix this, using a non-nil NODISP argument in the 'sit-for' is not enough
(though it's arguable it should be and maybe that's a separate bug).
Binding 'inhibit-redisplay' to 't' around 'sit-for' seems to fix the issue
robustly.

* lisp/jsonrpc.el (jsonrpc-request): Bind inhibit-redisplay to t and pass
  NODISP to sit-for.
This commit is contained in:
João Távora 2026-01-26 22:56:33 +00:00
parent 3dbddb4497
commit b224605d30

View file

@ -488,7 +488,8 @@ to the original request (normal or error) are ignored."
,@(when (plist-member args :timeout) `(:timeout ,timeout)))))
(cond (cancel-on-input
(unwind-protect
(let ((inhibit-quit t)) (while (sit-for 30)))
(let ((inhibit-quit t) (inhibit-redisplay t))
(while (sit-for 30 t)))
(setq canceled t))
(when (functionp cancel-on-input)
(funcall cancel-on-input (car id-and-timer)))