diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index ef5dbf8103..8909e8d431 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -5,7 +5,7 @@ ;; Author: Noah Friedman ;; Keywords: extensions ;; Created: 1995-10-06 -;; Version: 1.0.0 +;; Version: 1.1.0 ;; Package-Requires: ((emacs "26.3")) ;; This is a GNU ELPA :core package. Avoid functionality that is not @@ -338,12 +338,26 @@ eldoc-display-message-no-interference-p (defvar eldoc-documentation-functions nil - "Hook for functions to call to return doc string. -Each function should accept no arguments and return a one-line -string for displaying doc about a function etc. appropriate to -the context around point. It should return nil if there's no doc -appropriate for the context. Typically doc is returned if point -is on a function-like name or in its arg list. + "Hook of functions that produce doc strings. +Each hook function should accept no arguments and decide whether +to display a doc short string about the context around point. + +Typically doc is returned if point is on a function-like name or +in its arg list. + +If the decision and the doc string can be produced quickly, the +hook function should immediately return the doc string, or nil if +there's no doc appropriate for the context. Otherwise, if its +computation is expensive or can't be performed directly, the +function can instead return a cons (:async . FETCHER) where where +FETCHER is a function of one argument, CALLBACK. When the result +arrives, FETCHER must call CALLBACK and pass it the doc string to +be displayed. + +A current limitation of the asynchronous case is that it is only +guaranteed to work correctly if the value of +`eldoc-documentation-function' (notice the singular) is +`eldoc-documentation-default'. Major modes should modify this hook locally, for example: (add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t) @@ -351,14 +365,18 @@ eldoc-documentation-functions taken into account if the major mode specific function does not return any documentation.") +(defun eldoc--handle-multiline (res) + "Helper for handling a bit of `eldoc-echo-area-use-multiline-p'." + (if eldoc-echo-area-use-multiline-p res + (truncate-string-to-width + res (1- (window-width (minibuffer-window)))))) + (defun eldoc-documentation-default () "Show first doc string for item at point. Default value for `eldoc-documentation-function'." (let ((res (run-hook-with-args-until-success 'eldoc-documentation-functions))) - (when res - (if eldoc-echo-area-use-multiline-p res - (truncate-string-to-width - res (1- (window-width (minibuffer-window)))))))) + (cond ((stringp res) (eldoc--handle-multiline res)) + (t res)))) (defun eldoc-documentation-compose () "Show multiple doc string results at once. @@ -368,13 +386,11 @@ eldoc-documentation-compose 'eldoc-documentation-functions (lambda (f) (let ((str (funcall f))) - (when str (push str res)) + (when (stringp str) (push str res)) nil))) (when res (setq res (mapconcat #'identity (nreverse res) ", ")) - (if eldoc-echo-area-use-multiline-p res - (truncate-string-to-width - res (1- (window-width (minibuffer-window)))))))) + (eldoc--handle-multiline res)))) (defcustom eldoc-documentation-function #'eldoc-documentation-default "Function to call to return doc string. @@ -417,11 +433,30 @@ eldoc-print-current-symbol-info ;; Erase the last message if we won't display a new one. (when eldoc-last-message (eldoc-message nil)) - (let ((non-essential t)) + (let ((non-essential t) + (buffer (current-buffer))) ;; Only keep looking for the info as long as the user hasn't ;; requested our attention. This also locally disables inhibit-quit. (while-no-input - (eldoc-message (funcall eldoc-documentation-function))))))) + (let* + ((waiting-for-callback t) + (callback + (lambda (string) + (with-current-buffer buffer + ;; JT@2020-05-25: Currently, we expect one single + ;; docstring from the client, we silently swallow + ;; anything the client unexpectedly gives us, + ;; including updates. This could change. + (when waiting-for-callback + (setq waiting-for-callback nil) + (eldoc-message (eldoc--handle-multiline string)))))) + (res + (funcall eldoc-documentation-function))) + (cond ((stringp res) (eldoc-message res)) + ((and (consp res) + (eq (car res) :async)) + (funcall (cdr res) callback)) + (t (eldoc-message nil))))))))) ;; If the entire line cannot fit in the echo area, the symbol name may be ;; truncated or eliminated entirely from the output to make room for the