emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

js2025 7d328eaca7e 1/4: Eglot: introduce eglot-advertise-cancellation


From: João Távora
Subject: js2025 7d328eaca7e 1/4: Eglot: introduce eglot-advertise-cancellation
Date: Fri, 17 Jan 2025 08:33:00 -0500 (EST)

branch: js2025
commit 7d328eaca7e1b4f701d3cff14b0b377a542ab7cc
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>

    Eglot: introduce eglot-advertise-cancellation
    
    Setting this variable to true causes Eglot to send special
    cancellation notification for certain stale client request.
    This may improve the performance of some LSP servers, who might
    be able to avoid doing costly but ultimately useless work on
    behalf of the client.
    
    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.
---
 doc/misc/eglot.texi     |  8 ++++++++
 lisp/jsonrpc.el         | 12 ++++++++----
 lisp/progmodes/eglot.el | 16 +++++++++++++++-
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index af38adc094a..b2cbb795429 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -983,6 +983,14 @@ from the language server to be handled as Emacs's progress 
reporting
 facilities.
 @end table
 
+@vindex eglot-advertise-cancellation
+@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 improve the
+performance of some LSP servers, who might be able to avoid doing costly
+but ultimately useless work on behalf of the client.
+
 @node Advanced server configuration
 @chapter Advanced server configuration
 
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index 1d3a983d41e..92d31bf4429 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -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
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 3c9644568ef..9ed36e39e65 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -573,6 +573,15 @@ 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.")
@@ -1739,7 +1748,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))
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]