summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authordannyfreeman <danny@dfreeman.email>2022-12-09 12:49:26 +0000
committerJoão Távora <joaotavora@gmail.com>2022-12-09 13:03:57 +0000
commit74a009dd96a643b12a63a29fba3d40a74e7d82a2 (patch)
treebf01dd79925eadf4ffe19bd8212080304440fd07 /lisp
parent0cfeb1c2bc98b3b4c9ea8c28d176ac65b9211f7f (diff)
downloademacs-74a009dd96a643b12a63a29fba3d40a74e7d82a2.tar.gz
emacs-74a009dd96a643b12a63a29fba3d40a74e7d82a2.tar.bz2
emacs-74a009dd96a643b12a63a29fba3d40a74e7d82a2.zip
Eglot: Handle LSP progress with Emacs progress reporters (bug#59149)
Co-authored-by: João Távora <joaotavora@gmail.com> * lisp/progmodes/eglot.el (eglot-report-progress): New custom variable. (eglot-lsp-server): New slot for tracking active progress reporters. (eglot-handle-notification (eql $/progress)): New method. The LSP spec describes methods for reporting progress on long running jobs to the client: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#progress https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workDoneProgress This change reports those notifications in the minibuffer as they come in. It shows a percent indicator (if the server provides theme), or a spinner. This change could open the door for writing a "cancel long running request" command, which are identified by these progress notifications. See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_workDoneProgress_cancel * doc/misc/eglot.texi (Customizing Eglot): Describe new variable.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/progmodes/eglot.el30
1 files changed, 30 insertions, 0 deletions
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 06541d47d82..a53f62fc565 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -387,6 +387,11 @@ done by `eglot-reconnect'."
"String displayed in mode line when Eglot is active."
:type 'string)
+(defcustom eglot-report-progress t
+ "If non-nil, show progress of long running LSP server work"
+ :type 'boolean
+ :version "29.1")
+
(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.")
@@ -471,6 +476,7 @@ This can be useful when using docker to run a language server.")
(TextDocumentEdit (:textDocument :edits) ())
(TextEdit (:range :newText))
(VersionedTextDocumentIdentifier (:uri :version) ())
+ (WorkDoneProgress (:kind) (:title :message :percentage :cancellable))
(WorkspaceEdit () (:changes :documentChanges))
(WorkspaceSymbol (:name :kind) (:containerName :location :data)))
"Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces.
@@ -832,6 +838,9 @@ treated as in `eglot--dbind'."
(project
:documentation "Project associated with server."
:accessor eglot--project)
+ (progress-reporters
+ :initform (make-hash-table :test #'equal) :accessor eglot--progress-reporters
+ :documentation "Maps LSP progress tokens to progress reporters.")
(inhibit-autoreconnect
:initform t
:documentation "Generalized boolean inhibiting auto-reconnection if true."
@@ -2051,6 +2060,27 @@ COMMAND is a symbol naming the command."
"Handle notification telemetry/event.") ;; noop, use events buffer
(cl-defmethod eglot-handle-notification
+ (server (_method (eql $/progress)) &key token value)
+ "Handle $/progress notification identified by TOKEN from SERVER."
+ (when eglot-report-progress
+ (cl-flet ((fmt (&rest args) (mapconcat #'identity args " ")))
+ (eglot--dbind ((WorkDoneProgress) kind title percentage message) value
+ (pcase kind
+ ("begin"
+ (let* ((prefix (format (concat "[eglot] %s %s:" (when percentage " "))
+ (eglot-project-nickname server) token))
+ (pr (puthash token
+ (if percentage
+ (make-progress-reporter prefix 0 100 percentage 1 0)
+ (make-progress-reporter prefix nil nil nil 1 0))
+ (eglot--progress-reporters server))))
+ (progress-reporter-update pr percentage (fmt title message))))
+ ("report"
+ (when-let ((pr (gethash token (eglot--progress-reporters server))))
+ (progress-reporter-update pr percentage (fmt title message))))
+ ("end" (remhash token (eglot--progress-reporters server))))))))
+
+(cl-defmethod eglot-handle-notification
(_server (_method (eql textDocument/publishDiagnostics)) &key uri diagnostics
&allow-other-keys) ; FIXME: doesn't respect `eglot-strict-mode'
"Handle notification publishDiagnostics."