]> git.eshelyaron.com Git - emacs.git/commitdiff
Eglot: introduce eglot-advertise-cancellation
authorJoão Távora <joaotavora@gmail.com>
Tue, 14 Jan 2025 15:58:57 +0000 (15:58 +0000)
committerEshel Yaron <me@eshelyaron.com>
Thu, 30 Jan 2025 18:10:20 +0000 (19:10 +0100)
Setting this variable to true causes Eglot to send special
cancellation notification for certain stale client request.

This may help some LSP servers avoid doing costly but ultimately useless
work on behalf of the client, improving overall performance.

Request cancellation is described in

   https://microsoft.github.io/language-server-protocol/
      specifications/lsp/3.17/specification/#cancelRequest

* lisp/jsonrpc.el (jsonrpc-request): Accept function as value for
CANCEL-ON-INPUT.

* lisp/progmodes/eglot.el (eglot--request): Rework.

* doc/misc/eglot.texi (Customizing Eglot): Mention
eglot-advertise-cancellation.

(cherry picked from commit 7f0ef9655cdc28c3b8055e32c9e84ea57339b139)

doc/misc/eglot.texi
etc/EGLOT-NEWS
lisp/jsonrpc.el
lisp/progmodes/eglot.el

index df24cf2a1dca55e5dc66a2c310220905b4b2d40d..47649455ceceb9426f27dd6a7d2f6442490f957c 100644 (file)
@@ -919,6 +919,13 @@ Set this variable to non-nil if you'd like progress notifications coming
 from the language server to be handled by Emacs's progress reporting
 facilities.  If the value is the symbol @code{messages} the message
 buffer is used, else the progress is reported in the mode line.
+
+@cindex request cancellation
+@item eglot-advertise-cancellation
+Setting this variable to true causes Eglot to send special cancellation
+notification for certain stale client request.  This may help some LSP
+servers avoid doing costly but ultimately useless work on behalf of the
+client, improving overall performance.
 @end vtable
 
 @node Other Variables
index f4621994b6759040be8ced746d3328560aa058fd..9deac73d9fc2296d688ced337a44064b801a98f7 100644 (file)
@@ -20,6 +20,12 @@ https://github.com/joaotavora/eglot/issues/1234.
 \f
 * Changes in upcoming Eglot
 
+** New 'eglot-advertise-cancellation' variable
+
+Tweaking this variable may help some LSP servers avoid doing costly but
+ultimately useless work on behalf of the client, improving overall
+performance.
+
 \f
 * Changes in Eglot 1.18 (20/1/2025)
 
index df612e63d05b3636c006491220ed787d9ea1b7bf..c1743c13611ba4f9df07a3e6061dde1b2a189cad 100644 (file)
@@ -399,10 +399,12 @@ error of type `jsonrpc-error'.
 
 DEFERRED and TIMEOUT as in `jsonrpc-async-request', which see.
 
-If CANCEL-ON-INPUT is non-nil and the user inputs something while
-the function is waiting, then it exits immediately, returning
-CANCEL-ON-INPUT-RETVAL.  Any future replies (normal or error) are
-ignored."
+If CANCEL-ON-INPUT is non-nil and the user inputs something while the
+function is waiting, then any future replies to the request by the
+remote endpoint (normal or error) are ignored and the function exits
+returning CANCEL-ON-INPUT-RETVAL.  If CANCEL-ON-INPUT is a function, it
+is invoked with one argument, an integer identifying the cancelled
+request as specified in the JSONRPC 2.0 spec."
   (let* ((tag (cl-gensym "jsonrpc-request-catch-tag")) id-and-timer
          canceled
          (throw-on-input nil)
@@ -435,6 +437,8 @@ ignored."
                        (unwind-protect
                            (let ((inhibit-quit t)) (while (sit-for 30)))
                          (setq canceled t))
+                       (when (functionp cancel-on-input)
+                         (funcall cancel-on-input (car id-and-timer)))
                        `(canceled ,cancel-on-input-retval))
                       (t (while t (accept-process-output nil 30)))))
             ;; In normal operation, continuations for error/success is
index 166b39361029b10e746d9e28391fbd0bf06e6905..b87a45e9912bd78568d7cf4d2d60f4b25ee3b34c 100644 (file)
@@ -569,6 +569,14 @@ under cursor."
           (const :tag "Execute custom commands" :executeCommandProvider)
           (const :tag "Inlay hints" :inlayHintProvider)))
 
+(defcustom eglot-advertise-cancellation nil
+  "If non-nil, Eglot attemps to inform server of cancelled requests.
+This is done by sending an additional '$/cancelRequest' notification
+every time Eglot decides to forget a request.  The effect of this
+notification is implementation defined, and is only useful for some
+servers."
+  :type 'boolean)
+
 (defvar eglot-withhold-process-id nil
   "If non-nil, Eglot will not send the Emacs process id to the language server.
 This can be useful when using docker to run a language server.")
@@ -1747,7 +1755,12 @@ Unless IMMEDIATE, send pending changes before making request."
   (unless immediate (eglot--signal-textDocument/didChange))
   (jsonrpc-request server method params
                    :timeout timeout
-                   :cancel-on-input cancel-on-input
+                   :cancel-on-input
+                   (cond ((and cancel-on-input
+                               eglot-advertise-cancellation)
+                          (lambda (id)
+                            (jsonrpc-notify server '$/cancelRequest `(:id ,id))))
+                         (cancel-on-input))
                    :cancel-on-input-retval cancel-on-input-retval))
 
 \f