diff --git a/CHANGELOG.org b/CHANGELOG.org index dce251a990..300ba47195 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -32,9 +32,10 @@ * Add Roc support * Add support for environment variables in rust analyzer runnables. Allowing the new ~Update Tests (Expect)~ code lens to work as expected. * Add support for [[https://github.com/mathworks/MATLAB-language-server][MATLAB language server]] (requires [[https://github.com/MathWorks/Emacs-MATLAB-Mode][matlab-mode]]). - * Add support for [[https://github.com/c3lang/c3c][c3 language]] (requires [[https://github.com/c3lang/c3-ts-mode][c3-ts-mode]] and [[https://github.com/pherrymason/c3-lsp][c3lsp]]). + * Add support for [[https://github.com/c3lang/c3c][c3 language]] (requires [[https://github.com/c3lang/c3-ts-mode][c3-ts-mode]] and [[https://github.com/pherrymason/c3-lsp][c3lsp]]). * Drop support for emacs 27.1 and 27.2 * Add ~lsp-nix-nixd-server-arguments~ to allow passing arguments to the ~nixd~ LSP. + * Add ~lsp-display-pending-async-request-via-spinner~. If non-nil, indicate we are waiting for async responses via a spinner in the modeline. * Improve the lsp-ocaml client (see [[https://github.com/emacs-lsp/lsp-mode/issues/4731][#4731]] for the follow-up issue. MRs: [[https://github.com/emacs-lsp/lsp-mode/pull/4741][#4741]], [[https://github.com/emacs-lsp/lsp-mode/pull/4732][#4732]]) ** 9.0.0 diff --git a/lsp-mode.el b/lsp-mode.el index b3391e7127..5d8daabc2e 100644 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -211,6 +211,12 @@ Takes a value accepted by `spinner-start'." ,@(mapcar (lambda (c) (list 'const (car c))) spinner-types))) +(defcustom lsp-display-pending-async-request-via-spinner nil + "If non-nil, indicate we are waiting for async responses via a spinner +in the modeline." + :group 'lsp-mode + :type 'boolean) + (defvar-local lsp-use-workspace-root-for-server-default-directory nil "Use `lsp-workspace-root' for `default-directory' when starting LSP process.") @@ -3236,6 +3242,24 @@ If WORKSPACE is not provided current workspace will be used." "Remove TOKEN from the WORKSPACE work-done-tokens." (remhash token (lsp--workspace-work-done-tokens workspace))) +(defun lsp-client-set-async-request (id handler client) + "Set ID to HANDLER for pending async requests for a CLIENT" + (puthash id handler (lsp--client-response-handlers client)) + (if (and lsp-display-pending-async-request-via-spinner + (= (hash-table-count (lsp--client-response-handlers client)) 1)) + (lsp--spinner-start))) + +(defun lsp-client-get-async-request (id client) + "Get the handler for ID from pending async requests for a CLIENT" + (gethash id (lsp--client-response-handlers client)) + ) + +(defun lsp-client-rem-async-request (id client) + "Remove ID from pending async requests for a CLIENT" + (remhash id (lsp--client-response-handlers client)) + (if (and lsp-display-pending-async-request-via-spinner + (zerop (hash-table-count (lsp--client-response-handlers client)))) + (lsp--spinner-stop))) (defun lsp--make-notification (method &optional params) "Create notification body for method METHOD and parameters PARAMS." @@ -3681,11 +3705,9 @@ CANCEL-TOKEN is the token that can be used to cancel request." (plist-get body :params) 'outgoing-req) workspace)) - (puthash id + (lsp-client-set-async-request id (list callback error-callback method start-time (current-time)) - (-> workspace - (lsp--workspace-client) - (lsp--client-response-handlers))) + (lsp--workspace-client workspace)) (lsp--send-no-wait body (lsp--workspace-proc workspace))) body) (error "The connected server(s) does not support method %s. @@ -5366,7 +5388,7 @@ If EXCLUDE-DECLARATION is non-nil, request the server to include declarations." (defun lsp--cancel-request (id) "Cancel request with ID in all workspaces." (lsp-foreach-workspace - (->> lsp--cur-workspace lsp--workspace-client lsp--client-response-handlers (remhash id)) + (->> lsp--cur-workspace lsp--workspace-client (lsp-client-rem-async-request id)) (lsp-notify "$/cancelRequest" `(:id ,id)))) (defvar-local lsp--hover-saved-bounds nil) @@ -7112,25 +7134,25 @@ server. WORKSPACE is the active workspace." (pcase (lsp--get-message-type json-data) ('response (cl-assert id) - (-let [(callback _ method _ before-send) (gethash id (lsp--client-response-handlers client))] + (-let [(callback _ method _ before-send) (lsp-client-get-async-request id client)] (when (lsp--log-io-p method) (lsp--log-entry-new (lsp--make-log-entry method id data 'incoming-resp (lsp--ms-since before-send)) workspace)) (when callback - (remhash id (lsp--client-response-handlers client)) + (lsp-client-rem-async-request id client) (funcall callback (lsp:json-response-result json-data))))) ('response-error (cl-assert id) - (-let [(_ callback method _ before-send) (gethash id (lsp--client-response-handlers client))] + (-let [(_ callback method _ before-send) (lsp-client-get-async-request id client)] (when (lsp--log-io-p method) (lsp--log-entry-new (lsp--make-log-entry method id (lsp:json-response-error-error json-data) 'incoming-resp (lsp--ms-since before-send)) workspace)) (when callback - (remhash id (lsp--client-response-handlers client)) + (lsp-client-rem-async-request id client) (funcall callback (lsp:json-response-error-error json-data))))) ('notification (lsp--on-notification workspace json-data)) @@ -9145,7 +9167,9 @@ IGNORE-MULTI-FOLDER to ignore multi folder server." (defun lsp--spinner-stop () "Stop the spinner in case all of the workspaces are started." - (when (--all? (eq (lsp--workspace-status it) 'initialized) + (when (--all? (and (eq (lsp--workspace-status it) 'initialized) + (or (null lsp-display-pending-async-request-via-spinner) + (zerop (hash-table-count (-> it (lsp--workspace-client) (lsp--client-response-handlers)))))) lsp--buffer-workspaces) (spinner-stop)))