(cancel-on-input))
:cancel-on-input-retval cancel-on-input-retval))
+(defvar-local eglot--inflight-async-requests nil
+ "An plist of symbols to lists of JSONRPC ids.
+The ids designate in-flight asynchronous requests that may be cancelled
+according to `eglot-advertise-cancellation'.")
+
+(cl-defun eglot--cancel-inflight-async-requests
+ (&optional (hints '(:textDocument/signatureHelp
+ :textDocument/hover
+ :textDocument/documentHighlight
+ :textDocument/codeAction)))
+ (when-let* ((server (and hints
+ eglot-advertise-cancellation
+ (eglot-current-server))))
+ (dolist (hint hints)
+ (dolist (id (plist-get eglot--inflight-async-requests hint))
+ ;; FIXME: in theory, as `jsonrpc-async-request' explains, this
+ ;; request may never have been sent at all. But that's rare, and
+ ;; it's only a problem if the server borks on cancellation of
+ ;; never-sent requests.
+ (jsonrpc-notify server '$/cancelRequest `(:id ,id)))
+ (cl-remf eglot--inflight-async-requests hint))))
+
+(cl-defun eglot--async-request (server
+ method
+ params
+ &key
+ (success-fn nil success-fn-supplied-p)
+ (error-fn nil error-fn-supplied-p)
+ (timeout-fn nil timeout-fn-supplied-p)
+ (timeout nil timeout-supplied-p)
+ hint
+ &aux moreargs)
+ "Like `jsonrpc-async-request', but for Eglot LSP requests.
+HINT argument is a symbol passed as DEFERRED to `jsonrpc-async-request'
+and also used as a hint of the request cancellation mechanism (see
+`eglot-advertise-cancellation')."
+ (cl-labels ((clearing-fn (fn)
+ (lambda (&rest args)
+ (when fn (apply fn args))
+ (cl-remf eglot--inflight-async-requests hint))))
+ (eglot--cancel-inflight-async-requests (list hint))
+ (when timeout-supplied-p
+ (setq moreargs (nconc `(:timeout ,timeout) moreargs)))
+ (when hint
+ (setq moreargs (nconc `(:deferred ,hint) moreargs)))
+ (let ((id
+ (car (apply #'jsonrpc-async-request
+ server method params
+ :success-fn (clearing-fn success-fn)
+ :error-fn (clearing-fn error-fn)
+ :timeout-fn (clearing-fn timeout-fn)
+ moreargs))))
+ (when (and hint eglot-advertise-cancellation)
+ (push id
+ (plist-get eglot--inflight-async-requests hint))))))
+
\f
;;; Encoding fever
;;;
"Cache of `workspace/Symbol' results used by `xref-find-definitions'.")
(defun eglot--pre-command-hook ()
- "Reset some temporary variables."
+ "Reset some state."
(clrhash eglot--workspace-symbols-cache)
+ (eglot--cancel-inflight-async-requests)
(setq eglot--last-inserted-char nil))
(defun eglot--CompletionParams ()
"A member of `eldoc-documentation-functions', for signatures."
(when (eglot-server-capable :signatureHelpProvider)
(let ((buf (current-buffer)))
- (jsonrpc-async-request
+ (eglot--async-request
(eglot--current-server-or-lose)
:textDocument/signatureHelp (eglot--TextDocumentPositionParams)
:success-fn
nil))
signatures "\n")
:echo (eglot--sig-info active-sig activeParameter t))))))
- :deferred :textDocument/signatureHelp))
+ :hint :textDocument/signatureHelp))
t))
(defun eglot-hover-eldoc-function (cb &rest _ignored)
"A member of `eldoc-documentation-functions', for hover."
(when (eglot-server-capable :hoverProvider)
(let ((buf (current-buffer)))
- (jsonrpc-async-request
+ (eglot--async-request
(eglot--current-server-or-lose)
:textDocument/hover (eglot--TextDocumentPositionParams)
:success-fn (eglot--lambda ((Hover) contents range)
(eglot--hover-info contents range))))
(funcall cb info
:echo (and info (string-match "\n" info))))))
- :deferred :textDocument/hover))
+ :hint :textDocument/hover))
t))
(defun eglot-highlight-eldoc-function (_cb &rest _ignored)
;; ignore cb and return nil to say "no doc".
(when (eglot-server-capable :documentHighlightProvider)
(let ((buf (current-buffer)))
- (jsonrpc-async-request
+ (eglot--async-request
(eglot--current-server-or-lose)
:textDocument/documentHighlight (eglot--TextDocumentPositionParams)
:success-fn
`(,(lambda (o &rest _) (delete-overlay o))))
ov)))
highlights))))
- :deferred :textDocument/documentHighlight)
+ :hint :textDocument/documentHighlight)
nil)))
(defun eglot--imenu-SymbolInformation (res)
(bounds (eglot--code-action-bounds))
(use-text-p (memq 'eldoc-hint eglot-code-action-indications))
tooltip blurb)
- (jsonrpc-async-request
+ (eglot--async-request
(eglot--current-server-or-lose)
:textDocument/codeAction
(eglot--code-action-params :beg (car bounds) :end (cadr bounds)
,tooltip)))))
(setq eglot--suggestion-overlay ov)))))
(when use-text-p (funcall cb blurb)))
- :deferred :textDocument/codeAction)
+ :hint :textDocument/codeAction)
(and use-text-p t))))
\f