[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
emacs-29 55d29c9bacb: Eglot: fix jit-lock inlay hint bugs
From: |
João Távora |
Subject: |
emacs-29 55d29c9bacb: Eglot: fix jit-lock inlay hint bugs |
Date: |
Fri, 24 Feb 2023 09:49:29 -0500 (EST) |
branch: emacs-29
commit 55d29c9bacb6227bc8b3a6c0dd52c7085fe63aaf
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>
Eglot: fix jit-lock inlay hint bugs
One of the bugs was straightforward. The timer function of
eglot--update-hints must set the correct buffer.
The other is much more odd. When using Eglot on Emacs's own
src/coding.c, the jit-lock code starts calling its jit-functions over
and over again with the same sequence of arguments, like so:
======================================================================
1 -> (eglot--update-hints 63551 65051)
1 <- eglot--update-hints: [nil 25592 52026 4
======================================================================
1 -> (eglot--update-hints 65051 66551)
1 <- eglot--update-hints: [nil 25592 52026 4
======================================================================
1 -> (eglot--update-hints-1 63551 66551)
1 <- eglot--update-hints-1: nil
======================================================================
1 -> (eglot--update-hints 63551 65051)
1 <- eglot--update-hints: [nil 25592 52026 4
======================================================================
1 -> (eglot--update-hints 65051 66551)
1 <- eglot--update-hints: [nil 25592 52026 5
======================================================================
1 -> (eglot--update-hints-1 63551 66551)
1 <- eglot--update-hints-1: nil
This continues forever at a very fast rate and saturates the LSP
channel.
At first I thought that it was because eglot--update-hints-1 is
actually causing the buffer to be modified with overlays sometime in
the future, but it is not so! It seems that merely calling
(goto-char (eglot--lsp-position-to-point position))
(from the LSP request handler in eglot--update-hints-1) will cause
this bug.
* lisp/progmodes/eglot.el (eglot--update-hints): Fix bugs.
---
lisp/progmodes/eglot.el | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index e20d209332d..2b9d44f84e6 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -3492,12 +3492,15 @@ If NOERROR, return predicate, else erroring function."
(defvar-local eglot--outstanding-inlay-hints-region (cons nil nil)
"Jit-lock-calculated (FROM . TO) region with potentially outdated hints")
+(defvar-local eglot--outstanding-inlay-hints-last-region nil)
+
(defvar-local eglot--outstanding-inlay-regions-timer nil
"Helper timer for `eglot--update-hints'")
(defun eglot--update-hints (from to)
"Jit-lock function for Eglot inlay hints."
(cl-symbol-macrolet ((region eglot--outstanding-inlay-hints-region)
+ (last-region eglot--outstanding-inlay-hints-last-region)
(timer eglot--outstanding-inlay-regions-timer))
(setcar region (min (or (car region) (point-max)) from))
(setcdr region (max (or (cdr region) (point-min)) to))
@@ -3513,12 +3516,28 @@ If NOERROR, return predicate, else erroring function."
;; not introducing any more delay over jit-lock's timers.
(when (= jit-lock-context-unfontify-pos (point-max))
(if timer (cancel-timer timer))
- (setq timer (run-at-time
- 0 nil
- (lambda ()
- (eglot--update-hints-1 (max (car region) (point-min))
- (min (cdr region) (point-max)))
- (setq region (cons nil nil) timer nil)))))))
+ (let ((buf (current-buffer)))
+ (setq timer (run-at-time
+ 0 nil
+ (lambda ()
+ (eglot--when-live-buffer buf
+ ;; HACK: In some pathological situations
+ ;; (Emacs's own coding.c, for example),
+ ;; jit-lock is calling `eglot--update-hints'
+ ;; repeatedly with same sequence of
+ ;; arguments, which leads to
+ ;; `eglot--update-hints-1' being called with
+ ;; the same region repeatedly. This happens
+ ;; even if the hint-painting code does
+ ;; nothing else other than widen, narrow,
+ ;; move point then restore these things.
+ ;; Possible Emacs bug, but this fixes it.
+ (unless (equal last-region region)
+ (eglot--update-hints-1 (max (car region)
(point-min))
+ (min (cdr region)
(point-max)))
+ (setq last-region region))
+ (setq region (cons nil nil)
+ timer nil)))))))))
(defun eglot--update-hints-1 (from to)
"Do most work for `eglot--update-hints', including LSP request."
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- emacs-29 55d29c9bacb: Eglot: fix jit-lock inlay hint bugs,
João Távora <=