* Eglot "inlay hints" landed [not found] ` <CA+46MXbbW60t=JccgKGX39jTkOu+i=GZhzSQsfnqBUPb-mnJWg@mail.gmail.com> @ 2023-02-22 19:42 ` João Távora 2023-02-23 1:45 ` [SPAM UNSURE] " Stephen Leake ` (5 more replies) 0 siblings, 6 replies; 44+ messages in thread From: João Távora @ 2023-02-22 19:42 UTC (permalink / raw) To: emacs-devel; +Cc: Dimitri Belopopsky, Chinmay Dalal, Po Lu, Eli Zaretskii I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the emacs-29 branch. It's a feature that some users (including me) were looking for for some time. Inlay hints are small text annotations to specific parts of the whole buffer, not unlike diagnostics, but designed to help readability instead of indicating problems. For example, a C++ LSP server can serve hints about positional parameter names in function calls and a variable's automatically deduced type. Emacs can display these hints in many little 0-length overlays with an 'before-string property, thus helping the user remember those types and parameter names. Since inlay hints are potentially a large amount of data to request from the LSP server, the implementation strives to be as parsimonious as possible with these requests. So, by default, inlay hints are only requested for the visible portions of the buffer across windows showing this buffer. This is done by leveraging the 'window-scroll-functions' variable, making for a reasonably complex implementation involving per-window timers. When scrolling a window, it may take a short amount of time for inlay hints to "pop in". The new user variable 'eglot-lazy-inlay-hints' can be used to exert some control over this. Specifically, if the variable's value is set to 'nil', then inlay hints are greedily fetched for the whole buffer every time a change occurs. This is a much simpler mode of operation which may avoid problems, but is also likely much slower in large buffers. Also, because the inlay feature is probably visually suprising to some, it is turned OFF by default, which is not the usual practice of Eglot (at least not when the necessary infrastructure is present). This decision may be changed soon. Here's a good one-liner for enabling it by default in every Eglot-managed buffer: (add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode) I haven't tested inlay hints extensively across many LSP servers, so I would appreciate any testing, both for functional edge cases and regarding performance. There are possibly more optimization oportunities in the "lazy" mode of operation, like more aggressively deleting buffer overlays that are not in visible parts of the buffer. Though I ended up writing this one from scratch, I want to thank Dimitry Bolopopsky <dimitri@belopopsky.com> and Chinmay Dala <dalal.chinmay.0101@gmail.com> for suggestions and early patches. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [SPAM UNSURE] Eglot "inlay hints" landed 2023-02-22 19:42 ` Eglot "inlay hints" landed João Távora @ 2023-02-23 1:45 ` Stephen Leake 2023-02-23 5:29 ` Chinmay Dalal ` (4 subsequent siblings) 5 siblings, 0 replies; 44+ messages in thread From: Stephen Leake @ 2023-02-23 1:45 UTC (permalink / raw) To: João Távora Cc: emacs-devel, Dimitri Belopopsky, Chinmay Dalal, Po Lu, Eli Zaretskii João Távora <joaotavora@gmail.com> writes: > So, by default, inlay hints are only requested for the visible portions > of the buffer across windows showing this buffer. This is done by > leveraging the 'window-scroll-functions' variable, making for a > reasonably complex implementation involving per-window timers. When > scrolling a window, it may take a short amount of time for inlay hints > to "pop in". The new user variable 'eglot-lazy-inlay-hints' can be used > to exert some control over this. Since font-lock has the same requirement to refresh the visible portion of the display, requesting inlay hints in a function registered with jit-lock-register would be a simpler design. -- -- Stephe ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 10:17 ` Tassilo Horn ` (3 subsequent siblings) 5 siblings, 1 reply; 44+ messages in thread From: Chinmay Dalal @ 2023-02-23 5:29 UTC (permalink / raw) To: João Távora Cc: emacs-devel, Dimitri Belopopsky, Po Lu, Eli Zaretskii Thanks, this works well. > Since inlay hints are potentially a large amount of data to request from > the LSP server, the implementation strives to be as parsimonious as > possible with these requests. > > So, by default, inlay hints are only requested for the visible portions > of the buffer across windows showing this buffer. This is done by > leveraging the 'window-scroll-functions' variable, making for a > reasonably complex implementation involving per-window timers. When > scrolling a window, it may take a short amount of time for inlay hints > to "pop in". Can it be instead done in such a way that initially (when loading a new file) they are requested for the whole buffer, then on subsequent changes they are only requested for the visible regions. This has some edge cases like pasting a huge block into a selected region (here, text will be changed beyond what is currently visible so it will take some time when someone scrolls to that region) but IMHO it seems strictly better than the present. Chinmay ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 5:29 ` Chinmay Dalal @ 2023-02-23 6:31 ` Eli Zaretskii 2023-02-23 9:55 ` Chinmay Dalal 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 6:31 UTC (permalink / raw) To: Chinmay Dalal; +Cc: joaotavora, emacs-devel, dimitri, luangruo > From: Chinmay Dalal <dalal.chinmay.0101@gmail.com> > Cc: emacs-devel@gnu.org, Dimitri Belopopsky <dimitri@belopopsky.com>, Po Lu > <luangruo@yahoo.com>, Eli Zaretskii <eliz@gnu.org> > Date: Thu, 23 Feb 2023 10:59:17 +0530 > > > So, by default, inlay hints are only requested for the visible portions > > of the buffer across windows showing this buffer. This is done by > > leveraging the 'window-scroll-functions' variable, making for a > > reasonably complex implementation involving per-window timers. When > > scrolling a window, it may take a short amount of time for inlay hints > > to "pop in". > > Can it be instead done in such a way that initially (when loading a new > file) they are requested for the whole buffer, then on subsequent > changes they are only requested for the visible regions. Why would we want that? ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 11:05 ` Eli Zaretskii 0 siblings, 2 replies; 44+ messages in thread From: Chinmay Dalal @ 2023-02-23 9:55 UTC (permalink / raw) To: Eli Zaretskii; +Cc: joaotavora, emacs-devel, dimitri, luangruo Eli Zaretskii <eliz@gnu.org> writes: >> From: Chinmay Dalal <dalal.chinmay.0101@gmail.com> >> Cc: emacs-devel@gnu.org, Dimitri Belopopsky <dimitri@belopopsky.com>, Po Lu >> <luangruo@yahoo.com>, Eli Zaretskii <eliz@gnu.org> >> Date: Thu, 23 Feb 2023 10:59:17 +0530 >> >> > So, by default, inlay hints are only requested for the visible portions >> > of the buffer across windows showing this buffer. This is done by >> > leveraging the 'window-scroll-functions' variable, making for a >> > reasonably complex implementation involving per-window timers. When >> > scrolling a window, it may take a short amount of time for inlay hints >> > to "pop in". >> >> Can it be instead done in such a way that initially (when loading a new >> file) they are requested for the whole buffer, then on subsequent >> changes they are only requested for the visible regions. > > Why would we want that? It will solve this problem: >> > When >> > scrolling a window, it may take a short amount of time for inlay hints >> > to "pop in". ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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:05 ` Eli Zaretskii 1 sibling, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 10:03 UTC (permalink / raw) To: Chinmay Dalal; +Cc: Eli Zaretskii, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 9:56 AM Chinmay Dalal <dalal.chinmay.0101@gmail.com> wrote: > > Why would we want that? > > > >> > When > >> > scrolling a window, it may take a short amount of time for inlay hints > >> > to "pop in". > It will solve this problem: Not significantly though. There are many operations that invalidate the whole buffer's hints, like changing the name of a function parameter, or doing some git operation which changes the contents of the whole buffer. That will still cause pop-in. So I don't think it's worth the added complexity: if you want no scrolling pop-in, set eglot-lazy-inlay-hints to nil. Maybe it's not bad for small buffers and fast servers. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 2 replies; 44+ messages in thread From: Dimitri Belopopsky @ 2023-02-23 10:55 UTC (permalink / raw) To: João Távora; +Cc: Chinmay Dalal, Eli Zaretskii, emacs-devel, luangruo [-- Attachment #1: Type: text/plain, Size: 1492 bytes --] Inlay hints are working well on my end! The only issue I seem to be having is when the server doesn't support inlay hints, and I have " (add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode)" in my config. It keeps erroring in this case and the connection to the lsp server seems to terminate in some cases. In any case it causes interference with other things, like completion which can stop working. You can try it with pylsp, and add "(add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode)" to your config. Trying to write a simple main function will show issues. For example this python code: def main(): pass On Thu, 23 Feb 2023 at 11:04, João Távora <joaotavora@gmail.com> wrote: > On Thu, Feb 23, 2023 at 9:56 AM Chinmay Dalal > <dalal.chinmay.0101@gmail.com> wrote: > > > > Why would we want that? > > > > > > >> > When > > >> > scrolling a window, it may take a short amount of time for inlay > hints > > >> > to "pop in". > > > It will solve this problem: > > Not significantly though. There are many operations that > invalidate the whole buffer's hints, like changing the name > of a function parameter, or doing some git operation > which changes the contents of the whole buffer. That will > still cause pop-in. So I don't think it's worth the added > complexity: if you want no scrolling pop-in, set > eglot-lazy-inlay-hints to nil. Maybe it's not bad for small > buffers and fast servers. > > João > [-- Attachment #2: Type: text/html, Size: 2145 bytes --] ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 1 sibling, 0 replies; 44+ messages in thread From: João Távora @ 2023-02-23 11:07 UTC (permalink / raw) To: Dimitri Belopopsky; +Cc: Chinmay Dalal, Eli Zaretskii, emacs-devel, luangruo On Thu, Feb 23, 2023 at 10:55 AM Dimitri Belopopsky <dimitri@belopopsky.com> wrote: > > Inlay hints are working well on my end! > The only issue I seem to be having is when the server doesn't support inlay hints, and I have " (add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode)" in my config. That's odd. I distinctly remembered thinking about this and making this issue a warning, not an error. Maybe it didn't make it in the commit I pushed somehow. I'll check. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 1 sibling, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 12:03 UTC (permalink / raw) To: Dimitri Belopopsky; +Cc: Chinmay Dalal, Eli Zaretskii, emacs-devel, luangruo On Thu, Feb 23, 2023 at 10:55 AM Dimitri Belopopsky <dimitri@belopopsky.com> wrote: > > Inlay hints are working well on my end! > The only issue I seem to be having is when the server doesn't support inlay hints, and I have " (add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode)" in my config. > > It keeps erroring in this case and the connection to the lsp server seems to terminate in some cases. In any case it causes interference with other things, like completion which can stop working. > > You can try it with pylsp, and add "(add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode)" to your config. Trying to write a simple main function will show issues. I can't reproduce this with this server. All I see is a warning: Warning (eglot): No :inlayHintProvider support. Inlay hints will not work. which is how it's supposed to work. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 12:03 ` João Távora @ 2023-02-23 13:25 ` Dimitri Belopopsky 0 siblings, 0 replies; 44+ messages in thread From: Dimitri Belopopsky @ 2023-02-23 13:25 UTC (permalink / raw) To: João Távora; +Cc: Chinmay Dalal, Eli Zaretskii, emacs-devel, luangruo [-- Attachment #1: Type: text/plain, Size: 1167 bytes --] On Thu, 23 Feb 2023 at 13:05, João Távora <joaotavora@gmail.com> wrote: > On Thu, Feb 23, 2023 at 10:55 AM Dimitri Belopopsky > <dimitri@belopopsky.com> wrote: > > > > Inlay hints are working well on my end! > > The only issue I seem to be having is when the server doesn't support > inlay hints, and I have " (add-hook 'eglot-managed-mode-hook > #'eglot-inlay-hints-mode)" in my config. > > > > It keeps erroring in this case and the connection to the lsp server > seems to terminate in some cases. In any case it causes interference with > other things, like completion which can stop working. > > > > You can try it with pylsp, and add "(add-hook 'eglot-managed-mode-hook > #'eglot-inlay-hints-mode)" to your config. Trying to write a simple main > function will show issues. > > I can't reproduce this with this server. All I see is a warning: > > Warning (eglot): No :inlayHintProvider support. Inlay hints will not work. > > which is how it's supposed to work. > > João > My bad... I'm using straight.el, and somehow it wasn't picking things correctly. Forcing it to use the built-in variant makes everything work correctly. [-- Attachment #2: Type: text/html, Size: 1656 bytes --] ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 9:55 ` Chinmay Dalal 2023-02-23 10:03 ` João Távora @ 2023-02-23 11:05 ` Eli Zaretskii 2023-02-23 11:23 ` João Távora 1 sibling, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 11:05 UTC (permalink / raw) To: Chinmay Dalal; +Cc: joaotavora, emacs-devel, dimitri, luangruo > From: Chinmay Dalal <dalal.chinmay.0101@gmail.com> > Cc: joaotavora@gmail.com, emacs-devel@gnu.org, dimitri@belopopsky.com, > luangruo@yahoo.com > Date: Thu, 23 Feb 2023 15:25:21 +0530 > > > Eli Zaretskii <eliz@gnu.org> writes: > > >> Can it be instead done in such a way that initially (when loading a new > >> file) they are requested for the whole buffer, then on subsequent > >> changes they are only requested for the visible regions. > > > > Why would we want that? > > It will solve this problem: > > >> > When > >> > scrolling a window, it may take a short amount of time for inlay hints > >> > to "pop in". So would using jit-lock-register, which was proposed here. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 11:05 ` Eli Zaretskii @ 2023-02-23 11:23 ` João Távora 2023-02-23 12:36 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 11:23 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Chinmay Dalal, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 11:05 AM Eli Zaretskii <eliz@gnu.org> wrote: > > > From: Chinmay Dalal <dalal.chinmay.0101@gmail.com> > > Cc: joaotavora@gmail.com, emacs-devel@gnu.org, dimitri@belopopsky.com, > > luangruo@yahoo.com > > Date: Thu, 23 Feb 2023 15:25:21 +0530 > > > > > > Eli Zaretskii <eliz@gnu.org> writes: > > > > >> Can it be instead done in such a way that initially (when loading a new > > >> file) they are requested for the whole buffer, then on subsequent > > >> changes they are only requested for the visible regions. > > > > > > Why would we want that? > > > > It will solve this problem: > > > > >> > When > > >> > scrolling a window, it may take a short amount of time for inlay hints > > >> > to "pop in". > > So would using jit-lock-register, which was proposed here. The "pop-in" delay is just a function of the intentional bandwidth-conserving timer delay + the normal LSP interprocess communication delay. Any jit/lazy Emacs-side solution is going to have to deal at least with the second addend of that sum. jit-lock-register was unknown to me. It seems to rely on some heuristic to know what regions need to be "refontified". I wonder if the heuristic will be accurate for inlay hints, since changing void foo(int bar){...} to void foo(int baz){...} in one part of the buffer doesn't usually change the fontification of the rest of the buffer. But it might very well invalidate the inlay hints everywhere. In fact the invalidation impact is not just in the same buffer, but potentially all other buffers (all the ones where a call to 'foo' is found). Eglot's inlay hints implementation doesn't handle this edge case. Though I don't think it would be extremely hard to, it doesn't seem extremely relevant for what is usually a "best effort" helper feature from the LSP side. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 12:36 UTC (permalink / raw) To: João Távora; +Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo > From: João Távora <joaotavora@gmail.com> > Date: Thu, 23 Feb 2023 11:23:40 +0000 > Cc: Chinmay Dalal <dalal.chinmay.0101@gmail.com>, emacs-devel@gnu.org, > dimitri@belopopsky.com, luangruo@yahoo.com > > On Thu, Feb 23, 2023 at 11:05 AM Eli Zaretskii <eliz@gnu.org> wrote: > > > > > Eli Zaretskii <eliz@gnu.org> writes: > > > > > > >> Can it be instead done in such a way that initially (when loading a new > > > >> file) they are requested for the whole buffer, then on subsequent > > > >> changes they are only requested for the visible regions. > > > > > > > > Why would we want that? > > > > > > It will solve this problem: > > > > > > >> > When > > > >> > scrolling a window, it may take a short amount of time for inlay hints > > > >> > to "pop in". > > > > So would using jit-lock-register, which was proposed here. > > The "pop-in" delay is just a function of the intentional > bandwidth-conserving timer delay + the normal LSP interprocess > communication delay. Any jit/lazy Emacs-side solution > is going to have to deal at least with the second addend of > that sum. I don't understand: using jit-lock-register just means your code is called via jit-lock's fontification-functions instead of window-scroll-functions that you used. Any problems with LSP delays that you deal with in the latter should be possible in the former as well, no? Or what am I missing? The advantages of using jit-lock are that (a) it is more accurate in telling you which parts of the buffer are about to be displayed, and (b) it is much more reliable, because window-scroll-functions are not necessarily called when something changes on display. For example, we lately discovered that pixel-scroll-precision-mode doesn't call window-scroll-functions. > jit-lock-register was unknown to me. It seems to rely on some > heuristic to know what regions need to be "refontified". It isn't a heuristic. jit-lock is called from the display engine, which always has a pretty good idea which parts of the buffer it needs to show on the screen. > I wonder if the heuristic will be accurate for inlay hints, since > changing void foo(int bar){...} to void foo(int baz){...} in one > part of the buffer doesn't usually change the fontification of the > rest of the buffer. The display engine doesn't know which parts will be affected by the change, it only knowes what's on display and what isn't. The function called via fontification-functions are supposed to know their job, and look at the parts of the buffer according to their needs; jit-lock just gives them a hint in the form of the region of the buffer it wants to display. > In fact the invalidation impact is not just in the same buffer, > but potentially all other buffers (all the ones where a call to > 'foo' is found). Eglot's inlay hints implementation doesn't > handle this edge case. Though I don't think it would be > extremely hard to, it doesn't seem extremely relevant for what > is usually a "best effort" helper feature from the LSP side. We don't need to make the overlays until the buffer is shown in some window, right? ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 12:36 ` Eli Zaretskii @ 2023-02-23 12:57 ` João Távora 2023-02-23 14:48 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 12:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo Eli Zaretskii <eliz@gnu.org> writes: > The advantages of using jit-lock are that (a) it is more accurate in > telling you which parts of the buffer are about to be displayed, and > (b) Ah, if it works with "parts of the buffer about to be displayed", then it should be good, yes. But the docstring of jit-lock-register says "START and END indicating the region that needs to be (re)fontified". If that is guaranteed to always match the "region of the buffer about to be displayed" in the window, then we're good. I wonder if it also removes the need for the "smoothing" timers I am using. But note though, that while this has promise for a simpler and more robust implementation, it will _not_ solve the "pop-in" delay. The effects that Eglot's jit-lock-register FUN fontification function produces in the buffer are guaranteed _not_ be finished by the time FUN returns (unless these FUN is allowed to be slow and blocking, which I really don't think is the point). That's what I meant by "any Emacs-side solution [...] deal with [the normal LSP interprocess communication] delay". > it is much more reliable, because window-scroll-functions are not > necessarily called when something changes on display. For example, we > lately discovered that pixel-scroll-precision-mode doesn't call > window-scroll-functions. >> In fact the invalidation impact is not just in the same buffer, >> but potentially all other buffers (all the ones where a call to >> 'foo' is found). Eglot's inlay hints implementation doesn't >> handle this edge case. Though I don't think it would be >> extremely hard to, it doesn't seem extremely relevant for what >> is usually a "best effort" helper feature from the LSP side. > > We don't need to make the overlays until the buffer is shown in some > window, right? Yes, but two buffers A and B might already be showing in some window. If you do the change in buffer A and it affects B, then in the current version, the parts of A being show in windows will be updated, but B the parts of B being shown in some other windows will not. João PS: On an unrelated note, I pushed this to emacs-29. If you wish me to revert the inlay hints implementation and do all this work in master, it's fine by me. In practice, it won't really make that much of a difference because Eglot (along with being a new emacs-29 feature) is also a GNU ELPA :core package and emacs-29 users will have access to the latest and greatest features and bugfixes relatively easily anyway. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 14:48 UTC (permalink / raw) To: João Távora; +Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo > From: João Távora <joaotavora@gmail.com> > Cc: dalal.chinmay.0101@gmail.com, emacs-devel@gnu.org, > dimitri@belopopsky.com, luangruo@yahoo.com > Date: Thu, 23 Feb 2023 12:57:26 +0000 > > Eli Zaretskii <eliz@gnu.org> writes: > > > We don't need to make the overlays until the buffer is shown in some > > window, right? > > Yes, but two buffers A and B might already be showing in some window. > If you do the change in buffer A and it affects B, then in the current > version, the parts of A being show in windows will be updated, but B the > parts of B being shown in some other windows will not. 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. > PS: On an unrelated note, I pushed this to emacs-29. If you wish me to > revert the inlay hints implementation and do all this work in master, > it's fine by me. emacs-29 is fine, thanks. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 14:48 ` Eli Zaretskii @ 2023-02-23 16:09 ` João Távora 2023-02-23 17:17 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 16:09 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 2:49 PM Eli Zaretskii <eliz@gnu.org> wrote: > > > From: João Távora <joaotavora@gmail.com> > > Cc: dalal.chinmay.0101@gmail.com, emacs-devel@gnu.org, > > dimitri@belopopsky.com, luangruo@yahoo.com > > Date: Thu, 23 Feb 2023 12:57:26 +0000 > > > > Eli Zaretskii <eliz@gnu.org> writes: > > > > > We don't need to make the overlays until the buffer is shown in some > > > window, right? > > > > Yes, but two buffers A and B might already be showing in some window. > > If you do the change in buffer A and it affects B, then in the current > > version, the parts of A being show in windows will be updated, but B the > > parts of B being shown in some other windows will not. > > 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. Regardless of that separate issue, I started experimenting with jit-lock-register. It's promising, but has problems. Here's a small experiment. Use this foo.cpp file somewhere and have say, the clangd server handy. void foo(int bar){} int main() { foo(42); .... repeats about ~250 times .... foo(42); } If you start eglot and eglot-inlay-hints-mode in this buffer, you should see void foo(int bar){} int main() { foo(bar: 42); // 'bar: ' is the untangible hint overlay foo(bar: 42); foo(bar: 42); ... < end of window > I also traced the current eglot--update-hints-1 file which is a binary function of two buffer positions, just like the jit function. This is the function that contacts the LSP server via JSONRPC and some time in the future, after it returns, the 0-length overlays will be created. Here's how it is called after enabling eglot and scrolling 4 screenfuls forward (C-v) and 4 back (M-v). ====================================================================== 1 -> (eglot--update-hints-1 1 476) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 443 927) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 894 1378) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 1345 1829) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 1796 2280) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 1345 1829) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 894 1378) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 443 927) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 1 476) 1 <- eglot--update-hints-1: nil As you can see, it only requests inlay hints for the regions actually displayed in the window. It re-requests some stuff when going back, since it has no memory of what it already requested or if things were invalidated. Now if I put eglot--update-hints-1 in jit-lock-function and disable my window-scroll-functions, then do the same: ====================================================================== 1 -> (eglot--update-hints-1 1 1501) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 1501 2678) 1 <- eglot--update-hints-1: nil As you can see, it did much larger, heavier requests upfront, even before it knew I was going to scroll forward. But in general it worked and you can argue that doing only two requests for larger chunks of inlay hints is better than more requests for smaller chunks. Now, if I change the line void foo(int bar){} to void foo(int baz){} the point is to get updated hints in the window: int main() { foo(baz: 42); // 'bar: ' is the untangible hint overlay foo(baz: 42); foo(baz: 42); ... < end of window > The jit-lock implementation will do this: ====================================================================== 1 -> (eglot--update-hints-1 1 19) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 1 20) 1 <- eglot--update-hints-1: nil ====================================================================== 1 -> (eglot--update-hints-1 20 1520) 1 <- eglot--update-hints-1: nil The first two calls are useless and so is most of the third one. For the third one you can argue, as above, that it's a good thing to predict that the user is going to scroll down. But the first two, which also caused two LSP requests, are definitely useless. OT1H, I think I can make this work, by finding some means to coalesce those three calls into one. Suggestions welcome. Even after that complexity, it seems it will be a much neater implementation. OTOH it sort of negates my original intention of requesting only as many inlay hints as strictly necessary. THough that might have been premature optimization anyway. > > PS: On an unrelated note, I pushed this to emacs-29. If you wish me to > > revert the inlay hints implementation and do all this work in master, > > it's fine by me. > > emacs-29 is fine, thanks. OK! João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 17:17 UTC (permalink / raw) To: João Távora; +Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo > 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? > Regardless of that separate issue, I started experimenting with > jit-lock-register. It's promising, but has problems. 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. 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. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 17:17 ` Eli Zaretskii @ 2023-02-23 17:46 ` João Távora 2023-02-23 18:01 ` Eli Zaretskii 2023-02-23 19:27 ` Stefan Monnier 0 siblings, 2 replies; 44+ messages in thread From: João Távora @ 2023-02-23 17:46 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo [-- 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 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 17:46 ` João Távora @ 2023-02-23 18:01 ` Eli Zaretskii 2023-02-23 19:26 ` João Távora 2023-02-23 19:27 ` Stefan Monnier 1 sibling, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 18:01 UTC (permalink / raw) To: João Távora, Stefan Monnier Cc: dalal.chinmay.0101, emacs-devel, dimitri, luangruo > From: João Távora <joaotavora@gmail.com> > Date: Thu, 23 Feb 2023 17:46:08 +0000 > Cc: dalal.chinmay.0101@gmail.com, emacs-devel@gnu.org, dimitri@belopopsky.com, > luangruo@yahoo.com > > > 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. That was written under the assumption that the overlays in B are already updated. Then redisplay will know it must redraw B. > > 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. I actually gave you a recipe for demonstrating the problems I have in mind: scroll the window under pixel-scroll-precision-mode. AFAIK, we don't call window-scroll-functions in that case. Another situation where we don't call window-scroll-functions is when the user types into the buffer. Yet another situation is when you type "C-x 1" to delete all the other windows on the frame, leaving the current window that now shows more stuff than before. > 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. Sorry, I don't have time for that ATM, but maybe Stefan will want to comment. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 18:01 ` Eli Zaretskii @ 2023-02-23 19:26 ` João Távora 2023-02-23 19:54 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 19:26 UTC (permalink / raw) To: Eli Zaretskii Cc: Stefan Monnier, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 6:01 PM Eli Zaretskii <eliz@gnu.org> wrote: > > > From: João Távora <joaotavora@gmail.com> > > Date: Thu, 23 Feb 2023 17:46:08 +0000 > > Cc: dalal.chinmay.0101@gmail.com, emacs-devel@gnu.org, dimitri@belopopsky.com, > > luangruo@yahoo.com > > > > > 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. > > That was written under the assumption that the overlays in B are > already updated. Then redisplay will know it must redraw B. > > > > 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. > > I actually gave you a recipe for demonstrating the problems I have in > mind: scroll the window under pixel-scroll-precision-mode. AFAIK, we > don't call window-scroll-functions in that case. I don't have a pixel-scroll-enabled Emacs to test. Can you scroll large portions of the window like that and w-s-functions will never get called? I'd say that's a bug we should fix. > Another situation where we don't call window-scroll-functions is when > the user types into the buffer. That is handled by Eglot's after-change-functions already so it isn't a problem. > Yet another situation is when you type "C-x 1" to delete all the other > windows on the frame, leaving the current window that now shows more > stuff than before. Reproduced. Easy enough to fix with window-configuration-change-functions. I pushed a fix. > > 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. > > Sorry, I don't have time for that ATM, but maybe Stefan will want to > comment. I'll keep trying. I think what I'd want is for the "contextual" call with the big chunk about to be jit-refontified remember the smaller adjacent chunks and make a request for the big chunk + the smaller chunks. Here's the latest version of the patch using a timer to achieve that. It's pretty gross, but I hope it expresses the idea. diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index eea8be6d1aa..251f6f11090 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -3507,14 +3507,47 @@ 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 nil + "List of regions") + +(defvar-local eglot--inlay-hints-outstanding-timer nil + "Timer") + +(defun eglot--update-hints (from to) + "Jit-lock function for Eglot inlay hints." + (if eglot--inlay-hints-outstanding-timer + (cancel-timer eglot--inlay-hints-outstanding-timer)) + (push (cons from to) eglot--inlay-hints-outstanding) + (setq eglot--inlay-hints-outstanding-timer + (run-with-timer + ;; FIXME: Gross + (+ 0.1 (max eglot-lazy-inlay-hints jit-lock-context-time)) + nil (lambda () + (trace-values eglot--inlay-hints-outstanding) + (cl-loop with region< = (lambda (r1 r2) + (if (= (car r1) (car r2)) + (< (cdr r1) (cdr r2)) + (< (car r1) (car r2)))) + with sorted = (cl-sort eglot--inlay-hints-outstanding region<) + with coalesced = (cl-reduce (lambda (acc x) + (cond ((and acc (>= (cdr (car acc)) + (car x))) + (setcdr (car acc) (cdr x)) + acc) + (t + (push x acc) + acc))) + sorted + :initial-value nil) + for r in coalesced + do (eglot--update-hints-1 (max (car r) (point-min)) + (min (cdr r) (point-max))) + finally + (setq eglot--inlay-hints-outstanding nil + eglot--inlay-hints-outstanding-timer 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,36 +3578,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)))))))))) - -(defun eglot--inlay-hints-after-window-config-change () - (eglot--update-hints-1 (window-start) (window-end))) - (define-minor-mode eglot-inlay-hints-mode "Minor mode for annotating buffers with LSP server's inlay hints." :global nil @@ -3584,28 +3587,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) - (add-hook 'window-configuration-change-hook - #'eglot--inlay-hints-after-window-config-change 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 'window-configuration-change-hook - #'eglot--inlay-hints-after-window-config-change) - (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)))) ^ permalink raw reply related [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-23 19:54 UTC (permalink / raw) To: João Távora Cc: monnier, dalal.chinmay.0101, emacs-devel, dimitri, luangruo > From: João Távora <joaotavora@gmail.com> > Date: Thu, 23 Feb 2023 19:26:10 +0000 > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, dalal.chinmay.0101@gmail.com, > emacs-devel@gnu.org, dimitri@belopopsky.com, luangruo@yahoo.com > > > I actually gave you a recipe for demonstrating the problems I have in > > mind: scroll the window under pixel-scroll-precision-mode. AFAIK, we > > don't call window-scroll-functions in that case. > > I don't have a pixel-scroll-enabled Emacs to test. Can you scroll > large portions of the window like that and w-s-functions will never > get called? I'd say that's a bug we should fix. > > > Another situation where we don't call window-scroll-functions is when > > the user types into the buffer. > > That is handled by Eglot's after-change-functions already so it > isn't a problem. > > > Yet another situation is when you type "C-x 1" to delete all the other > > windows on the frame, leaving the current window that now shows more > > stuff than before. > > Reproduced. Easy enough to fix with window-configuration-change-functions. > I pushed a fix. My point is that using jit-lock machinery, you will never miss an update, because redisplay is very good at knowing when something needs to be redrawn. It has to. By contrast, all those hooks are less reliable, and also make Emacs sluggish, because the hooks are many times triggered when there's nothing to do wrt display. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 19:54 ` Eli Zaretskii @ 2023-02-23 20:03 ` João Távora 0 siblings, 0 replies; 44+ messages in thread From: João Távora @ 2023-02-23 20:03 UTC (permalink / raw) To: Eli Zaretskii; +Cc: monnier, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 7:54 PM Eli Zaretskii <eliz@gnu.org> wrote: > > Reproduced. Easy enough to fix with window-configuration-change-functions. > > I pushed a fix. > > My point is that using jit-lock machinery, you will never miss an > update, because redisplay is very good at knowing when something needs > to be redrawn. It has to. Sure, I agree there. > By contrast, all those hooks are less > reliable, and also make Emacs sluggish, because the hooks are many > times triggered when there's nothing to do wrt display. It remains to be seen whether this is more or less sluggish than the jit-lock version, because at least the naive jit-lock version is making lots of requests over to the process. In TRAMP scenarios or networking scenarios, this may be slow. So I'm am focusing on finding the best solution but it's not immediately obvious that jit is always best, because of the fixed overhead (in this case LSP comms), which doesn't exist in the use cases jit-lock was designed for. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 17:46 ` João Távora 2023-02-23 18:01 ` Eli Zaretskii @ 2023-02-23 19:27 ` Stefan Monnier 2023-02-23 19:39 ` João Távora 1 sibling, 1 reply; 44+ messages in thread From: Stefan Monnier @ 2023-02-23 19:27 UTC (permalink / raw) To: João Távora Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo > 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. Sorry, I have not followed the discussion, so I don't know what are "inlay hints" nor how to test them. What problem do you see what you try your code? > +(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))))))) Why do you compare to `window-start/end`? As you say, they're not reliably available during jit-lock, and that's for fundamental reasons: jit-lock effects can change `window-start/end`. But I can't see a good reason why you'd need to do such comparison: the fact that jit-lock calls you is supposed to say "we need this for redisplay", so you shouldn't need to double-check against window bounds. Unless maybe you have `jit-lock-stealth-time` set to a non-nil value, in which case indeed jit-lock will be called even on non-displayed areas of the buffer, but it's arguably what the user (you in this case) asked for. IOW, you should be able to skip `eglot--update-hints` altogether and use `eglot--update-hints-1` directly (modulo catching errors and such maybe). Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 19:27 ` Stefan Monnier @ 2023-02-23 19:39 ` João Távora 2023-02-23 19:53 ` Stefan Monnier 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 19:39 UTC (permalink / raw) To: Stefan Monnier Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 7:28 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote: > > > 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. > > Sorry, I have not followed the discussion, so I don't know what are > "inlay hints" nor how to test them. What problem do you see what you > try your code? Hi Stefan. Inlay hints are described summarily in the very first message to this thread and in the commit implementing them. They're very many 0-length overlays, almost like tooltips, annotating type deductions and positional parameter names. The goal here is to request them at the correct time and balance multiple objectives: 1. minimize the number of requests 2. ensure the request covers all visible portions of the buffer across any windows showing it. 3. don't request for too large a region, else the amount of data can be prohibitive. The latest message I sent to Eli has my best shot at it. If you have a clangd executable somewhere, you can test this rather easily with the eglot.el in core and a cpp file such as void foo(int bar) {} int main() { foo(42); foo(42); ... very many lines of this ... foo(42); foo(42); foo(42); } You should see some intangible text appear in the buffer so that it will look like: void foo(int bar) {} int main() { foo( bar: 42); foo( bar: 42); ... very many lines of this ... foo( bar: 42); foo( bar: 42); foo( bar: 42); } Then scroll around in the buffer and check the traces of eglot--update-hints-1. Try to change that 'int bar' to 'int quux' and see if the system reacts correctly to the change updating the ' bar: ' hint to ' quux: '. See also my last message to Eli, which contains a horrible patch that nevertheless does more or less achieve those objectives. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Stefan Monnier @ 2023-02-23 19:53 UTC (permalink / raw) To: João Távora Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo > See also my last message to Eli, which contains a horrible > patch that nevertheless does more or less achieve those > objectives. Hmm... that patch looks reasonably sane to me (while writing the previous message I hesitated to suggest to delay the actual work to after redisplay so you can coalesce several jit chunks). Which part do you find horrible? Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 19:53 ` Stefan Monnier @ 2023-02-23 20:09 ` João Távora 2023-02-23 22:19 ` Stefan Monnier 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 20:09 UTC (permalink / raw) To: Stefan Monnier Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 7:53 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote: > > > See also my last message to Eli, which contains a horrible > > patch that nevertheless does more or less achieve those > > objectives. > > Hmm... that patch looks reasonably sane to me (while writing the > previous message I hesitated to suggest to delay the actual work to > after redisplay so you can coalesce several jit chunks). > > Which part do you find horrible? Mostly the fact that it's operating on a separate timer, but one that is directly correlated to jit-lock-context-time. So the bookkeeping and the coalescing of the small+large jit chunks should be provided by the jit infrastructure instead. And then no extra timer or logic would be needed. Can we make jit-lock.el a :core ELPA package? João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Stefan Monnier @ 2023-02-23 22:19 UTC (permalink / raw) To: João Távora Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo > Mostly the fact that it's operating on a separate timer, but one > that is directly correlated to jit-lock-context-time. But that's because you're willing to wait for the context refresh to do your own. > So the bookkeeping and the coalescing of the small+large jit chunks > should be provided by the jit infrastructure instead. So far, you're the first to need such a thing. In my experience the needs for "jit display refresh" can be fairly subtly different, so it's not clear how generally useful your approach would be. Maybe we could provide some shared infrastructure to maintain a "coalescing set of buffer regions", but if so, I suspect that it wouldn't need to be tied to `jit-lock.el`. Also, I'm not sure it gives exactly the info you need/want: I suspect that in some languages you can have: foo (x) ... function foo (bar : Int) so that changing the `foo` definition will need to update the inlay on the call to `foo` that is earlier in the buffer, hence jit-lock-context refresh won't be sufficient and you'll need to force your own refresh. [ I think jit-lock would benefit from being able to flush a particular backend's without forcing all of the backends at the sane time. ] > And then no extra timer or logic would be needed. You mean you'd integrate it into `jit-lock-context`? Maybe that could be done. > Can we make jit-lock.el a :core ELPA package? I have no opinion on that. Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 22:19 ` Stefan Monnier @ 2023-02-23 23:59 ` João Távora 2023-02-24 1:08 ` Stefan Monnier 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-23 23:59 UTC (permalink / raw) To: Stefan Monnier Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Thu, Feb 23, 2023 at 10:19 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote: > > > Mostly the fact that it's operating on a separate timer, but one > > that is directly correlated to jit-lock-context-time. > > But that's because you're willing to wait for the context refresh to do > your own. > > > So the bookkeeping and the coalescing of the small+large jit chunks > > should be provided by the jit infrastructure instead. > > So far, you're the first to need such a thing. In my experience the > needs for "jit display refresh" can be fairly subtly different, so it's > not clear how generally useful your approach would be. Maybe we could > provide some shared infrastructure to maintain a "coalescing set of > buffer regions", but if so, I suspect that it wouldn't need to be tied > to `jit-lock.el`. > > Also, I'm not sure it gives exactly the info you need/want: > I suspect that in some languages you can have: > > foo (x) > ... > function foo (bar : Int) Yeah, in that case we're frobbed. But isn't that a problem already those "some languages" for regular "contextual" fontification? > > And then no extra timer or logic would be needed. > > You mean you'd integrate it into `jit-lock-context`? > Maybe that could be done. > > Can we make jit-lock.el a :core ELPA package? > I have no opinion on that. That's the only reasonable way that Eglot can ever be changed to make use of new jit-lock infrastructure. Anyway, have a look at this patch: This implementation is much simpler than the one based on windows-scroll-functions. It's also conceptually safer, since jit-lock is guaranteed to refontify the regions that may need redisplaying. It's not trivially simple though, as simply adding 'eglot--update-hints-1' to jit-lock-functions, while possible, is going to request inlay hints from the LSP server for every small fraction changed by the user. So we do some bookkeeping on regions and coalesce them at a suitable time for a larger request. To do this, we use a jit-lock implementation detail, jit-lock-context-unfontify-pos, which tells us that the contextual fontification has just finished. Not sure how brittle it is, but it seems to work reasonably. * doc/misc/eglot.texi (Eglot Variables): Remove mention to deleted eglot-lazy-inlay-hints. * lisp/progmodes/eglot.el (eglot-lazy-inlay-hints) (eglot--inlay-hints-after-scroll) (eglot--inlay-hints-fully) (eglot--inlay-hints-lazily): Remove. (eglot--update-hints): Add function. (eglot-inlay-hints-mode): Simplify. --- diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index eea8be6d1aa..9955b04574f 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -3489,32 +3489,38 @@ eglot-type-hint-face (defface eglot-parameter-hint-face '((t (:inherit eglot-inlay-hint-face))) "Face used for parameter inlay hint overlays.") -(defcustom eglot-lazy-inlay-hints 0.3 - "If non-nil, restrict LSP inlay hints to visible portion of the buffer. - -Value is a number specifying how many seconds to wait after a -window has been (re)scrolled before requesting new inlay hints -for the now-visible portion of the buffer shown in the window. - -If nil, then inlay hints are requested for the entire buffer. -This could be slow. - -This value is only meaningful if the minor mode -`eglot-inlay-hints-mode' is turned on in a buffer." - :type 'number - :version "29.1") - -(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--outstanding-inlay-regions nil + "List of regions that weren't yet \"contextually\" fontified.") + +(defun eglot--update-hints (from to) + "Jit-lock function for Eglot inlay hints." + ;; HACK: Comparing `jit-lock-context-unfontify-pos' to `point-max' + ;; is our way of telling whether this call to `jit-lock-functions' + ;; happens after `jit-lock-context-timer' has just run. This is the + ;; best time to coalesce the regions in + ;; `eglot--outstanding-inlay-regions' and contact the LSP server. Any + ;; other call to this function just adds another region to that list. + (if (= jit-lock-context-unfontify-pos (point-max)) + (let* ((sorted (sort (cons (cons from to) + eglot--outstanding-inlay-regions) + (pcase-lambda (`(,a1 . ,a2) `(,b1 . ,b2)) + (if (= a1 b1) (< a2 b2) (< a1 b1))))) + (coalesced (cl-reduce (lambda (acc x) + (cond ((and acc (>= (cdr (car acc)) + (car x))) + (setcdr (car acc) (cdr x)) + acc) + (t (push x acc) acc))) + sorted + :initial-value nil))) + (dolist (r coalesced) + (eglot--update-hints-1 (max (car r) (point-min)) + (min (cdr r) (point-max)))) + (setq eglot--outstanding-inlay-regions nil)) + (push (cons from to) eglot--outstanding-inlay-regions))) (defun eglot--update-hints-1 (from to) - "Request LSP inlay hints and annotate current buffer from FROM to TO." + "Do most work for `eglot--update-hints', including LSP request." (let* ((buf (current-buffer)) (paint-hint (eglot--lambda ((InlayHint) position kind label paddingLeft paddingRight) @@ -3545,67 +3551,16 @@ 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)))))))))) - -(defun eglot--inlay-hints-after-window-config-change () - (eglot--update-hints-1 (window-start) (window-end))) - (define-minor-mode eglot-inlay-hints-mode "Minor mode for annotating buffers with LSP server's inlay hints." :global nil (cond (eglot-inlay-hints-mode - (cond - ((not (eglot--server-capable :inlayHintProvider)) + (if (eglot--server-capable :inlayHintProvider) + (jit-lock-register #'eglot--update-hints 'contextual) (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) - (add-hook 'window-configuration-change-hook - #'eglot--inlay-hints-after-window-config-change 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)) - (t - (add-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-fully nil t) - (eglot--inlay-hints-fully)))) + "No :inlayHintProvider support. Inlay hints will not work."))) (t - (remove-hook 'window-configuration-change-hook - #'eglot--inlay-hints-after-window-config-change) - (remove-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-lazily t) - (remove-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-fully t) - (remove-hook 'window-scroll-functions - #'eglot--inlay-hints-after-scroll t) + (jit-lock-unregister #'eglot--update-hints) (remove-overlays nil nil 'eglot--inlay-hint t)))) ^ permalink raw reply related [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 2 replies; 44+ messages in thread From: Stefan Monnier @ 2023-02-24 1:08 UTC (permalink / raw) To: João Távora Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo >> Also, I'm not sure it gives exactly the info you need/want: >> I suspect that in some languages you can have: >> >> foo (x) >> ... >> function foo (bar : Int) > > Yeah, in that case we're frobbed. But isn't that a problem already > those "some languages" for regular "contextual" fontification? Yes and no: yes, there are already cases where the jit-lock-context heuristic of refreshing everything *after* a modification is not sufficient, but as a general rule programming languages are designed for "forward-only parsing" so it's unusual for a change at POS to affect the parsing before POS (and most uses of jit-lock limit themselves to syntactic information, so there are rather few cases where this is a problem). In those few cases we use things like the `jit-lock-defer-multiline` property which the major mode's font-lock rules can place manually in an ad-hoc manner. In your case, I suspect for the affected language servers there's not much more we can do but to say that the whole buffer's inlays need to be recomputed after a change. > To do this, we use a jit-lock implementation detail, > jit-lock-context-unfontify-pos, which tells us that the contextual > fontification has just finished. Not sure how brittle it is, but it > seems to work reasonably. I think it won't work reliably in the case where the "immediate" jit-lock refresh happens to cover everything until window-end (e.g. we just inserted chunk of text that ends after window-end). In that case the jit-lock-context thingy will just mark the rest of the buffer as "not fresh" but won't call your fontification function at all. [ And of course, there are also those few rare modes that don't use jit-lock-context at all. ] I think using your own timer is probably the better option. I'd make it wait for `eglot-lazy-inlay-hints` rather than (+ eglot-lazy-inlay-hints jit-lock-context-time), but I'd give it as default value a value computed from `jit-lock-context-time`. Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-24 1:08 ` Stefan Monnier @ 2023-02-24 2:28 ` João Távora 2023-02-24 7:35 ` Eli Zaretskii 1 sibling, 0 replies; 44+ messages in thread From: João Távora @ 2023-02-24 2:28 UTC (permalink / raw) To: Stefan Monnier Cc: Eli Zaretskii, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Fri, Feb 24, 2023 at 1:08 AM Stefan Monnier <monnier@iro.umontreal.ca> wrote: > In your case, I suspect for the affected language servers there's not much > more we can do but to say that the whole buffer's inlays need to be > recomputed after a change. I'd really like to avoid that. If it comes to that, and the problem really is annoying enough (it might not be, and inlay hints are usually a best-effort thing by the servers themselves) then I think going back to the window-scroll-functions might be a better option. It doesn't have this problem. > > To do this, we use a jit-lock implementation detail, > > jit-lock-context-unfontify-pos, which tells us that the contextual > > fontification has just finished. Not sure how brittle it is, but it > > seems to work reasonably. > > I think it won't work reliably in the case where the "immediate" > jit-lock refresh happens to cover everything until window-end (e.g. we > just inserted chunk of text that ends after window-end). In that case > the jit-lock-context thingy will just mark the rest of the buffer as > "not fresh" but won't call your fontification function at all. Yes, I noticed something like that: many immediate small jit lock calls where the condition was true. > [ And of course, there are also those few rare modes that don't use > jit-lock-context at all. ] > > I think using your own timer is probably the better option. I'd > make it wait for `eglot-lazy-inlay-hints` rather than (+ > eglot-lazy-inlay-hints jit-lock-context-time), but I'd give it as > default value a value computed from `jit-lock-context-time`. Using a timer is necessary, but I've found that a 0-second timer is sufficient to coalesce "well". But we only fire the timer if the "unfontify-pos == point-max" condition is met. Then we don't need to compete with jit-lock-context-timer, which is really the part I found very bad. I've pushed this last version to emacs-29. Have a look there, please. And thanks for the insight! João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 1 sibling, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-24 7:35 UTC (permalink / raw) To: Stefan Monnier Cc: joaotavora, dalal.chinmay.0101, emacs-devel, dimitri, luangruo > From: Stefan Monnier <monnier@iro.umontreal.ca> > Cc: Eli Zaretskii <eliz@gnu.org>, dalal.chinmay.0101@gmail.com, > emacs-devel@gnu.org, dimitri@belopopsky.com, luangruo@yahoo.com > Date: Thu, 23 Feb 2023 20:08:41 -0500 > > Yes and no: yes, there are already cases where the jit-lock-context > heuristic of refreshing everything *after* a modification is not > sufficient If a jit-lock client is smart enough, it should itself install an after-change function to remove the 'fontified property from the portions of buffer text affected by a change that are before the first changed position (or maybe even in other buffers). > but as a general rule programming languages are designed for > "forward-only parsing" so it's unusual for a change at POS to affect the > parsing before POS Strictly speaking, this is inaccurate: a change in the middle of a line could very well affect parsing of that entire line, so it in effect affects everything from the beginning of that line (perhaps even more, if that line is a continued line, in the language syntax). But jit-lock is supposed to already account for that, and call the fontification-functions with START set to the beginning of the line, unless I'm misremembering. (You already know all that, but maybe João doesn't.) > > To do this, we use a jit-lock implementation detail, > > jit-lock-context-unfontify-pos, which tells us that the contextual > > fontification has just finished. Not sure how brittle it is, but it > > seems to work reasonably. > > I think it won't work reliably in the case where the "immediate" > jit-lock refresh happens to cover everything until window-end (e.g. we > just inserted chunk of text that ends after window-end). In that case > the jit-lock-context thingy will just mark the rest of the buffer as > "not fresh" but won't call your fontification function at all. > [ And of course, there are also those few rare modes that don't use > jit-lock-context at all. ] jit-lock doesn't use window-end. It can't, really: the results of fontification could affect where the window ends, which is why window-end is only updated when redisplay of a window successfully finishes, which is way after jit-lock did its job. That is why jit-lock calls fontification-functions with END that is arbitrarily computed from START; this is controlled by jit-lock-chunk-size. And a function called via fontification-functions could legitimately decide it fontifies more than just the chunk for which it was called. (Again, you already know all that. I'm writing this to avoid potential misunderstandings and confusion.) ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-24 7:35 ` Eli Zaretskii @ 2023-02-24 10:42 ` João Távora 2023-02-24 11:33 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-24 10:42 UTC (permalink / raw) To: Eli Zaretskii Cc: Stefan Monnier, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Fri, Feb 24, 2023 at 7:35 AM Eli Zaretskii <eliz@gnu.org> wrote: > > > From: Stefan Monnier <monnier@iro.umontreal.ca> > > Cc: Eli Zaretskii <eliz@gnu.org>, dalal.chinmay.0101@gmail.com, > > emacs-devel@gnu.org, dimitri@belopopsky.com, luangruo@yahoo.com > > Date: Thu, 23 Feb 2023 20:08:41 -0500 > > > > Yes and no: yes, there are already cases where the jit-lock-context > > heuristic of refreshing everything *after* a modification is not > > sufficient > > If a jit-lock client is smart enough, it should itself install an > after-change function to remove the 'fontified property from the > portions of buffer text affected by a change that are before the first > changed position (or maybe even in other buffers). Thanks, I was going to ask about that. I suppose this is how one marks sections of a buffer "dirty" or invalidatest them so that jit-lock knows it must run over them again when it sees fit. If it works with other buffers as well, it might provide an elegant solution to the "A affects B" scenario we discussed earlier. > > but as a general rule programming languages are designed for > > "forward-only parsing" so it's unusual for a change at POS to affect the > > parsing before POS > > Strictly speaking, this is inaccurate: a change in the middle of a > line could very well affect parsing of that entire line, so it in > effect affects everything from the beginning of that line (perhaps > even more, if that line is a continued line, in the language syntax). > But jit-lock is supposed to already account for that, and call the > fontification-functions with START set to the beginning of the line, > unless I'm misremembering. (You already know all that, but maybe João > doesn't.) Thanks, I think I can confirm this. I've observed this behaviour. Jit lock starts in the beginning of the line to end of the line in a small chunk containing the small changed region, only then proceeds to larger chunks (after some jit-lock-contextual-time, apparently). > > > To do this, we use a jit-lock implementation detail, > > > jit-lock-context-unfontify-pos, which tells us that the contextual > > > fontification has just finished. Not sure how brittle it is, but it > > > seems to work reasonably. > > > > I think it won't work reliably in the case where the "immediate" > > jit-lock refresh happens to cover everything until window-end (e.g. we > > just inserted chunk of text that ends after window-end). In that case > > the jit-lock-context thingy will just mark the rest of the buffer as > > "not fresh" but won't call your fontification function at all. > > [ And of course, there are also those few rare modes that don't use > > jit-lock-context at all. ] > > jit-lock doesn't use window-end. It can't, really: the results of > fontification could affect where the window ends, which is why > window-end is only updated when redisplay of a window successfully > finishes, which is way after jit-lock did its job. > > That is why jit-lock calls fontification-functions with END that is > arbitrarily computed from START; this is controlled by > jit-lock-chunk-size. And a function called via > fontification-functions could legitimately decide it fontifies more > than just the chunk for which it was called. And Eglot's eglot--update-hints is indeed one such function. The coalescing of small jit-lock chunks is very "generous" and it will request inlay hints for things in the middle that jit-lock didn't strictly think are necessary. This works out well in my testing with the latest version of the feature installed in emacs-29. > (Again, you already know all that. I'm writing this to avoid > potential misunderstandings and confusion.) Thanks for the clarifications. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-02-24 11:33 UTC (permalink / raw) To: João Távora Cc: monnier, dalal.chinmay.0101, emacs-devel, dimitri, luangruo > From: João Távora <joaotavora@gmail.com> > Date: Fri, 24 Feb 2023 10:42:26 +0000 > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, dalal.chinmay.0101@gmail.com, > emacs-devel@gnu.org, dimitri@belopopsky.com, luangruo@yahoo.com > > On Fri, Feb 24, 2023 at 7:35 AM Eli Zaretskii <eliz@gnu.org> wrote: > > > > If a jit-lock client is smart enough, it should itself install an > > after-change function to remove the 'fontified property from the > > portions of buffer text affected by a change that are before the first > > changed position (or maybe even in other buffers). > > Thanks, I was going to ask about that. I suppose this is how one > marks sections of a buffer "dirty" or invalidatest them so that > jit-lock knows it must run over them again when it sees fit. > > If it works with other buffers as well, it might provide an > elegant solution to the "A affects B" scenario we discussed > earlier. I don't see why it wouldn't work. jit-lock relies on the 'fontified' property to know which part(s) of buffer text need (re-)fontification when they are about to be shown on display. So any portion of buffer text where this property is nil will cause jit-lock to call fontification-functions on that part. ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-24 11:33 ` Eli Zaretskii @ 2023-02-24 12:26 ` João Távora 0 siblings, 0 replies; 44+ messages in thread From: João Távora @ 2023-02-24 12:26 UTC (permalink / raw) To: Eli Zaretskii; +Cc: monnier, dalal.chinmay.0101, emacs-devel, dimitri, luangruo On Fri, Feb 24, 2023 at 11:33 AM Eli Zaretskii <eliz@gnu.org> wrote: > > > From: João Távora <joaotavora@gmail.com> > > Date: Fri, 24 Feb 2023 10:42:26 +0000 > > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, dalal.chinmay.0101@gmail.com, > > emacs-devel@gnu.org, dimitri@belopopsky.com, luangruo@yahoo.com > > > > On Fri, Feb 24, 2023 at 7:35 AM Eli Zaretskii <eliz@gnu.org> wrote: > > > > > > If a jit-lock client is smart enough, it should itself install an > > > after-change function to remove the 'fontified property from the > > > portions of buffer text affected by a change that are before the first > > > changed position (or maybe even in other buffers). > > > > Thanks, I was going to ask about that. I suppose this is how one > > marks sections of a buffer "dirty" or invalidatest them so that > > jit-lock knows it must run over them again when it sees fit. > > > > If it works with other buffers as well, it might provide an > > elegant solution to the "A affects B" scenario we discussed > > earlier. > > I don't see why it wouldn't work. Yes. I never said it wouldn't :-) (and you never said I said, I'm just clarifying :-). Anyway, there is also this to this topic. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_inlayHint_refresh an "inlay hint refresh request" from the server. A separate capability apparently designed to cover this case. I don't know how it fits into the equation but I would think it was designed for editors with none of our jit-capabilities. Maybe it's mostly useless to us now, especially given its poor interface (it's just a bare request with no parameters). It does illustrate the typical LSP line of reasoning: "the server knows best, because the server knows the language". IOWs the LSP server knowledge stands for Emacs major-mode knowledge. The difference here is that the interfaces to extract that knowledge from the server are very limited or poorly designed. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 10:17 ` Tassilo Horn 2023-02-23 12:55 ` Chinmay Dalal ` (2 subsequent siblings) 5 siblings, 0 replies; 44+ messages in thread From: Tassilo Horn @ 2023-02-23 10:17 UTC (permalink / raw) To: emacs-devel João Távora <joaotavora@gmail.com> writes: Hi João, > I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the > emacs-29 branch. It's a feature that some users (including me) were > looking for for some time. I've just tried it out within a rust project of mine and it's fabulous! Thanks a lot. Bye, Tassilo ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-22 19:42 ` Eglot "inlay hints" landed João Távora ` (2 preceding siblings ...) 2023-02-23 10:17 ` Tassilo Horn @ 2023-02-23 12:55 ` Chinmay Dalal 2023-02-23 19:50 ` Nikola Pajkovsky 2023-02-27 22:50 ` Johann Klähn 5 siblings, 0 replies; 44+ messages in thread From: Chinmay Dalal @ 2023-02-23 12:55 UTC (permalink / raw) To: João Távora Cc: emacs-devel, Dimitri Belopopsky, Po Lu, Eli Zaretskii I've come to realize that the pop-in is not a real problem - if one is to read the information provided by the hints they have to spend time doing that anyway Chinmay ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-22 19:42 ` Eglot "inlay hints" landed João Távora ` (3 preceding siblings ...) 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-27 22:50 ` Johann Klähn 5 siblings, 1 reply; 44+ messages in thread From: Nikola Pajkovsky @ 2023-02-23 19:50 UTC (permalink / raw) To: João Távora Cc: emacs-devel, Dimitri Belopopsky, Chinmay Dalal, Po Lu, Eli Zaretskii João Távora <joaotavora@gmail.com> writes: > I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the > emacs-29 branch. It's a feature that some users (including me) were > looking for for some time. Nice work João! I tried rust inlay hints, and it does not work for me. I bet it's because eglot uses label only if it's string. The same problem was in lsp-mode. https://github.com/emacs-lsp/lsp-mode/commit/6b01d49757994c09c90623bf67f072d02f00f8e9 -- Nikola ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 0 siblings, 2 replies; 44+ messages in thread From: João Távora @ 2023-02-23 21:35 UTC (permalink / raw) To: Nikola Pajkovsky Cc: emacs-devel, Dimitri Belopopsky, Chinmay Dalal, Po Lu, Eli Zaretskii On Thu, Feb 23, 2023 at 7:50 PM Nikola Pajkovsky <n.pajkovsky@gmail.com> wrote: > > João Távora <joaotavora@gmail.com> writes: > > > I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the > > emacs-29 branch. It's a feature that some users (including me) were > > looking for for some time. > > Nice work João! > > I tried rust inlay hints, and it does not work for me. I bet it's because > eglot uses label only if it's string. The same problem was in lsp-mode. Actually, I think I have code for that. So please show a reproduction recipe. I think someone reported here that hints are working correctly with rust-analyzer, and I've tried it briefly myself with good results. So it must be something else. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-23 21:35 ` João Távora @ 2023-02-23 21:45 ` Nikola Pajkovsky 2023-02-24 4:20 ` Chinmay Dalal 1 sibling, 0 replies; 44+ messages in thread From: Nikola Pajkovsky @ 2023-02-23 21:45 UTC (permalink / raw) To: João Távora Cc: Nikola Pajkovsky, emacs-devel, Dimitri Belopopsky, Chinmay Dalal, Po Lu, Eli Zaretskii João Távora <joaotavora@gmail.com> writes: > On Thu, Feb 23, 2023 at 7:50 PM Nikola Pajkovsky <n.pajkovsky@gmail.com> wrote: >> >> João Távora <joaotavora@gmail.com> writes: >> >> > I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the >> > emacs-29 branch. It's a feature that some users (including me) were >> > looking for for some time. >> >> Nice work João! >> >> I tried rust inlay hints, and it does not work for me. I bet it's because >> eglot uses label only if it's string. The same problem was in lsp-mode. > > Actually, I think I have code for that. So please show a reproduction > recipe. I think someone reported here that hints are working > correctly with rust-analyzer, and I've tried it briefly myself with good > results. So it must be something else. Interesting. ``` -> % rust-analyzer --version rust-analyzer 0.3.1402-standalone ``` For instance, I don't see the inlay hints for the code like this: ``` struct Foo { b: u32, } fn main() { let s = Foo { b: 10 }; let f = std::fs::File::create("t"); } ``` ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 1 sibling, 2 replies; 44+ messages in thread From: Chinmay Dalal @ 2023-02-24 4:20 UTC (permalink / raw) To: João Távora Cc: Nikola Pajkovsky, emacs-devel, Dimitri Belopopsky, Po Lu, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 1830 bytes --] João Távora <joaotavora@gmail.com> writes: > On Thu, Feb 23, 2023 at 7:50 PM Nikola Pajkovsky <n.pajkovsky@gmail.com> wrote: >> >> João Távora <joaotavora@gmail.com> writes: >> >> > I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the >> > emacs-29 branch. It's a feature that some users (including me) were >> > looking for for some time. >> >> Nice work João! >> >> I tried rust inlay hints, and it does not work for me. I bet it's because >> eglot uses label only if it's string. The same problem was in lsp-mode. > > Actually, I think I have code for that. So please show a reproduction > recipe. I think someone reported here that hints are working > correctly with rust-analyzer, and I've tried it briefly myself with good > results. So it must be something else. > > João You can look at the end of any long rust function with hl-line-mode on: there's an empty overlay but it's supposed to have a link to the beginning of the function. Screenshot attached. I think the bug is in eglot--update-hints-1: (if (stringp label) label (plist-get label :value)) It should instead be the value of :value from the _first element_ of label, as the spec says a label is a string or a _list of_ `InlayHintLabelPart`s: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint The response from the server is of this form: (:position (:line 95 :character 1) :label [(:value "fn keyboard_interrupt_handler" :location (:uri "file:///home/chinmay/stuff/rust/blog_os/src/interrupts.rs" :range (:start (:line 67 :character 26) :end (:line 67 :character 52))))] :tooltip "fn keyboard_interrupt_handler" :paddingLeft t :paddingRight :json-false) [-- Attachment #2: empty overlay --] [-- Type: image/png, Size: 1424 bytes --] ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-24 4:20 ` Chinmay Dalal @ 2023-02-24 5:04 ` Chinmay Dalal 2023-02-24 9:59 ` João Távora 1 sibling, 0 replies; 44+ messages in thread From: Chinmay Dalal @ 2023-02-24 5:04 UTC (permalink / raw) To: João Távora Cc: Nikola Pajkovsky, emacs-devel, Dimitri Belopopsky, Po Lu, Eli Zaretskii Chinmay Dalal <dalal.chinmay.0101@gmail.com> writes: > João Távora <joaotavora@gmail.com> writes: > >> On Thu, Feb 23, 2023 at 7:50 PM Nikola Pajkovsky <n.pajkovsky@gmail.com> wrote: >>> >>> João Távora <joaotavora@gmail.com> writes: >>> >>> > I've just landed Eglot "inlay hints" on lisp/progmodes/eglot.el in the >>> > emacs-29 branch. It's a feature that some users (including me) were >>> > looking for for some time. >>> >>> Nice work João! >>> >>> I tried rust inlay hints, and it does not work for me. I bet it's because >>> eglot uses label only if it's string. The same problem was in lsp-mode. >> >> Actually, I think I have code for that. So please show a reproduction >> recipe. I think someone reported here that hints are working >> correctly with rust-analyzer, and I've tried it briefly myself with good >> results. So it must be something else. >> >> João > > > You can look at the end of any long rust function with hl-line-mode on: > there's an empty overlay but it's supposed to have a link to the > beginning of the function. Screenshot attached. > > I think the bug is in eglot--update-hints-1: > > (if (stringp label) label (plist-get label :value)) > > It should instead be the value of :value from the _first element_ of > label, as the spec says a label is a string or a _list of_ `InlayHintLabelPart`s: > > https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint > > The response from the server is of this form: > > (:position (:line 95 :character 1) > :label [(:value "fn keyboard_interrupt_handler" > :location (:uri "file:///home/chinmay/stuff/rust/blog_os/src/interrupts.rs" > :range (:start (:line 67 :character 26) > :end (:line 67 :character 52))))] > :tooltip "fn keyboard_interrupt_handler" > :paddingLeft t > :paddingRight > :json-false) > > > [2. empty overlay --- image/png; swappy-20230224-100015.png]... Of course, this is not ideal when there are multiple elements in the label list (but not strictly wrong either). I raised this point when I opened bug#61412: https://mail.gnu.org/archive/html/bug-gnu-emacs/2023-02/msg00760.html Also, can the clickable link be actually implemented using the `keymap` property of overlays: https://www.gnu.org/software/emacs/manual/html_node/elisp/Special-Properties.html#index-keymap-of-character instead of just displaying the text? Chinmay ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 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 1 sibling, 1 reply; 44+ messages in thread From: João Távora @ 2023-02-24 9:59 UTC (permalink / raw) To: Chinmay Dalal Cc: Nikola Pajkovsky, emacs-devel, Dimitri Belopopsky, Po Lu, Eli Zaretskii On Fri, Feb 24, 2023 at 4:30 AM Chinmay Dalal <dalal.chinmay.0101@gmail.com> wrote: > You can look at the end of any long rust function with hl-line-mode on: > there's an empty overlay but it's supposed to have a link to the > beginning of the function. Screenshot attached. > > I think the bug is in eglot--update-hints-1: > > (if (stringp label) label (plist-get label :value)) > > It should instead be the value of :value from the _first element_ of > label, as the spec says a label is a string or a _list of_ `InlayHintLabelPart`s: Nice catch! Indeed I missed that. > Of course, this is not ideal when there are multiple elements in the > label list (but not strictly wrong either). Yeah, for now let's stick to the first. I don't know how to interpret "multiple hints" for the same "language element", in Emacs at least. What do other editors do? > Also, can the clickable link be actually implemented using the `keymap` > property of overlays: > https://www.gnu.org/software/emacs/manual/html_node/elisp/Special-Properties.html#index-keymap-of-character > instead of just displaying the text? Probably yes. João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-24 9:59 ` João Távora @ 2023-02-24 11:03 ` Nikola Pajkovsky 0 siblings, 0 replies; 44+ messages in thread From: Nikola Pajkovsky @ 2023-02-24 11:03 UTC (permalink / raw) To: João Távora Cc: Chinmay Dalal, Nikola Pajkovsky, emacs-devel, Dimitri Belopopsky, Po Lu, Eli Zaretskii João Távora <joaotavora@gmail.com> writes: > On Fri, Feb 24, 2023 at 4:30 AM Chinmay Dalal > <dalal.chinmay.0101@gmail.com> wrote: > >> You can look at the end of any long rust function with hl-line-mode on: >> there's an empty overlay but it's supposed to have a link to the >> beginning of the function. Screenshot attached. >> >> I think the bug is in eglot--update-hints-1: >> >> (if (stringp label) label (plist-get label :value)) >> >> It should instead be the value of :value from the _first element_ of >> label, as the spec says a label is a string or a _list of_ `InlayHintLabelPart`s: > > Nice catch! Indeed I missed that. > >> Of course, this is not ideal when there are multiple elements in the >> label list (but not strictly wrong either). > > Yeah, for now let's stick to the first. I don't know how to interpret > "multiple hints" for the same "language element", in Emacs at least. > What do other editors do? What I have done for lsp-mode is that I have joined all labels from `InlayHintsLabelPart`, and printed out the result. That works like a charm but probably not the best solution. >> Also, can the clickable link be actually implemented using the `keymap` >> property of overlays: >> https://www.gnu.org/software/emacs/manual/html_node/elisp/Special-Properties.html#index-keymap-of-character >> instead of just displaying the text? > > Probably yes. > > João ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Eglot "inlay hints" landed 2023-02-22 19:42 ` Eglot "inlay hints" landed João Távora ` (4 preceding siblings ...) 2023-02-23 19:50 ` Nikola Pajkovsky @ 2023-02-27 22:50 ` Johann Klähn 5 siblings, 0 replies; 44+ messages in thread From: Johann Klähn @ 2023-02-27 22:50 UTC (permalink / raw) To: emacs-devel Works great, thanks! AFAICT ‘(and paddingLeft …)’ in eglot--update-hints-1 should check for :json-false, though. ^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2023-02-27 22:50 UTC | newest] Thread overview: 44+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [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 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
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).