all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
@ 2023-05-05 11:56 Felician Nemeth
  2023-05-05 13:18 ` Ruijie Yu via Emacs development discussions.
  2023-05-05 13:26 ` Eli Zaretskii
  0 siblings, 2 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-05 11:56 UTC (permalink / raw)
  To: emacs-devel; +Cc: João Távora

I'd like to submit a new package called eglot-x to ELPA.  Its commentary
starts with:

;; Eglot supports (a subset of) the Language Server Protocol.  However,
;; there are useful protocol extensions that are not part of the
;; official protocol specification.  Eglot-x adds support for some of
;; them.  If you find a bug in Eglot, please, try to reproduce it
;; without Eglot-x, because Eglot-x is substantially modifies Eglot's
;; normal behavior as well.

João intend to support only the standardized protocol features in
eglot.el, but lots of LSP servers extend the protocol in their own way.
(It was João who suggested the package name long ago.)  I considered
eglot-x just an experiment and a learning possibility, but people seem
to use it, so I'd like to make their life easier by this submission.

Currently, it mainly implements extensions for rust-analyzer and taplo,
but some other extensions are supported as well.

The package is hosted at https://github.com/nemethf/eglot-x

Thanks,
Felicián



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 11:56 [GNU ELPA] eglot-x.el: Protocol extensions for Eglot Felician Nemeth
@ 2023-05-05 13:18 ` Ruijie Yu via Emacs development discussions.
  2023-05-06 13:14   ` Felician Nemeth
  2023-05-05 13:26 ` Eli Zaretskii
  1 sibling, 1 reply; 20+ messages in thread
From: Ruijie Yu via Emacs development discussions. @ 2023-05-05 13:18 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: João Távora, emacs-devel

Didn't look into its sources, but the idea definitely sounds good.  Some
in-line comments below regarding the commentary you attached.

Felician Nemeth <felician.nemeth@gmail.com> writes:

> I'd like to submit a new package called eglot-x to ELPA.  Its commentary
> starts with:
>
> ;; Eglot supports (a subset of) the Language Server Protocol.  However,

I think you should mention (as you did down below) that eglot only
supports standardized protocol features of the LSP, in particular,
_nothing more_ -- hence your package to support commonly-used, yet not
standardized protocol specs.  Thoughts?

> ;; there are useful protocol extensions that are not part of the
> ;; official protocol specification.  Eglot-x adds support for some of
> ;; them.  If you find a bug in Eglot, please, try to reproduce it

New paragraph here at "if"?

> ;; without Eglot-x, because Eglot-x is substantially modifies Eglot's

Syntax: change "is substantially modifies" into either "substantially
modifies" or "has substantially modified".

> ;; normal behavior as well.
>
> João intend to support only the standardized protocol features in
> eglot.el, but lots of LSP servers extend the protocol in their own way.
> (It was João who suggested the package name long ago.)  I considered
> eglot-x just an experiment and a learning possibility, but people seem
> to use it, so I'd like to make their life easier by this submission.
>
> Currently, it mainly implements extensions for rust-analyzer and taplo,
> but some other extensions are supported as well.
>
> The package is hosted at https://github.com/nemethf/eglot-x
>
> Thanks,
> Felicián

-- 
Best,


RY



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 11:56 [GNU ELPA] eglot-x.el: Protocol extensions for Eglot Felician Nemeth
  2023-05-05 13:18 ` Ruijie Yu via Emacs development discussions.
@ 2023-05-05 13:26 ` Eli Zaretskii
  2023-05-05 14:20   ` João Távora
  2023-05-05 16:38   ` Philip Kaludercic
  1 sibling, 2 replies; 20+ messages in thread
From: Eli Zaretskii @ 2023-05-05 13:26 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: emacs-devel, joaotavora

> From: Felician Nemeth <felician.nemeth@gmail.com>
> Cc: João Távora <joaotavora@gmail.com>
> Date: Fri, 05 May 2023 13:56:21 +0200
> 
> I'd like to submit a new package called eglot-x to ELPA.  Its commentary
> starts with:
> 
> ;; Eglot supports (a subset of) the Language Server Protocol.  However,
> ;; there are useful protocol extensions that are not part of the
> ;; official protocol specification.  Eglot-x adds support for some of
> ;; them.  If you find a bug in Eglot, please, try to reproduce it
> ;; without Eglot-x, because Eglot-x is substantially modifies Eglot's
> ;; normal behavior as well.
> 
> João intend to support only the standardized protocol features in
> eglot.el, but lots of LSP servers extend the protocol in their own way.
> (It was João who suggested the package name long ago.)  I considered
> eglot-x just an experiment and a learning possibility, but people seem
> to use it, so I'd like to make their life easier by this submission.

It sounds strange to me to refuse to support LSP extensions in
eglot.el.  At the very least, eglot.el could benefit from offering a
supported mechanism for adding such extensions; there should be no
need for using advice for that.

João, why would you not consider supporting these extensions as part
of eglot.el?



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 13:26 ` Eli Zaretskii
@ 2023-05-05 14:20   ` João Távora
  2023-05-05 14:39     ` Eli Zaretskii
  2023-05-05 16:38   ` Philip Kaludercic
  1 sibling, 1 reply; 20+ messages in thread
From: João Távora @ 2023-05-05 14:20 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Felician Nemeth, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> João intend to support only the standardized protocol features in
>> eglot.el, but lots of LSP servers extend the protocol in their own way.
>> (It was João who suggested the package name long ago.)  I considered
>> eglot-x just an experiment and a learning possibility, but people seem
>> to use it, so I'd like to make their life easier by this submission.
>
> It sounds strange to me to refuse to support LSP extensions in
> eglot.el.

Noone "refused" anything.  Some years ago, Felicián and I came to this
agreement.  If there is an actual patch for eglot.el being proposed, I
can review it.  Felicián has contributed much code for eglot.el and they
are very appreciated.

> At the very least, eglot.el could benefit from offering a
> supported mechanism for adding such extensions; there should be no
> need for using advice for that.

I agree.  Eglot has an API.  I haven't looked at eglot-x in depth but I
suspect it's using some of this API in part.  If it's not sufficient,
then Eglot could enhance it.  What part of eglot-x is using advice, if
any?

> João, why would you not consider supporting these extensions as part
> of eglot.el?

They're non-standard, each server has its own set of extensions, which
in some cases could be volatile and become obsolete.  Furthermore, I
would suspect that if eglot-x.el modifies eglot.el's standard behaviour,
it is not as well tested across different servers and could provide a
surprise for users of other servers.

A guiding principle of eglot.el (and indede LSP) is to not have any
server-specific code.

The only such (reasonably manageable) exception is the
eglot-server-programs variable.  But even this variable should ideally be
dissipated across settings in major modes, as was frequently suggested
for gdscript.el mode with much success.  I plan to spin it off to a new
file in the near future, as it is growing very fast.

Furthermore, I presume some of these extensions need some kind of
user-facing UI, and Eglot is conservative about that.  As frequently
explained, I generally prefer using non-LSP generic UIs that integrate
well with all parts of Emacs.  Fine tuning the design of such UIs takes
time and care.

So in general, I think having eglot-x.el as a kind of laboratory where
authors can experiment freely with new LSP-powered UIs is an excellent
approach.  As these extensions make their way into the official LSP
protocol Eglot can support them.  For example, I believe "inlay hints"
started as some kind of rust-specific protocol extension and is now
well-supported in Eglot for many servers (I use it daily).

We could consider bundling eglot-x.el with the Eglot ELPA package (I do
hope Felicián is aware of the ins and outs of :core packages though).
And I think a separate package isn't really bad either.

João



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 14:20   ` João Távora
@ 2023-05-05 14:39     ` Eli Zaretskii
  2023-05-05 16:41       ` João Távora
  0 siblings, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2023-05-05 14:39 UTC (permalink / raw)
  To: João Távora; +Cc: felician.nemeth, emacs-devel

> From: João Távora <joaotavora@gmail.com>
> Cc: Felician Nemeth <felician.nemeth@gmail.com>,  emacs-devel@gnu.org
> Date: Fri, 05 May 2023 15:20:21 +0100
> 
> > At the very least, eglot.el could benefit from offering a
> > supported mechanism for adding such extensions; there should be no
> > need for using advice for that.
> 
> I agree.  Eglot has an API.  I haven't looked at eglot-x in depth but I
> suspect it's using some of this API in part.  If it's not sufficient,
> then Eglot could enhance it.  What part of eglot-x is using advice, if
> any?
> 
> > João, why would you not consider supporting these extensions as part
> > of eglot.el?
> 
> They're non-standard, each server has its own set of extensions, which
> in some cases could be volatile and become obsolete.  Furthermore, I
> would suspect that if eglot-x.el modifies eglot.el's standard behaviour,
> it is not as well tested across different servers and could provide a
> surprise for users of other servers.

I understand and agree in general, but surely each change should be
judged by itself, and some, maybe many, might not have these
problematic aspects?

> A guiding principle of eglot.el (and indede LSP) is to not have any
> server-specific code.

If "server-specific" behavior is, for example, just some non-standard
capabilities, that doesn't count as "server-specific code" in my book.
After all, a standard-compliant server could very well implement only
a subset of the capabilities documented by the standard.

> So in general, I think having eglot-x.el as a kind of laboratory where
> authors can experiment freely with new LSP-powered UIs is an excellent
> approach.  As these extensions make their way into the official LSP
> protocol Eglot can support them.  For example, I believe "inlay hints"
> started as some kind of rust-specific protocol extension and is now
> well-supported in Eglot for many servers (I use it daily).
> 
> We could consider bundling eglot-x.el with the Eglot ELPA package (I do
> hope Felicián is aware of the ins and outs of :core packages though).
> And I think a separate package isn't really bad either.

But it should not use advice, IMNSHO.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 13:26 ` Eli Zaretskii
  2023-05-05 14:20   ` João Távora
@ 2023-05-05 16:38   ` Philip Kaludercic
  1 sibling, 0 replies; 20+ messages in thread
From: Philip Kaludercic @ 2023-05-05 16:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Felician Nemeth, emacs-devel, joaotavora

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Felician Nemeth <felician.nemeth@gmail.com>
>> Cc: João Távora <joaotavora@gmail.com>
>> Date: Fri, 05 May 2023 13:56:21 +0200
>> 
>> I'd like to submit a new package called eglot-x to ELPA.  Its commentary
>> starts with:
>> 
>> ;; Eglot supports (a subset of) the Language Server Protocol.  However,
>> ;; there are useful protocol extensions that are not part of the
>> ;; official protocol specification.  Eglot-x adds support for some of
>> ;; them.  If you find a bug in Eglot, please, try to reproduce it
>> ;; without Eglot-x, because Eglot-x is substantially modifies Eglot's
>> ;; normal behavior as well.
>> 
>> João intend to support only the standardized protocol features in
>> eglot.el, but lots of LSP servers extend the protocol in their own way.
>> (It was João who suggested the package name long ago.)  I considered
>> eglot-x just an experiment and a learning possibility, but people seem
>> to use it, so I'd like to make their life easier by this submission.
>
> It sounds strange to me to refuse to support LSP extensions in
> eglot.el.  At the very least, eglot.el could benefit from offering a
> supported mechanism for adding such extensions; there should be no
> need for using advice for that.
>
> João, why would you not consider supporting these extensions as part
> of eglot.el?

I think that it makes sense to have non-standard and perhaps not even
well specified (?) extensions to LSP as part of a separate package that
is not part of the core, so that it can adjust to changes in the
implementations that provide these extensions more quickly.  I don't
know what the working procedure is for LSP, but if they do get added to
the standard, it should be easy to move the code from eglot-x to eglot,
if the package is on GNU ELPA.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 14:39     ` Eli Zaretskii
@ 2023-05-05 16:41       ` João Távora
  2023-05-06 13:12         ` Felician Nemeth
  0 siblings, 1 reply; 20+ messages in thread
From: João Távora @ 2023-05-05 16:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: felician.nemeth, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> I understand and agree in general, but surely each change should be
> judged by itself, and some, maybe many, might not have these
> problematic aspects?

Right.  Each change can be judged by itself.

>> A guiding principle of eglot.el (and indede LSP) is to not have any
>> server-specific code.
>
> If "server-specific" behavior is, for example, just some non-standard
> capabilities, that doesn't count as "server-specific code" in my book.
> After all, a standard-compliant server could very well implement only
> a subset of the capabilities documented by the standard.

Right, again.  Each change should be judged on its own merits.

> But it should not use advice, IMNSHO.

Agree.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 16:41       ` João Távora
@ 2023-05-06 13:12         ` Felician Nemeth
  2023-05-06 13:27           ` Eli Zaretskii
  2023-05-06 13:51           ` [GNU ELPA] eglot-x.el: Protocol extensions for Eglot João Távora
  0 siblings, 2 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-06 13:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: João Távora, emacs-devel

I can surely try to submit these extension one-by-one as patches to
Eglot, but my first attempt was friendly rejected, so I think a package
collecting these rejected extension is a good thing.  Also, even my
patches implementing standard LSP features take a long time to be
processed, so temporarily collecting some extensions in the eglot-x
package allows me to work in my own pace.

Sometime ago, I collected the internal variables, functions, and advised
functions that eglot-x uses from Eglot in order to help to refine
Eglot's public API:

  https://github.com/joaotavora/eglot/discussions/802#discussioncomment-2171239

If it helps, I can explain one by one why it was necessary to use them.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-05 13:18 ` Ruijie Yu via Emacs development discussions.
@ 2023-05-06 13:14   ` Felician Nemeth
  0 siblings, 0 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-06 13:14 UTC (permalink / raw)
  To: Ruijie Yu; +Cc: João Távora, emacs-devel

Thanks for your comments.  I'll update the README based on this
feedback.

Ruijie Yu <ruijie@netyu.xyz> writes:

> Didn't look into its sources, but the idea definitely sounds good.  Some
> in-line comments below regarding the commentary you attached.
>
> Felician Nemeth <felician.nemeth@gmail.com> writes:
>
>> I'd like to submit a new package called eglot-x to ELPA.  Its commentary
>> starts with:
>>
>> ;; Eglot supports (a subset of) the Language Server Protocol.  However,
>
> I think you should mention (as you did down below) that eglot only
> supports standardized protocol features of the LSP, in particular,
> _nothing more_ -- hence your package to support commonly-used, yet not
> standardized protocol specs.  Thoughts?
>
>> ;; there are useful protocol extensions that are not part of the
>> ;; official protocol specification.  Eglot-x adds support for some of
>> ;; them.  If you find a bug in Eglot, please, try to reproduce it
>
> New paragraph here at "if"?
>
>> ;; without Eglot-x, because Eglot-x is substantially modifies Eglot's
>
> Syntax: change "is substantially modifies" into either "substantially
> modifies" or "has substantially modified".
>
>> ;; normal behavior as well.
>>
>> João intend to support only the standardized protocol features in
>> eglot.el, but lots of LSP servers extend the protocol in their own way.
>> (It was João who suggested the package name long ago.)  I considered
>> eglot-x just an experiment and a learning possibility, but people seem
>> to use it, so I'd like to make their life easier by this submission.
>>
>> Currently, it mainly implements extensions for rust-analyzer and taplo,
>> but some other extensions are supported as well.
>>
>> The package is hosted at https://github.com/nemethf/eglot-x
>>
>> Thanks,
>> Felicián



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-06 13:12         ` Felician Nemeth
@ 2023-05-06 13:27           ` Eli Zaretskii
  2023-05-06 15:17             ` Felician Nemeth
  2023-05-06 13:51           ` [GNU ELPA] eglot-x.el: Protocol extensions for Eglot João Távora
  1 sibling, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2023-05-06 13:27 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: joaotavora, emacs-devel

> From: Felician Nemeth <felician.nemeth@gmail.com>
> Cc: João Távora <joaotavora@gmail.com>,
>   emacs-devel@gnu.org
> Date: Sat, 06 May 2023 15:12:14 +0200
> 
> I can surely try to submit these extension one-by-one as patches to
> Eglot, but my first attempt was friendly rejected, so I think a package
> collecting these rejected extension is a good thing.  Also, even my
> patches implementing standard LSP features take a long time to be
> processed, so temporarily collecting some extensions in the eglot-x
> package allows me to work in my own pace.

Since Eglot is now part of Emacs, the situation has changed.  IMO, it
is no longer reasonable to have extensions that cannot be possibly
supported by the version of Eglot that comes with Emacs.  IOW, if
someone wants to download and install your extensions, we should try
not to force them to also download and install a newer version of
Eglot from ELPA.  I hope this is possible.

> Sometime ago, I collected the internal variables, functions, and advised
> functions that eglot-x uses from Eglot in order to help to refine
> Eglot's public API:
> 
>   https://github.com/joaotavora/eglot/discussions/802#discussioncomment-2171239
> 
> If it helps, I can explain one by one why it was necessary to use them.

What mechanisms aside of advice can be used to extend Eglot so that it
could optionally support those extensions?



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-06 13:12         ` Felician Nemeth
  2023-05-06 13:27           ` Eli Zaretskii
@ 2023-05-06 13:51           ` João Távora
  2023-05-06 15:28             ` Felician Nemeth
  1 sibling, 1 reply; 20+ messages in thread
From: João Távora @ 2023-05-06 13:51 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: Eli Zaretskii, emacs-devel

On Sat, May 6, 2023 at 2:12 PM Felician Nemeth
<felician.nemeth@gmail.com> wrote:
>
> I can surely try to submit these extension one-by-one as patches to
> Eglot, but my first attempt was friendly rejected, so I think a package
> collecting these rejected extension is a good thing.  Also, even my
> patches implementing standard LSP features take a long time to be
> processed, so temporarily collecting some extensions in the eglot-x
> package allows me to work in my own pace.

I don't recall the details (or the discussion, do you have the link?)
but looking at eglot-x I see around 10-20 new things, I don't remember
you submitting 10-20 new separate things.  So start with the one you think
is the most valuable, most popular, and has the  highest chance of
integration.

João



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-06 13:27           ` Eli Zaretskii
@ 2023-05-06 15:17             ` Felician Nemeth
  2023-05-06 15:27               ` Eli Zaretskii
  0 siblings, 1 reply; 20+ messages in thread
From: Felician Nemeth @ 2023-05-06 15:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: joaotavora, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> IMO, it is no longer reasonable to have extensions that cannot be
> possibly supported by the version of Eglot that comes with Emacs.
> IOW, if someone wants to download and install your extensions, we
> should try not to force them to also download and install a newer
> version of Eglot from ELPA.  I hope this is possible.

Yes, I think so.  I'll keep this in mind when I modify eglot-x.

> What mechanisms aside of advice can be used to extend Eglot so that it
> could optionally support those extensions?

1. Eglot support editing remote files when the source files and the LSP
   server are on the same remote system.  There is an extension that
   makes possible to edit files when the files and the server are on
   different systems.

   Eglot's own remote file support rewrites filenames, which interfered
   with my implementation.  My solution was basically to selective
   advice some Eglot functions to make file-remote-p always return nil.

   An alternative approach could be an Eglot configuration variable to
   optionally disable its tramp support.


2. There's a clangd extension for encoding negotiation.  The server
   sends the result of the negotiation in an InitializeResult response.
   Eglot saves the capabilities part of this response, which is usually
   enough, but this extension puts the negotiated encoding elsewhere.

   Eglot-x uses a series of add-advices calls to copy the encoding
   string into the exposed capabilities variable.

   An alternative approach for Eglot could be to save the whole
   InitializeResult response as well.

   However, the encoding negotiation extension has been standardized (in
   a slightly different way).  Eglot does support the standardized
   feature.  So maybe it is enough to wait a bit until clangd implements
   the new standard and then this feature can be removed from eglot-x.


3. Eglot uses the eglot--apply-text-edits defun to apply server
   initiated edits.  There is an extension that allows the server to
   send the edits in a different format (snippet-text-edits).

   Eglot-x puts an advise on eglot--apply-text-edits to check the format
   of the edits and act accordingly.

   I don't know how to avoid this advice.


4. Eglot-x puts an advice on eglot--mode-line-format in order to display
   the server's status (which the server sends if the client supports an
   LSP extension.)

   I think eglot-x should just use its own space in the mode line.  I
   think I just wasn't able to figure out how it could be put next to
   Eglot's mode-line.


5. Finally, eglot-x stores its own state in an instance of the
   eglot-lsp-server.  eglot-lsp-server is defined with defclass, so it
   is possible to add new slots to it without any problem.

   For some reason I just wanted to hide these eglot-x specific slots
   from Eglot.  It think the solution is to simply not use an advice
   here.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-06 15:17             ` Felician Nemeth
@ 2023-05-06 15:27               ` Eli Zaretskii
  2023-05-08 14:28                 ` bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function Felician Nemeth
  0 siblings, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2023-05-06 15:27 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: joaotavora, emacs-devel

> From: Felician Nemeth <felician.nemeth@gmail.com>
> Cc: joaotavora@gmail.com,  emacs-devel@gnu.org
> Date: Sat, 06 May 2023 17:17:14 +0200
> 
> 3. Eglot uses the eglot--apply-text-edits defun to apply server
>    initiated edits.  There is an extension that allows the server to
>    send the edits in a different format (snippet-text-edits).
> 
>    Eglot-x puts an advise on eglot--apply-text-edits to check the format
>    of the edits and act accordingly.
> 
>    I don't know how to avoid this advice.

Some hook or function variable, perhaps?  If they don't exist, perhaps
they could be added?




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [GNU ELPA] eglot-x.el: Protocol extensions for Eglot
  2023-05-06 13:51           ` [GNU ELPA] eglot-x.el: Protocol extensions for Eglot João Távora
@ 2023-05-06 15:28             ` Felician Nemeth
  0 siblings, 0 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-06 15:28 UTC (permalink / raw)
  To: João Távora; +Cc: Eli Zaretskii, emacs-devel

João Távora <joaotavora@gmail.com> writes:

> On Sat, May 6, 2023 at 2:12 PM Felician Nemeth
> <felician.nemeth@gmail.com> wrote:
>>
>> I can surely try to submit these extension one-by-one as patches to
>> Eglot, but my first attempt was friendly rejected, so I think a package
>> collecting these rejected extension is a good thing.  Also, even my
>> patches implementing standard LSP features take a long time to be
>> processed, so temporarily collecting some extensions in the eglot-x
>> package allows me to work in my own pace.
>
> I don't recall the details (or the discussion, do you have the link?)

All I was able to find is the following PR, which is not very helpful in
this regard: https://github.com/joaotavora/eglot/pull/211

> but looking at eglot-x I see around 10-20 new things, I don't remember
> you submitting 10-20 new separate things.  So start with the one you think
> is the most valuable, most popular, and has the  highest chance of
> integration.

Sure, but firstly my plan is to nudge you to deal with my patches
concerning standard LSP features and Eglot-enhancements :)



^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function
  2023-05-06 15:27               ` Eli Zaretskii
@ 2023-05-08 14:28                 ` Felician Nemeth
  2023-05-08 14:54                   ` Felician Nemeth
  2023-05-08 16:33                   ` João Távora
  0 siblings, 2 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-08 14:28 UTC (permalink / raw)
  To: 63372; +Cc: joaotavora, Eli Zaretskii

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

In https://lists.gnu.org/archive/html/emacs-devel/2023-05/msg00173.html
Eli Zaretskii <eliz@gnu.org> writes:

>> From: Felician Nemeth <felician.nemeth@gmail.com>
>> Cc: joaotavora@gmail.com,  emacs-devel@gnu.org
>> Date: Sat, 06 May 2023 17:17:14 +0200
>> 
>> 3. Eglot uses the eglot--apply-text-edits defun to apply server
>>    initiated edits.  There is an extension that allows the server to
>>    send the edits in a different format (snippet-text-edits).
>> 
>>    Eglot-x puts an advise on eglot--apply-text-edits to check the format
>>    of the edits and act accordingly.
>> 
>>    I don't know how to avoid this advice.
>
> Some hook or function variable, perhaps?  If they don't exist, perhaps
> they could be added?

I've attached a patch with my first attempt at this.  João, what do you
think of this approach?

(Independently of this issue, maybe a configurable
apply-workspace-edit-function would be useful as well.  One alternative
implementation of the current eglot--apply-workspace-edit could be to
apply all edits without asking for confirmation and then show a
`vc-diff'-like interface allowing the user to revert/accept all of the
changes with a single keystroke.)

Thank you.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-variable-eglot-apply-text-edits-function.patch --]
[-- Type: text/x-diff, Size: 1963 bytes --]

From 1a5c534a291a9ee247cb142a4816b75a9cff3ff1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felici=C3=A1n=20N=C3=A9meth?= <felician.nemeth@gmail.com>
Date: Mon, 8 May 2023 15:57:56 +0200
Subject: [PATCH] Add variable: eglot-apply-text-edits-function

This allows third parties to experiment with UI, or implement the
SnippetTextEdits LSP extension.

* lisp/progmodes/eglot.el (eglot-apply-text-edits-function): New
defvar defaulting to eglot--apply-lsp-text-edits.
(eglot--apply-text-edits): Delegate the editing task to
eglot-apply-text-edits-function.
(eglot--apply-lsp-text-edits): New defun containing most of the
old eglot--apply-text-edits.
---
 lisp/progmodes/eglot.el | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 95a5b325fb..eb79a8d2d3 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -895,6 +895,11 @@ eglot--language-ids
 (cl-defmethod initialize-instance :before ((_server eglot-lsp-server) &optional args)
   (cl-remf args :initializationOptions))
 
+(defvar eglot-apply-text-edits-function #'eglot--apply-lsp-text-edits
+  "Function to call to apply text edits to the current buffer.
+The fuction must have a single argument holding the \"edits\"
+value of a TextDocumentEdit LSP object, i.e., a TextEdit or an
+AnnotatedTextEdit LSP object.")
 
 ;;; Process management
 (defvar eglot--servers-by-project (make-hash-table :test #'equal)
@@ -3349,6 +3354,10 @@ eglot--apply-text-edits
   (unless (or (not version) (equal version eglot--versioned-identifier))
     (jsonrpc-error "Edits on `%s' require version %d, you have %d"
                    (current-buffer) version eglot--versioned-identifier))
+  (funcall eglot-apply-text-edits-function edits))
+
+(cl-defun eglot--apply-lsp-text-edits (edits)
+  "Apply EDITS for current buffer."
   (atomic-change-group
     (let* ((change-group (prepare-change-group))
            (howmany (length edits))
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function
  2023-05-08 14:28                 ` bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function Felician Nemeth
@ 2023-05-08 14:54                   ` Felician Nemeth
  2023-05-08 16:33                   ` João Távora
  1 sibling, 0 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-08 14:54 UTC (permalink / raw)
  To: 63372; +Cc: Eli Zaretskii, joaotavora

Felician Nemeth <felician.nemeth@gmail.com> writes:

> I've attached a patch with my first attempt at this.  João, what do you
> think of this approach?

I forgot to add that alternatively SnippetTextEdit support can be added
to Eglot as well.  The patch without the boring parts would look like
the following.

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index eb79a8d2d3..0a4738b3b9 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -3350,14 +3350,13 @@ eglot-imenu
 
 (cl-defun eglot--apply-text-edits (edits &optional version)
   "Apply EDITS for current buffer if at VERSION, or if it's nil."
+  ;; This is quite rust-analyzer specific.  It assumes there is at
+  ;; most one meaningful SnippetTextEdit and that can be identified by
+  ;; searching for "$0".
   (unless edits (cl-return-from eglot--apply-text-edits))
   (unless (or (not version) (equal version eglot--versioned-identifier))
     (jsonrpc-error "Edits on `%s' require version %d, you have %d"
                    (current-buffer) version eglot--versioned-identifier))
   (atomic-change-group
     (let* ((change-group (prepare-change-group))
            (howmany (length edits))
@@ -3366,7 +3365,7 @@ eglot--apply-lsp-text-edits
                               howmany (current-buffer))
                       0 howmany))
-           (done 0))
-      (mapc (pcase-lambda (`(,newText ,beg . ,end))
+           (done 0)
+           snippet snippet-beg snippet-end)
+      (mapc (pcase-lambda (`(,newText ,insertTextFormat (,beg . ,end)))
               (let ((source (current-buffer)))
                 (with-temp-buffer
                   (insert newText)
@@ -3375,11 +3374,30 @@ eglot--apply-lsp-text-edits
                       (save-excursion
                         (save-restriction
                           (narrow-to-region beg end)
-                          (replace-buffer-contents temp)))
+                          (replace-buffer-contents temp))
+                                                  (when (and (eql insertTextFormat 2)
+                                     (string-match "\\$\\(0\\|{0[^}]*}\\)"
+                                                   newText))
+                            ;; "At the moment, rust-analyzer
+                            ;; guarantees that only a single edit will
+                            ;; have InsertTextFormat.Snippet.", but:
+                            ;; https://github.com/rust-analyzer/rust-analyzer/issues/11006
+                            ;; Every one of them has insertTextFormat
+                            ;; = 2, and there's no easy, reliable way
+                            ;; to tell, which one contains a real
+                            ;; snippet. RA's own .ts implementation
+                            ;; uses the regexp above.
+                            (setq snippet newText)
+                            (setq snippet-beg (point-min-marker))
+                            (setq snippet-end (point-max-marker))))
                       (eglot--reporter-update reporter (cl-incf done)))))))
-            (mapcar (eglot--lambda ((TextEdit) range newText)
-                      (cons newText (eglot--range-region range 'markers)))
+            (mapcar (eglot--lambda ((SnippetTextEdit) range newText insertTextFormat)
+                      (list newText insertTextFormat (eglot--range-region range 'markers)))
                     (reverse edits)))
+      (when snippet
+        (goto-char snippet-beg)
+        (delete-region snippet-beg snippet-end)
+        (funcall (eglot--snippet-expansion-fn) snippet))
       (undo-amalgamate-change-group change-group)
       (progress-reporter-done reporter))))





^ permalink raw reply related	[flat|nested] 20+ messages in thread

* bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function
  2023-05-08 14:28                 ` bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function Felician Nemeth
  2023-05-08 14:54                   ` Felician Nemeth
@ 2023-05-08 16:33                   ` João Távora
  2023-05-10 19:35                     ` Felician Nemeth
  1 sibling, 1 reply; 20+ messages in thread
From: João Távora @ 2023-05-08 16:33 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: 63372, Eli Zaretskii

On Mon, May 8, 2023 at 3:30 PM Felician Nemeth
<felician.nemeth@gmail.com> wrote:
>
> In https://lists.gnu.org/archive/html/emacs-devel/2023-05/msg00173.html
> Eli Zaretskii <eliz@gnu.org> writes:
>
> >> From: Felician Nemeth <felician.nemeth@gmail.com>
> >> Cc: joaotavora@gmail.com,  emacs-devel@gnu.org
> >> Date: Sat, 06 May 2023 17:17:14 +0200
> >>
> >> 3. Eglot uses the eglot--apply-text-edits defun to apply server
> >>    initiated edits.  There is an extension that allows the server to
> >>    send the edits in a different format (snippet-text-edits).
> >>
> >>    Eglot-x puts an advise on eglot--apply-text-edits to check the format
> >>    of the edits and act accordingly.
> >>
> >>    I don't know how to avoid this advice.
> >
> > Some hook or function variable, perhaps?  If they don't exist, perhaps
> > they could be added?
>
> I've attached a patch with my first attempt at this.  João, what do you
> think of this approach?

It could work.  But I think   Some comments

? +(defvar eglot-apply-text-edits-function #'eglot--apply-lsp-text-edits

eglot--apply-lsp-text-edits should in theory be external, because it
is something pluggable on and off.

IME these things also tend lend themselves to "multiple handlers"
in the future, so maybe a generalized "special" hook (ending in
"functions", plural) is better.  Then some `run-hook-wrapped`
would iterate through it.

But then, I wonder, since most of Eglot's API is already CLOS
based, isn't a generic function best?  A generic function can
have :around methods, and if we follow the convention of
passing the server as the first argument, third parties
can make server-specific extensions.

Also, in some CLOS versions (not eieio.el's yet) there
are even method combinations that simulate hooks.

> +(cl-defun eglot--apply-lsp-text-edits (edits)
> +  "Apply EDITS for current buffer."
>    (atomic-change-group
>     (let* ((change-group (prepare-change-group))

Won't every "apply edit" function need this as boilerplate to
guarantee undo-stability?  Likely this should be popped to
around the call to the generic function.

> (Independently of this issue, maybe a configurable
> apply-workspace-edit-function would be useful as well.  One alternative
> implementation of the current eglot--apply-workspace-edit could be to
> apply all edits without asking for confirmation and then show a
> `vc-diff'-like interface allowing the user to revert/accept all of the
> changes with a single keystroke.)

If this is truly independent, request it in a different bug report
(or a different thread within this bug) with a different patch.
If it is not  independent, let's focus on the infrastructure functionality
first.

João





^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function
  2023-05-08 16:33                   ` João Távora
@ 2023-05-10 19:35                     ` Felician Nemeth
  2023-05-11 19:54                       ` João Távora
  0 siblings, 1 reply; 20+ messages in thread
From: Felician Nemeth @ 2023-05-10 19:35 UTC (permalink / raw)
  To: João Távora; +Cc: 63372, Eli Zaretskii

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

João Távora <joaotavora@gmail.com> writes:

>> >> 3. Eglot uses the eglot--apply-text-edits defun to apply server
>> >>    initiated edits.  There is an extension that allows the server to
>> >>    send the edits in a different format (snippet-text-edits).
>> >>
>> >>    Eglot-x puts an advise on eglot--apply-text-edits to check the format
>> >>    of the edits and act accordingly.
>> >>
>> >>    I don't know how to avoid this advice.
>> >
>> > Some hook or function variable, perhaps?  If they don't exist, perhaps
>> > they could be added?

> But then, I wonder, since most of Eglot's API is already CLOS
> based, isn't a generic function best?  A generic function can
> have :around methods, and if we follow the convention of
> passing the server as the first argument, third parties
> can make server-specific extensions.

You're right, I think.  In the attached patch, I simply changed
eglot--apply-text-edits to a cl-defgeneric and renamed it.  The patch is
straightforward, but I had to eliminate a cl-return-from call, because
generic functions don't seem to support that.

Thanks.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Eglot-Replace-eglot-apply-text-edits-with-a-public-f.patch --]
[-- Type: text/x-diff, Size: 7186 bytes --]

From 4c5e62c901ada66a1ad59e4484cd0be17af64aa4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felici=C3=A1n=20N=C3=A9meth?= <felician.nemeth@gmail.com>
Date: Wed, 10 May 2023 20:58:33 +0200
Subject: [PATCH] Eglot: Replace eglot--apply-text-edits with a public function

This allows third parties, for example, to cleanly implement the
non-standard snippet-text-edit feature.

* lisp/progmodes/eglot.el (eglot--apply-text-edits): Rename to ...
(eglot-apply-text-edits): ... this, also change to cl-defgeneric,
and relocate the code next to the other defgenerics.
(eglot--signal-textDocument/willSave, eglot-format)
(eglot-completion-at-point, eglot--apply-workspace-edit): Call
renamed function.
---
 lisp/progmodes/eglot.el | 81 +++++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 39 deletions(-)

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 32626634b7..1c26acfe1f 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -859,6 +859,37 @@ eglot-workspace-folders
                      :name (abbreviate-file-name dir)))
              `(,(project-root project) ,@(project-external-roots project))))))
 
+(cl-defgeneric eglot-apply-text-edits (_server edits &optional version)
+  "Apply EDITS for current buffer if at VERSION, or if it's nil."
+  (when edits
+    (unless (or (not version) (equal version eglot--versioned-identifier))
+      (jsonrpc-error "Edits on `%s' require version %d, you have %d"
+                     (current-buffer) version eglot--versioned-identifier))
+    (atomic-change-group
+      (let* ((change-group (prepare-change-group))
+             (howmany (length edits))
+             (reporter (make-progress-reporter
+                        (format "[eglot] applying %s edits to `%s'..."
+                                howmany (current-buffer))
+                        0 howmany))
+             (done 0))
+        (mapc (pcase-lambda (`(,newText ,beg . ,end))
+                (let ((source (current-buffer)))
+                  (with-temp-buffer
+                    (insert newText)
+                    (let ((temp (current-buffer)))
+                      (with-current-buffer source
+                        (save-excursion
+                          (save-restriction
+                            (narrow-to-region beg end)
+                            (replace-buffer-contents temp)))
+                        (eglot--reporter-update reporter (cl-incf done)))))))
+              (mapcar (eglot--lambda ((TextEdit) range newText)
+                        (cons newText (eglot--range-region range 'markers)))
+                      (reverse edits)))
+        (undo-amalgamate-change-group change-group)
+        (progress-reporter-done reporter)))))
+
 (defclass eglot-lsp-server (jsonrpc-process-connection)
   ((project-nickname
     :documentation "Short nickname for the associated project."
@@ -2680,9 +2711,9 @@ eglot--signal-textDocument/willSave
       (jsonrpc-notify server :textDocument/willSave params))
     (when (eglot--server-capable :textDocumentSync :willSaveWaitUntil)
       (ignore-errors
-        (eglot--apply-text-edits
-         (eglot--request server :textDocument/willSaveWaitUntil params
-                         :timeout 0.5))))))
+        (eglot-apply-text-edits
+         server (eglot--request server :textDocument/willSaveWaitUntil params
+                                :timeout 0.5))))))
 
 (defun eglot--signal-textDocument/didSave ()
   "Maybe send textDocument/didSave to server."
@@ -2945,11 +2976,13 @@ eglot-format
                    (:range ,(list :start (eglot--pos-to-lsp-position beg)
                                   :end (eglot--pos-to-lsp-position end)))))
                 (t
-                 '(:textDocument/formatting :documentFormattingProvider nil)))))
+                 '(:textDocument/formatting :documentFormattingProvider nil))))
+              (server (eglot--current-server-or-lose)))
     (eglot--server-capable-or-lose cap)
-    (eglot--apply-text-edits
+    (eglot-apply-text-edits
+     server
      (eglot--request
-      (eglot--current-server-or-lose)
+      server
       method
       (cl-list*
        :textDocument (eglot--TextDocumentIdentifier)
@@ -3172,7 +3205,7 @@ eglot-completion-at-point
                         (delete-region (- (point) (length proxy)) (point))
                         (funcall snippet-fn (or insertText label))))
                  (when (cl-plusp (length additionalTextEdits))
-                   (eglot--apply-text-edits additionalTextEdits)))
+                   (eglot-apply-text-edits server additionalTextEdits)))
                (eglot--signal-textDocument/didChange)))))))))
 
 (defun eglot--hover-info (contents &optional _range)
@@ -3351,37 +3384,6 @@ eglot-imenu
         (((SymbolInformation)) (eglot--imenu-SymbolInformation res))
         (((DocumentSymbol)) (eglot--imenu-DocumentSymbol res))))))
 
-(cl-defun eglot--apply-text-edits (edits &optional version)
-  "Apply EDITS for current buffer if at VERSION, or if it's nil."
-  (unless edits (cl-return-from eglot--apply-text-edits))
-  (unless (or (not version) (equal version eglot--versioned-identifier))
-    (jsonrpc-error "Edits on `%s' require version %d, you have %d"
-                   (current-buffer) version eglot--versioned-identifier))
-  (atomic-change-group
-    (let* ((change-group (prepare-change-group))
-           (howmany (length edits))
-           (reporter (make-progress-reporter
-                      (format "[eglot] applying %s edits to `%s'..."
-                              howmany (current-buffer))
-                      0 howmany))
-           (done 0))
-      (mapc (pcase-lambda (`(,newText ,beg . ,end))
-              (let ((source (current-buffer)))
-                (with-temp-buffer
-                  (insert newText)
-                  (let ((temp (current-buffer)))
-                    (with-current-buffer source
-                      (save-excursion
-                        (save-restriction
-                          (narrow-to-region beg end)
-                          (replace-buffer-contents temp)))
-                      (eglot--reporter-update reporter (cl-incf done)))))))
-            (mapcar (eglot--lambda ((TextEdit) range newText)
-                      (cons newText (eglot--range-region range 'markers)))
-                    (reverse edits)))
-      (undo-amalgamate-change-group change-group)
-      (progress-reporter-done reporter))))
-
 (defun eglot--apply-workspace-edit (wedit &optional confirm)
   "Apply the workspace edit WEDIT.  If CONFIRM, ask user first."
   (eglot--dbind ((WorkspaceEdit) changes documentChanges) wedit
@@ -3407,7 +3409,8 @@ eglot--apply-workspace-edit
       (cl-loop for edit in prepared
                for (path edits version) = edit
                do (with-current-buffer (find-file-noselect path)
-                    (eglot--apply-text-edits edits version))
+                    (eglot-apply-text-edits (eglot--current-server-or-lose)
+                                            edits version))
                finally (eldoc) (eglot--message "Edit successful!")))))
 
 (defun eglot-rename (newname)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function
  2023-05-10 19:35                     ` Felician Nemeth
@ 2023-05-11 19:54                       ` João Távora
  2023-05-15 20:03                         ` Felician Nemeth
  0 siblings, 1 reply; 20+ messages in thread
From: João Távora @ 2023-05-11 19:54 UTC (permalink / raw)
  To: Felician Nemeth; +Cc: 63372, Eli Zaretskii

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

After having another look at eglot-x.el i don't
think eglot--apply-text-edits (plural) is the right
place to put the generic.  You'd just repeat a lot
of code of the original, with no clear way to reuse it.

Maybe you want something more akin to the attached patch,
which introduces eglot-apply-text-edit (singular).  In your
override for this function you can check conditions to either
proceed with the non-standard edit or delegate to the default
implementation with (cl-call-next-method).

João

[-- Attachment #2: 0001-Eglot-allow-extensions-to-application-of-LSP-edits-b.patch --]
[-- Type: application/octet-stream, Size: 3543 bytes --]

From d51a12156b6278a1ff1f4dbf0d8991d79749ae00 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora@gmail.com>
Date: Thu, 11 May 2023 20:50:20 +0100
Subject: [PATCH] Eglot: allow extensions to application of LSP edits
 (bug#63372)

* lisp/progmodes/eglot.el (eglot-apply-text-edit): New function.
(eglot--apply-text-edits): Rework.
---
 lisp/progmodes/eglot.el | 47 ++++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index dc8d4674425..c045f71fe9b 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -843,6 +843,20 @@ eglot-workspace-folders
                      :name (abbreviate-file-name dir)))
              `(,(project-root project) ,@(project-external-roots project))))))
 
+(cl-defgeneric eglot-apply-text-edit (_server edit)
+  "Apply EDIT supplied by SERVER in current buffer."
+  (eglot--dbind ((TextEdit) range newText) edit
+    (cl-destructuring-bind (beg . end) (eglot--range-region range 'markers)
+      (let ((source (current-buffer)))
+        (with-temp-buffer
+          (insert newText)
+          (let ((temp (current-buffer)))
+            (with-current-buffer source
+              (save-excursion
+                (save-restriction
+                  (narrow-to-region beg end)
+                  (replace-buffer-contents temp))))))))))
+
 (defclass eglot-lsp-server (jsonrpc-process-connection)
   ((project-nickname
     :documentation "Short nickname for the associated project."
@@ -3327,29 +3341,18 @@ eglot--apply-text-edits
     (jsonrpc-error "Edits on `%s' require version %d, you have %d"
                    (current-buffer) version eglot--versioned-identifier))
   (atomic-change-group
-    (let* ((change-group (prepare-change-group))
-           (howmany (length edits))
-           (reporter (make-progress-reporter
+    (cl-loop
+     with change-group = (prepare-change-group)
+     with reporter = (make-progress-reporter
                       (format "[eglot] applying %s edits to `%s'..."
-                              howmany (current-buffer))
-                      0 howmany))
-           (done 0))
-      (mapc (pcase-lambda (`(,newText ,beg . ,end))
-              (let ((source (current-buffer)))
-                (with-temp-buffer
-                  (insert newText)
-                  (let ((temp (current-buffer)))
-                    (with-current-buffer source
-                      (save-excursion
-                        (save-restriction
-                          (narrow-to-region beg end)
-                          (replace-buffer-contents temp)))
-                      (eglot--reporter-update reporter (cl-incf done)))))))
-            (mapcar (eglot--lambda ((TextEdit) range newText)
-                      (cons newText (eglot--range-region range 'markers)))
-                    (reverse edits)))
-      (undo-amalgamate-change-group change-group)
-      (progress-reporter-done reporter))))
+                              (length edits) (current-buffer))
+                      0 (length edits))
+     for e across (reverse edits) for done from 1
+     do (eglot-apply-text-edit (eglot--current-server-or-lose) e)
+     (eglot--reporter-update reporter done)
+     finally
+     (undo-amalgamate-change-group change-group)
+     (progress-reporter-done reporter))))
 
 (defun eglot--apply-workspace-edit (wedit &optional confirm)
   "Apply the workspace edit WEDIT.  If CONFIRM, ask user first."
-- 
2.36.1.windows.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function
  2023-05-11 19:54                       ` João Távora
@ 2023-05-15 20:03                         ` Felician Nemeth
  0 siblings, 0 replies; 20+ messages in thread
From: Felician Nemeth @ 2023-05-15 20:03 UTC (permalink / raw)
  To: João Távora; +Cc: 63372, Eli Zaretskii

João Távora <joaotavora@gmail.com> writes:

> After having another look at eglot-x.el i don't
> think eglot--apply-text-edits (plural) is the right
> place to put the generic.  You'd just repeat a lot
> of code of the original, with no clear way to reuse it.
>
> Maybe you want something more akin to the attached patch,
> which introduces eglot-apply-text-edit (singular).  In your
> override for this function you can check conditions to either
> proceed with the non-standard edit or delegate to the default
> implementation with (cl-call-next-method).

Unfortunately, I think this won't help me cleanly implement the
snippet-text-edits feature.  The server can send many text-edits and at
most one of them can be a snippet-text-edit, which currently means that
it contains a "$0" to tell the client where to put the point after
applying the edits.

My implementation applied all the edits and save the snippet (if there
was any) for later use.  Then it called eglot--snippet-expansion-fn on
the saved snippet.  This way the user saw results of all the edits
before the snippet expansion.

If the latest patch is merged, then I can I override the singular
eglot-apply-text-edit, but I think I have no way to run a custom code
after all the edits are applied.

Thanks,
Felicián





^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2023-05-15 20:03 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-05 11:56 [GNU ELPA] eglot-x.el: Protocol extensions for Eglot Felician Nemeth
2023-05-05 13:18 ` Ruijie Yu via Emacs development discussions.
2023-05-06 13:14   ` Felician Nemeth
2023-05-05 13:26 ` Eli Zaretskii
2023-05-05 14:20   ` João Távora
2023-05-05 14:39     ` Eli Zaretskii
2023-05-05 16:41       ` João Távora
2023-05-06 13:12         ` Felician Nemeth
2023-05-06 13:27           ` Eli Zaretskii
2023-05-06 15:17             ` Felician Nemeth
2023-05-06 15:27               ` Eli Zaretskii
2023-05-08 14:28                 ` bug#63372: [PATCH] Add variable: eglot-apply-text-edits-function Felician Nemeth
2023-05-08 14:54                   ` Felician Nemeth
2023-05-08 16:33                   ` João Távora
2023-05-10 19:35                     ` Felician Nemeth
2023-05-11 19:54                       ` João Távora
2023-05-15 20:03                         ` Felician Nemeth
2023-05-06 13:51           ` [GNU ELPA] eglot-x.el: Protocol extensions for Eglot João Távora
2023-05-06 15:28             ` Felician Nemeth
2023-05-05 16:38   ` Philip Kaludercic

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.