unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: "João Távora" <joaotavora@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: dalal.chinmay.0101@gmail.com, emacs-devel@gnu.org,
	dimitri@belopopsky.com,  luangruo@yahoo.com
Subject: Re: Eglot "inlay hints" landed
Date: Thu, 23 Feb 2023 17:46:08 +0000	[thread overview]
Message-ID: <CALDnm51POo+Fs2P8ZD_9T4AAMWb75hE44CS0JrXBb3YTcsqV9A@mail.gmail.com> (raw)
In-Reply-To: <83k008pah3.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 2764 bytes --]

On Thu, Feb 23, 2023 at 5:17 PM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: João Távora <joaotavora@gmail.com>
> > Date: Thu, 23 Feb 2023 16:09:24 +0000
> > Cc: dalal.chinmay.0101@gmail.com, emacs-devel@gnu.org, dimitri@belopopsky.com,
> >       luangruo@yahoo.com
> >
> > > If there's a change in A that affects B, jit-lock will call
> > > fontification-functions in both A and B, each one when it's about to
> > > display the corresponding window.
> >
> > Sure, but you're in charge of coding up the "affection" by asking
> > the LSP server.  In other words, only the LSP server knows that the
> > change in A affects B. You must assume that it does and ask it "Hey LSP
> > server, given that I've just changed document A, in your document B from
> > 42 to 420 is are there any new or different inlay hints you'd like to
> > give me?" jit-lock cannot foresee that upfront, it will only act on B's
> > display if B's buffer is changed.
>
> That's no for jit-lock to do.  And I don't see how it could be
> relevant to the issue we are discussing.  How do you do this now?

I don't.  I was just pointing out that jit-lock by itself doesn't
solve this A -> B dependency, which you seemed to suggest it does when
you wrote:

> > If there's a change in A that affects B, jit-lock will call
> > fontification-functions in both A and B, each one when it's about to
> > display the corresponding window.

So I agree with you shouldn't be continuing the discussion of this
topic: it is for later.

> That might be so, but one problem it does NOT have is missing the
> cases when you MUST ask the LSP server, because something is going to
> change on display.

That's true.  But then so does the other more naive implementation
which you get when you set eglot-lazy-inlay-hints to nil, and I'm
not sure which one is more performance.

> window-scroll-functions cannot promise that, since
> they are only called "when the window is scrolled", and there's more
> to that condition than meets the eye, believe me.

I believe you.  But as far as I can tell so far, it's the least
imperfect of the methods, and I haven't seen demonstrations of
problems so far, only your speculation of hypothetical problems.
Which again, I believe in, but I would like to measure the actual
problems quantitatively and qualitatively to make a good decision.

I'd love to switch over to the jit-lock implementation as it has
potential to be much neater.  But I can't seem to get it to not
over-request stuff. I attach the patch I've been trying, and it's
clearly got some thinkos when you test it.  It doesn't help that
`window-start` and `window-end` aren't -- apparently -- reliable
when called from a jit-lock function.

João

[-- Attachment #2: better-inlay-hints-maybe.patch --]
[-- Type: application/octet-stream, Size: 4989 bytes --]

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 7b4251a1242..76b56fa14e0 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -3507,14 +3507,27 @@ eglot-lazy-inlay-hints
 (defun eglot--inlay-hints-fully ()
   (eglot--widening (eglot--update-hints-1 (point-min) (point-max))))
 
-(cl-defun eglot--inlay-hints-lazily (&optional (buffer (current-buffer)))
-  (eglot--when-live-buffer buffer
-    (when eglot--managed-mode
-      (dolist (window (get-buffer-window-list nil nil 'visible))
-        (eglot--update-hints-1 (window-start window) (window-end window))))))
+(defvar-local eglot--inlay-hints-outstanding (cons nil nil)
+  "Largest (BEG . END) window subregion not yet updated for inlay hints.")
+
+(defun eglot--update-hints (from to)
+  "Jit-lock function for Eglot inlay hints."
+  (cl-symbol-macrolet ((x eglot--inlay-hints-outstanding))
+    (setq x (cons (min from (or (car x) most-positive-fixnum))
+                  (max to (or (cdr x) 0))))
+    (let ((w (get-buffer-window)))
+      (trace-values "window:      " w)
+      (trace-values "window-region:      " (cons (window-start w) (window-end w)))
+      (trace-values "outstanding: " eglot--inlay-hints-outstanding)
+      ;  FIXME: this is NOT the correct condition to decide when to
+      ;  request stuff from the server.
+      (when (or (< (car x) (window-start w)) (> (cdr x) (window-end w)))
+        (unwind-protect
+            (eglot--update-hints-1 (car x) (cdr x))
+          (setq x (cons nil nil)))))))
 
 (defun eglot--update-hints-1 (from to)
-  "Request LSP inlay hints and annotate current buffer from FROM to TO."
+  "Do actual work for `eglot--update-hints', including LSP request."
   (let* ((buf (current-buffer))
          (paint-hint
           (eglot--lambda ((InlayHint) position kind label paddingLeft paddingRight)
@@ -3545,33 +3558,6 @@ eglot--update-hints-1
                       (mapc paint-hint hints))))
      :deferred 'eglot--update-hints-1)))
 
-(defun eglot--inlay-hints-after-scroll (window display-start)
-  (cl-macrolet ((wsetq (sym val) `(set-window-parameter window ',sym ,val))
-                (wgetq (sym) `(window-parameter window ',sym)))
-    (let ((buf (window-buffer window))
-          (timer (wgetq eglot--inlay-hints-timer))
-          (last-display-start (wgetq eglot--last-inlay-hint-display-start)))
-      (when (and eglot-lazy-inlay-hints
-                 ;; FIXME: If `window' is _not_ the selected window,
-                 ;; then for some unknown reason probably related to
-                 ;; the overlays added later to the buffer, the scroll
-                 ;; function will be called indefinitely.  Not sure if
-                 ;; an Emacs bug, but prevent useless duplicate calls
-                 ;; by saving and examining `display-start' fixes it.
-                 (not (eql last-display-start display-start)))
-        (when timer (cancel-timer timer))
-        (wsetq eglot--last-inlay-hint-display-start
-               display-start)
-        (wsetq eglot--inlay-hints-timer
-               (run-at-time
-                eglot-lazy-inlay-hints
-                nil (lambda ()
-                      (eglot--when-live-buffer buf
-                        (when (eq buf (window-buffer window))
-                          (eglot--update-hints-1 (window-start window)
-                                                 (window-end window))
-                          (wsetq eglot--inlay-hints-timer nil))))))))))
-
 (define-minor-mode eglot-inlay-hints-mode
   "Minor mode for annotating buffers with LSP server's inlay hints."
   :global nil
@@ -3581,24 +3567,15 @@ eglot-inlay-hints-mode
            (eglot--warn
             "No :inlayHintProvider support. Inlay hints will not work."))
           (eglot-lazy-inlay-hints
-           (add-hook 'eglot--document-changed-hook
-                     #'eglot--inlay-hints-lazily t t)
-           (add-hook 'window-scroll-functions
-                     #'eglot--inlay-hints-after-scroll nil t)
-           ;; Maybe there isn't a window yet for current buffer,
-           ;; so `run-at-time' ensures this runs after redisplay.
-           (run-at-time 0 nil #'eglot--inlay-hints-lazily))
+           (jit-lock-register #'eglot--update-hints))
           (t
            (add-hook 'eglot--document-changed-hook
                      #'eglot--inlay-hints-fully nil t)
            (eglot--inlay-hints-fully))))
         (t
-         (remove-hook 'eglot--document-changed-hook
-                      #'eglot--inlay-hints-lazily t)
+         (jit-lock-unregister #'eglot--update-hints)
          (remove-hook 'eglot--document-changed-hook
                       #'eglot--inlay-hints-fully t)
-         (remove-hook 'window-scroll-functions
-                      #'eglot--inlay-hints-after-scroll t)
          (remove-overlays nil nil 'eglot--inlay-hint t))))
 
 \f

  reply	other threads:[~2023-02-23 17:46 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <ypi9cz6ahi5n.fsf@gmail.com>
     [not found] ` <83edqqaf8c.fsf@gnu.org>
     [not found]   ` <2B284D77-97DF-4B3E-89FB-13F0CA93D240@gmail.com>
     [not found]     ` <CALDnm53otfeDQGr0dWWUhxGLTSuiWTstLXJz1HXQgWLiAgsk=A@mail.gmail.com>
     [not found]       ` <CA+46MXbbW60t=JccgKGX39jTkOu+i=GZhzSQsfnqBUPb-mnJWg@mail.gmail.com>
2023-02-22 19:42         ` Eglot "inlay hints" landed João Távora
2023-02-23  1:45           ` [SPAM UNSURE] " Stephen Leake
2023-02-23  5:29           ` Chinmay Dalal
2023-02-23  6:31             ` Eli Zaretskii
2023-02-23  9:55               ` Chinmay Dalal
2023-02-23 10:03                 ` João Távora
2023-02-23 10:55                   ` Dimitri Belopopsky
2023-02-23 11:07                     ` João Távora
2023-02-23 12:03                     ` João Távora
2023-02-23 13:25                       ` Dimitri Belopopsky
2023-02-23 11:05                 ` Eli Zaretskii
2023-02-23 11:23                   ` João Távora
2023-02-23 12:36                     ` Eli Zaretskii
2023-02-23 12:57                       ` João Távora
2023-02-23 14:48                         ` Eli Zaretskii
2023-02-23 16:09                           ` João Távora
2023-02-23 17:17                             ` Eli Zaretskii
2023-02-23 17:46                               ` João Távora [this message]
2023-02-23 18:01                                 ` Eli Zaretskii
2023-02-23 19:26                                   ` João Távora
2023-02-23 19:54                                     ` Eli Zaretskii
2023-02-23 20:03                                       ` João Távora
2023-02-23 19:27                                 ` Stefan Monnier
2023-02-23 19:39                                   ` João Távora
2023-02-23 19:53                                     ` Stefan Monnier
2023-02-23 20:09                                       ` João Távora
2023-02-23 22:19                                         ` Stefan Monnier
2023-02-23 23:59                                           ` João Távora
2023-02-24  1:08                                             ` Stefan Monnier
2023-02-24  2:28                                               ` João Távora
2023-02-24  7:35                                               ` Eli Zaretskii
2023-02-24 10:42                                                 ` João Távora
2023-02-24 11:33                                                   ` Eli Zaretskii
2023-02-24 12:26                                                     ` João Távora
2023-02-23 10:17           ` Tassilo Horn
2023-02-23 12:55           ` Chinmay Dalal
2023-02-23 19:50           ` Nikola Pajkovsky
2023-02-23 21:35             ` João Távora
2023-02-23 21:45               ` Nikola Pajkovsky
2023-02-24  4:20               ` Chinmay Dalal
2023-02-24  5:04                 ` Chinmay Dalal
2023-02-24  9:59                 ` João Távora
2023-02-24 11:03                   ` Nikola Pajkovsky
2023-02-27 22:50           ` Johann Klähn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CALDnm51POo+Fs2P8ZD_9T4AAMWb75hE44CS0JrXBb3YTcsqV9A@mail.gmail.com \
    --to=joaotavora@gmail.com \
    --cc=dalal.chinmay.0101@gmail.com \
    --cc=dimitri@belopopsky.com \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=luangruo@yahoo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).