diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi index b76f8bdfd71..2aff038b9ab 100644 --- a/doc/misc/eglot.texi +++ b/doc/misc/eglot.texi @@ -955,6 +955,13 @@ Note that you can still configure the excluded Emacs features manually to use Eglot in your @code{eglot-managed-mode-hook} or via some other mechanism. +@vindex eglot-report-progress +@cindex progress +@item eglot-report-progress +Set this variable to true if you'd like progress notifications coming +from the LSP server to be handled as Emacs's progress reporting +facilities. + @vindex eglot-workspace-configuration @cindex server workspace configuration @item eglot-workspace-configuration 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." @@ -2050,6 +2059,27 @@ COMMAND is a symbol naming the command." (_server (_method (eql telemetry/event)) &rest _any) "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'