From b53753f611045bb44ef4d1d30d6f426be889f277 Mon Sep 17 00:00:00 2001 From: dannyfreeman Date: Wed, 9 Nov 2022 08:46:45 -0500 Subject: [PATCH] Eglot: Display progress notifications in minibuffer as they arrive 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 should 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 --- lisp/progmodes/eglot.el | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index ecfede8fa6..b85d9fd445 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -820,6 +820,9 @@ eglot-lsp-server (spinner :documentation "List (ID DOING-WHAT DONE-P) representing server progress." :initform `(nil nil t) :accessor eglot--spinner) + (progress-reporter-alist + :documentation "Alist of (PROGRESS-TOKEN . PROGRESS-REPORTER)." + :accessor eglot--progress-reporter-alist) (inhibit-autoreconnect :initform t :documentation "Generalized boolean inhibiting auto-reconnection if true." @@ -2035,6 +2038,42 @@ eglot-handle-notification (_server (_method (eql telemetry/event)) &rest _any) "Handle notification telemetry/event.") ;; noop, use events buffer +(defun eglot--progress-report-message (title message) + "Format a $/progress report message, given a TITLE and/or MESSAGE string." + (cond + ((and title message) (format "%s %s" title message)) + (title title) + (message message))) + +(defun eglot--progress-reporter (server token) + "Get a prgress-reporter identified by the progress TOKEN from the SERVER ." + (cdr (assoc token (eglot--progress-reporter-alist server)))) + +(defun eglot--progress-reporter-delete (server token) + "Delete progress-reporters identified by the progress TOKEN from the SERVER." + (setf (eglot--progress-reporter-alist server) + (assoc-delete-all token (eglot--progress-reporter-alist server)))) + +(cl-defmethod eglot-handle-notification + (server (_method (eql $/progress)) &key token value) + "Handle a $/progress notification identified by TOKEN from the SERVER." + (cl-destructuring-bind (&key kind title percentage message) value + (pcase kind + ("begin" (let* ((prefix (format (concat "[eglot] %s %s:" (when percentage " ")) + (eglot-project-nickname server) token)) + (pr (if percentage + (make-progress-reporter prefix 0 100 percentage 1 0) + (make-progress-reporter prefix nil nil nil 1 0)))) + (eglot--progress-reporter-delete server token) + (setf (eglot--progress-reporter-alist server) + (cons (cons token pr) (eglot--progress-reporter-alist server))) + (progress-reporter-update pr percentage (eglot--progress-report-message title message)))) + ("report" (when-let ((pr (eglot--progress-reporter server token))) + (progress-reporter-update pr percentage (eglot--progress-report-message title message)))) + ("end" (when-let ((pr (eglot--progress-reporter server token))) + (progress-reporter-done pr) + (eglot--progress-reporter-delete server token)))))) + (cl-defmethod eglot-handle-notification (_server (_method (eql textDocument/publishDiagnostics)) &key uri diagnostics &allow-other-keys) ; FIXME: doesn't respect `eglot-strict-mode' -- 2.38.1