dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

eldoc.el (39342B)


      1 ;;; eldoc.el --- Show function arglist or variable docstring in echo area  -*- lexical-binding:t; -*-
      2 
      3 ;; Copyright (C) 1996-2020 Free Software Foundation, Inc.
      4 
      5 ;; Author: Noah Friedman <friedman@splode.com>
      6 ;; Keywords: extensions
      7 ;; Created: 1995-10-06
      8 ;; Version: 1.11.0
      9 ;; Package-Requires: ((emacs "26.3"))
     10 
     11 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
     12 ;; compatible with the version of Emacs recorded above.
     13 
     14 ;; This file is part of GNU Emacs.
     15 
     16 ;; GNU Emacs is free software: you can redistribute it and/or modify
     17 ;; it under the terms of the GNU General Public License as published by
     18 ;; the Free Software Foundation, either version 3 of the License, or
     19 ;; (at your option) any later version.
     20 
     21 ;; GNU Emacs is distributed in the hope that it will be useful,
     22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     24 ;; GNU General Public License for more details.
     25 
     26 ;; You should have received a copy of the GNU General Public License
     27 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
     28 
     29 ;;; Commentary:
     30 
     31 ;; This program was inspired by the behavior of the "mouse documentation
     32 ;; window" on many Lisp Machine systems; as you type a function's symbol
     33 ;; name as part of a sexp, it will print the argument list for that
     34 ;; function.  Behavior is not identical; for example, you need not actually
     35 ;; type the function name, you need only move point around in a sexp that
     36 ;; calls it.  Also, if point is over a documented variable, it will print
     37 ;; the one-line documentation for that variable instead, to remind you of
     38 ;; that variable's meaning.
     39 
     40 ;; This mode is now enabled by default in all major modes that provide
     41 ;; support for it, such as `emacs-lisp-mode'.
     42 ;; This is controlled by `global-eldoc-mode'.
     43 
     44 ;; Major modes for other languages may use ElDoc by adding an
     45 ;; appropriate function to the buffer-local value of
     46 ;; `eldoc-documentation-functions'.
     47 
     48 ;;; Code:
     49 
     50 (eval-when-compile (require 'cl-lib))
     51 
     52 (defgroup eldoc nil
     53   "Show function arglist or variable docstring in echo area."
     54   :group 'lisp
     55   :group 'extensions)
     56 
     57 (defcustom eldoc-idle-delay 0.50
     58   "Number of seconds of idle time to wait before printing.
     59 If user input arrives before this interval of time has elapsed after the
     60 last input, no documentation will be printed.
     61 
     62 If this variable is set to 0, no idle time is required."
     63   :type 'number)
     64 
     65 (defcustom eldoc-print-after-edit nil
     66   "If non-nil eldoc info is only shown when editing.
     67 Changing the value requires toggling `eldoc-mode'."
     68   :type 'boolean)
     69 
     70 (defcustom eldoc-echo-area-display-truncation-message t
     71   "If non-nil, provide verbose help when a message has been truncated.
     72 If nil, truncated messages will just have \"...\" appended."
     73   :type 'boolean
     74   :version "28.1")
     75 
     76 ;;;###autoload
     77 (defcustom eldoc-minor-mode-string (purecopy " ElDoc")
     78   "String to display in mode line when ElDoc Mode is enabled; nil for none."
     79   :type '(choice string (const :tag "None" nil)))
     80 
     81 (defcustom eldoc-argument-case #'identity
     82   "Case to display argument names of functions, as a symbol.
     83 This has two preferred values: `upcase' or `downcase'.
     84 Actually, any name of a function which takes a string as an argument and
     85 returns another string is acceptable.
     86 
     87 Note that this variable has no effect, unless
     88 `eldoc-documentation-strategy' handles it explicitly."
     89   :type '(radio (function-item upcase)
     90 		(function-item downcase)
     91                 function))
     92 (make-obsolete-variable 'eldoc-argument-case nil "25.1")
     93 
     94 (defcustom eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit
     95   "Allow long ElDoc doc strings to resize echo area display.
     96 If value is t, never attempt to truncate messages, even if the
     97 echo area must be resized to fit.
     98 
     99 If the value is a positive number, it is used to calculate a
    100 number of logical lines of documentation that ElDoc is allowed to
    101 put in the echo area.  If a positive integer, the number is used
    102 directly, while a float specifies the number of lines as a
    103 proporting of the echo area frame's height.
    104 
    105 If value is the symbol `truncate-sym-name-if-fit' t, the part of
    106 the doc string that represents a symbol's name may be truncated
    107 if it will enable the rest of the doc string to fit on a single
    108 line, without resizing the echo area.
    109 
    110 If value is nil, a doc string is always truncated to fit in a
    111 single line of display in the echo area.
    112 
    113 Any resizing of the echo area additionally respects
    114 `max-mini-window-height'."
    115   :type '(radio (const   :tag "Always" t)
    116                 (float   :tag "Fraction of frame height" 0.25)
    117                 (integer :tag "Number of lines" 5)
    118                 (const   :tag "Never" nil)
    119                 (const   :tag "Yes, but ask major-mode to truncate
    120  symbol names if it will\ enable argument list to fit on one
    121  line" truncate-sym-name-if-fit)))
    122 
    123 (defcustom eldoc-echo-area-prefer-doc-buffer nil
    124   "Prefer ElDoc's documentation buffer if it is showing in some frame.
    125 If this variable's value is t, ElDoc will skip showing
    126 documentation in the echo area if the dedicated documentation
    127 buffer (given by `eldoc-doc-buffer') is being displayed in some
    128 window.  If the value is the symbol `maybe', then the echo area
    129 is only skipped if the documentation doesn't fit there."
    130   :type 'boolean)
    131 
    132 (defface eldoc-highlight-function-argument
    133   '((t (:inherit bold)))
    134   "Face used for the argument at point in a function's argument list.
    135 Note that this face has no effect unless the `eldoc-documentation-strategy'
    136 handles it explicitly.")
    137 
    138 ;;; No user options below here.
    139 
    140 (defvar eldoc-message-commands-table-size 31
    141   "Used by `eldoc-add-command' to initialize `eldoc-message-commands' obarray.
    142 It should probably never be necessary to do so, but if you
    143 choose to increase the number of buckets, you must do so before loading
    144 this file since the obarray is initialized at load time.
    145 Remember to keep it a prime number to improve hash performance.")
    146 
    147 (defvar eldoc-message-commands
    148   ;; Don't define as `defconst' since it would then go to (read-only) purespace.
    149   (make-vector eldoc-message-commands-table-size 0)
    150   "Commands after which it is appropriate to print in the echo area.
    151 ElDoc does not try to print function arglists, etc., after just any command,
    152 because some commands print their own messages in the echo area and these
    153 functions would instantly overwrite them.  But `self-insert-command' as well
    154 as most motion commands are good candidates.
    155 This variable contains an obarray of symbols; do not manipulate it
    156 directly.  Instead, use `eldoc-add-command' and `eldoc-remove-command'.")
    157 
    158 ;; Not a constant.
    159 (defvar eldoc-last-data (make-vector 3 nil)
    160   ;; Don't define as `defconst' since it would then go to (read-only) purespace.
    161   "Bookkeeping; elements are as follows:
    162   0 - contains the last symbol read from the buffer.
    163   1 - contains the string last displayed in the echo area for variables,
    164       or argument string for functions.
    165   2 - `function' if function args, `variable' if variable documentation.")
    166 (make-obsolete-variable 'eldoc-last-data "use your own instead" "25.1")
    167 
    168 (defvar eldoc-last-message nil)
    169 
    170 (defvar eldoc-timer nil "ElDoc's timer object.")
    171 
    172 (defvar eldoc-current-idle-delay eldoc-idle-delay
    173   "Idle time delay currently in use by timer.
    174 This is used to determine if `eldoc-idle-delay' is changed by the user.")
    175 
    176 (defvar eldoc-message-function #'eldoc-minibuffer-message
    177   "The function used by `eldoc--message' to display messages.
    178 It should receive the same arguments as `message'.")
    179 
    180 (defun eldoc-edit-message-commands ()
    181   "Return an obarray containing common editing commands.
    182 
    183 When `eldoc-print-after-edit' is non-nil, ElDoc messages are only
    184 printed after commands contained in this obarray."
    185   (let ((cmds (make-vector 31 0))
    186 	(re (regexp-opt '("delete" "insert" "edit" "electric" "newline"))))
    187     (mapatoms (lambda (s)
    188 		(and (commandp s)
    189 		     (string-match-p re (symbol-name s))
    190 		     (intern (symbol-name s) cmds)))
    191 	      obarray)
    192     cmds))
    193 
    194 
    195 ;;;###autoload
    196 (define-minor-mode eldoc-mode
    197   "Toggle echo area display of Lisp objects at point (ElDoc mode).
    198 
    199 ElDoc mode is a buffer-local minor mode.  When enabled, the echo
    200 area displays information about a function or variable in the
    201 text where point is.  If point is on a documented variable, it
    202 displays the first line of that variable's doc string.  Otherwise
    203 it displays the argument list of the function called in the
    204 expression point is on." :lighter eldoc-minor-mode-string
    205   (setq eldoc-last-message nil)
    206   (cond
    207    ((not (eldoc--supported-p))
    208     (when (called-interactively-p 'any)
    209       (message "There is no ElDoc support in this buffer"))
    210     (setq eldoc-mode nil))
    211    (eldoc-mode
    212     (when eldoc-print-after-edit
    213       (setq-local eldoc-message-commands (eldoc-edit-message-commands)))
    214     (add-hook 'post-command-hook #'eldoc-schedule-timer nil t)
    215     (add-hook 'pre-command-hook #'eldoc-pre-command-refresh-echo-area nil t))
    216    (t
    217     (kill-local-variable 'eldoc-message-commands)
    218     (remove-hook 'post-command-hook #'eldoc-schedule-timer t)
    219     (remove-hook 'pre-command-hook #'eldoc-pre-command-refresh-echo-area t)
    220     (when eldoc-timer
    221       (cancel-timer eldoc-timer)
    222       (setq eldoc-timer nil)))))
    223 
    224 ;;;###autoload
    225 (define-globalized-minor-mode global-eldoc-mode eldoc-mode turn-on-eldoc-mode
    226   :initialize 'custom-initialize-delay
    227   :init-value t
    228   ;; For `read--expression', the usual global mode mechanism of
    229   ;; `change-major-mode-hook' runs in the minibuffer before
    230   ;; `eldoc-documentation-strategy' is set, so `turn-on-eldoc-mode'
    231   ;; does nothing.  Configure and enable eldoc from
    232   ;; `eval-expression-minibuffer-setup-hook' instead.
    233   (if global-eldoc-mode
    234       (add-hook 'eval-expression-minibuffer-setup-hook
    235                 #'eldoc--eval-expression-setup)
    236     (remove-hook 'eval-expression-minibuffer-setup-hook
    237                  #'eldoc--eval-expression-setup)))
    238 
    239 (defun eldoc--eval-expression-setup ()
    240   ;; Setup `eldoc', similar to `emacs-lisp-mode'.  FIXME: Call
    241   ;; `emacs-lisp-mode' itself?
    242   (cond ((<= emacs-major-version 27)
    243          (declare-function elisp-eldoc-documentation-function "elisp-mode")
    244          (add-function :before-until (local 'eldoc-documentation-function)
    245                        #'elisp-eldoc-documentation-function))
    246         (t (add-hook 'eldoc-documentation-functions
    247                      #'elisp-eldoc-var-docstring nil t)
    248            (add-hook 'eldoc-documentation-functions
    249                      #'elisp-eldoc-funcall nil t)
    250            (setq eldoc-documentation-strategy 'eldoc-documentation-default)))
    251   (eldoc-mode +1))
    252 
    253 ;;;###autoload
    254 (defun turn-on-eldoc-mode ()
    255   "Turn on `eldoc-mode' if the buffer has ElDoc support enabled.
    256 See `eldoc-documentation-strategy' for more detail."
    257   (when (eldoc--supported-p)
    258     (eldoc-mode 1)))
    259 
    260 
    261 (defun eldoc-schedule-timer ()
    262   "Ensure `eldoc-timer' is running.
    263 
    264 If the user has changed `eldoc-idle-delay', update the timer to
    265 reflect the change."
    266   (or (and eldoc-timer
    267            (memq eldoc-timer timer-idle-list)) ;FIXME: Why?
    268       (setq eldoc-timer
    269             (run-with-idle-timer
    270 	     eldoc-idle-delay nil
    271 	     (lambda ()
    272                (when (or eldoc-mode
    273                          (and global-eldoc-mode
    274                               (eldoc--supported-p)))
    275                  ;; Don't ignore, but also don't full-on signal errors
    276                  (with-demoted-errors "eldoc error: %s"
    277                    (eldoc-print-current-symbol-info)) )))))
    278 
    279   ;; If user has changed the idle delay, update the timer.
    280   (cond ((not (= eldoc-idle-delay eldoc-current-idle-delay))
    281          (setq eldoc-current-idle-delay eldoc-idle-delay)
    282          (timer-set-idle-time eldoc-timer eldoc-idle-delay t))))
    283 
    284 (defvar eldoc-mode-line-string nil)
    285 (put 'eldoc-mode-line-string 'risky-local-variable t)
    286 
    287 (defun eldoc-minibuffer-message (format-string &rest args)
    288   "Display messages in the mode-line when in the minibuffer.
    289 Otherwise work like `message'."
    290   (if (minibufferp)
    291       (progn
    292 	(add-hook 'minibuffer-exit-hook
    293 		  (lambda () (setq eldoc-mode-line-string nil
    294 			      ;; https://debbugs.gnu.org/16920
    295 			      eldoc-last-message nil))
    296 		  nil t)
    297 	(with-current-buffer
    298 	    (window-buffer
    299 	     (or (window-in-direction 'above (minibuffer-window))
    300 		 (minibuffer-selected-window)
    301 		 (get-largest-window)))
    302           (when (and mode-line-format
    303                      (not (and (listp mode-line-format)
    304                                (assq 'eldoc-mode-line-string mode-line-format))))
    305 	    (setq mode-line-format
    306 		  (list "" '(eldoc-mode-line-string
    307 			     (" " eldoc-mode-line-string " "))
    308 			mode-line-format)))
    309           (setq eldoc-mode-line-string
    310                 (when (stringp format-string)
    311                   (apply #'format-message format-string args)))
    312           (force-mode-line-update)))
    313     (apply #'message format-string args)))
    314 
    315 (make-obsolete
    316  'eldoc-message "use `eldoc-documentation-functions' instead." "eldoc-1.1.0")
    317 (defun eldoc-message (&optional string) (eldoc--message string))
    318 (defun eldoc--message (&optional string)
    319   "Display STRING as an ElDoc message if it's non-nil.
    320 
    321 Also store it in `eldoc-last-message' and return that value."
    322   (let ((omessage eldoc-last-message))
    323     (setq eldoc-last-message string)
    324     ;; Do not put eldoc messages in the log since they are Legion.
    325     ;; Emacs way of preventing log messages.
    326     (let ((message-log-max nil))
    327       (cond (eldoc-last-message
    328 	     (funcall eldoc-message-function "%s" eldoc-last-message))
    329 	    (omessage (funcall eldoc-message-function nil)))))
    330   eldoc-last-message)
    331 
    332 (defun eldoc--message-command-p (command)
    333   "Return non-nil if COMMAND is in `eldoc-message-commands'."
    334   (and (symbolp command)
    335        (intern-soft (symbol-name command) eldoc-message-commands)))
    336 
    337 ;; This function goes on pre-command-hook.
    338 ;; Motion commands clear the echo area for some reason,
    339 ;; which make eldoc messages flicker or disappear just before motion
    340 ;; begins.  This function reprints the last eldoc message immediately
    341 ;; before the next command executes, which does away with the flicker.
    342 ;; This doesn't seem to be required for Emacs 19.28 and earlier.
    343 ;; FIXME: The above comment suggests we don't really understand why
    344 ;; this is needed.  Maybe it's not needed any more, but if it is
    345 ;; we should figure out why.
    346 (defun eldoc-pre-command-refresh-echo-area ()
    347   "Reprint `eldoc-last-message' in the echo area."
    348   (and eldoc-last-message
    349        (not (minibufferp))      ;We don't use the echo area when in minibuffer.
    350        (if (and (eldoc-display-message-no-interference-p)
    351 		(eldoc--message-command-p this-command))
    352 	   (eldoc--message eldoc-last-message)
    353          ;; No need to call eldoc--message since the echo area will be cleared
    354          ;; for us, but do note that the last-message will be gone.
    355          (setq eldoc-last-message nil))))
    356 
    357 ;; The point of `eldoc--request-state' is not to over-request, which
    358 ;; can happen if the idle timer is restarted on execution of command
    359 ;; which is guaranteed not to change the conditions that warrant a new
    360 ;; request for documentation.
    361 (defvar eldoc--last-request-state nil
    362   "Tuple containing information about last ElDoc request.")
    363 (defun eldoc--request-state ()
    364   "Compute information to store in `eldoc--last-request-state'."
    365   (list (current-buffer) (buffer-modified-tick) (point)))
    366 
    367 (defun eldoc-display-message-p ()
    368   "Tell if ElDoc can use the echo area."
    369   (and (eldoc-display-message-no-interference-p)
    370        (not this-command)
    371        (eldoc--message-command-p last-command)))
    372 
    373 (make-obsolete 'eldoc-display-message-p
    374                "Use `eldoc-documentation-functions' instead."
    375                "eldoc-1.6.0")
    376 
    377 ;; Check various conditions about the current environment that might make
    378 ;; it undesirable to print eldoc messages right this instant.
    379 (defun eldoc-display-message-no-interference-p ()
    380   "Return nil if displaying a message would cause interference."
    381   (not (or executing-kbd-macro (bound-and-true-p edebug-active))))
    382 
    383 
    384 (defvar eldoc-documentation-functions nil
    385   "Hook of functions that produce doc strings.
    386 
    387 A doc string is typically relevant if point is on a function-like
    388 name, inside its arg list, or on any object with some associated
    389 information.
    390 
    391 Each hook function is called with at least one argument CALLBACK,
    392 a function, and decides whether to display a doc short string
    393 about the context around point.
    394 
    395 - If that decision can be taken quickly, the hook function may
    396   call CALLBACK immediately following the protocol described
    397   below.  Alternatively it may ignore CALLBACK entirely and
    398   return either the doc string, or nil if there's no doc
    399   appropriate for the context.
    400 
    401 - If the computation of said doc string (or the decision whether
    402   there is one at all) is expensive or can't be performed
    403   directly, the hook function should return a non-nil, non-string
    404   value and arrange for CALLBACK to be called at a later time,
    405   using asynchronous processes or other asynchronous mechanisms.
    406 
    407 To call the CALLBACK function, the hook function must pass it an
    408 obligatory argument DOCSTRING, a string containing the
    409 documentation, followed by an optional list of arbitrary
    410 keyword-value pairs of the form (:KEY VALUE :KEY2 VALUE2...).
    411 The information contained in these pairs is understood by members
    412 of `eldoc-display-functions', allowing the
    413 documentation-producing backend to cooperate with specific
    414 documentation-displaying frontends.  For example, KEY can be:
    415 
    416 * `:thing', VALUE being a short string or symbol designating what
    417   is being reported on.  It can, for example be the name of the
    418   function whose signature is being documented, or the name of
    419   the variable whose docstring is being documented.
    420   `eldoc-display-in-echo-area', a member of
    421   `eldoc-display-functions', sometimes omits this information
    422   depending on space constraints;
    423 
    424 * `:face', VALUE being a symbol designating a face which both
    425   `eldoc-display-in-echo-area' and `eldoc-display-in-buffer' will
    426   use when displaying `:thing''s value.
    427 
    428 Finally, major modes should modify this hook locally, for
    429 example:
    430   (add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t)
    431 so that the global value (i.e. the default value of the hook) is
    432 taken into account if the major mode specific function does not
    433 return any documentation.")
    434 
    435 (defvar eldoc-display-functions
    436   '(eldoc-display-in-echo-area eldoc-display-in-buffer)
    437   "Hook of functions tasked with displaying ElDoc results.
    438 Each function is passed two arguments: DOCS and INTERACTIVE. DOCS
    439 is a list (DOC ...) where DOC looks like (STRING :KEY VALUE :KEY2
    440 VALUE2 ...).  STRING is a string containing the documentation's
    441 text and the remainder of DOC is an optional list of
    442 keyword-value pairs denoting additional properties of that
    443 documentation.  For commonly recognized properties, see
    444 `eldoc-documentation-functions'.
    445 
    446 INTERACTIVE says if the request to display doc strings came
    447 directly from the user or from ElDoc's automatic mechanisms'.")
    448 
    449 (defvar eldoc--doc-buffer nil "Buffer displaying latest ElDoc-produced docs.")
    450 
    451 (defvar eldoc--doc-buffer-docs nil "Documentation items in `eldoc--doc-buffer'.")
    452 
    453 (defun eldoc-doc-buffer (&optional interactive)
    454   (interactive (list t))
    455   "Display ElDoc documentation buffer.
    456 This holds the results of the last documentation request."
    457   (unless (buffer-live-p eldoc--doc-buffer)
    458     (setq eldoc--doc-buffer (get-buffer-create "*eldoc*")))
    459   (when interactive
    460     (display-buffer eldoc--doc-buffer)))
    461 
    462 (defun eldoc--format-doc-buffer (docs)
    463   "Ensure DOCS are displayed in an *eldoc* buffer."
    464   (interactive (list t))
    465   (eldoc-doc-buffer) ;; ensure buffer exists
    466   (with-current-buffer eldoc--doc-buffer
    467     (unless (eq docs eldoc--doc-buffer-docs)
    468       (setq-local eldoc--doc-buffer-docs docs)
    469       (let ((inhibit-read-only t)
    470             (things-reported-on))
    471         (erase-buffer) (setq buffer-read-only t)
    472         (local-set-key "q" 'quit-window)
    473         (cl-loop for (docs . rest) on docs
    474                  for (this-doc . plist) = docs
    475                  for thing = (plist-get plist :thing)
    476                  when thing do
    477                  (cl-pushnew thing things-reported-on)
    478                  (setq this-doc
    479                        (concat
    480                         (propertize (format "%s" thing)
    481                                     'face (plist-get plist :face))
    482                         ": "
    483                         this-doc))
    484                  do (insert this-doc)
    485                  when rest do (insert "\n"))
    486         ;; Maybe rename the buffer.
    487         (rename-buffer (if things-reported-on
    488                            (format "*eldoc for %s*"
    489                                    (mapconcat (lambda (s) (format "%s" s))
    490                                               things-reported-on
    491                                               ", "))
    492                          "*eldoc*")))))
    493   eldoc--doc-buffer)
    494 
    495 (defun eldoc--echo-area-substring (available)
    496   "Given AVAILABLE lines, get buffer substring to display in echo area.
    497 Helper for `eldoc-display-in-echo-area'."
    498   (let ((start (prog1 (progn
    499                         (goto-char (point-min))
    500                         (skip-chars-forward " \t\n")
    501                         (point))
    502                  (goto-char (line-end-position available))
    503                  (skip-chars-backward " \t\n")))
    504         (truncated (save-excursion
    505                      (skip-chars-forward " \t\n")
    506                      (not (eobp)))))
    507     (cond ((eldoc--echo-area-prefer-doc-buffer-p truncated)
    508            nil)
    509           ((and truncated
    510                 (> available 1)
    511                 eldoc-echo-area-display-truncation-message)
    512            (goto-char (line-end-position 0))
    513            (concat (buffer-substring start (point))
    514                    (format
    515                     "\n(Documentation truncated. Use `%s' to see rest)"
    516                     (substitute-command-keys "\\[eldoc-doc-buffer]"))))
    517           (t
    518            (buffer-substring start (point))))))
    519 
    520 (defun eldoc--echo-area-prefer-doc-buffer-p (truncatedp)
    521   "Tell if display in the echo area should be skipped.
    522 Helper for `eldoc-display-in-echo-area'.  If TRUNCATEDP the
    523 documentation to potentially appear in the echo are is truncated."
    524   (and (or (eq eldoc-echo-area-prefer-doc-buffer t)
    525            (and truncatedp
    526                 (eq eldoc-echo-area-prefer-doc-buffer
    527                     'maybe)))
    528        (get-buffer-window eldoc--doc-buffer)))
    529 
    530 (defun eldoc-display-in-echo-area (docs _interactive)
    531   "Display DOCS in echo area.
    532 Honor `eldoc-echo-area-use-multiline-p' and
    533 `eldoc-echo-area-prefer-doc-buffer'."
    534   (cond
    535    (;; Check if he wave permission to mess with echo area at all.  For
    536     ;; example, if this-command is non-nil while running via an idle
    537     ;; timer, we're still in the middle of executing a command, e.g. a
    538     ;; query-replace where it would be annoying to overwrite the echo
    539     ;; area.
    540     (or
    541      (not (eldoc-display-message-no-interference-p))
    542      this-command
    543      (not (eldoc--message-command-p last-command))))
    544    (;; If we do but nothing to report, clear the echo area.
    545     (null docs)
    546     (eldoc--message nil))
    547    (t
    548     ;; Otherwise, establish some parameters.
    549     (let*
    550         ((width (1- (window-width (minibuffer-window))))
    551          (val (if (and (symbolp eldoc-echo-area-use-multiline-p)
    552                        eldoc-echo-area-use-multiline-p)
    553                   max-mini-window-height
    554                 eldoc-echo-area-use-multiline-p))
    555          (available (cl-typecase val
    556                       (float (truncate (* (frame-height) val)))
    557                       (integer val)
    558                       (t 'just-one-line)))
    559          single-doc single-doc-sym)
    560       (let ((echo-area-message
    561              (cond
    562               (;; To output to the echo area, we handle the
    563                ;; `truncate-sym-name-if-fit' special case first, by
    564                ;; checking for a lot of special conditions.
    565                (and
    566                 (eq 'truncate-sym-name-if-fit eldoc-echo-area-use-multiline-p)
    567                 (null (cdr docs))
    568                 (setq single-doc (caar docs))
    569                 (setq single-doc-sym
    570                       (format "%s" (plist-get (cdar docs) :thing)))
    571                 (< (length single-doc) width)
    572                 (not (string-match "\n" single-doc))
    573                 (> (+ (length single-doc) (length single-doc-sym) 2) width))
    574                single-doc)
    575               ((and (numberp available)
    576                     (cl-plusp available))
    577                ;; Else, given a positive number of logical lines, we
    578                ;; format the *eldoc* buffer, using as most of its
    579                ;; contents as we know will fit.
    580                (with-current-buffer (eldoc--format-doc-buffer docs)
    581                  (eldoc--echo-area-substring available)))
    582               (t ;; this is the "truncate brutally" situation
    583                (let ((string
    584                       (with-current-buffer (eldoc--format-doc-buffer docs)
    585                         (buffer-substring (goto-char (point-min))
    586                                           (line-end-position 1)))))
    587                  (if (> (length string) width)  ; truncation to happen
    588                      (unless (eldoc--echo-area-prefer-doc-buffer-p t)
    589                        (truncate-string-to-width string width))
    590                    (unless (eldoc--echo-area-prefer-doc-buffer-p nil)
    591                      string)))))))
    592         (when echo-area-message
    593           (eldoc--message echo-area-message)))))))
    594 
    595 (defun eldoc-display-in-buffer (docs interactive)
    596   "Display DOCS in a dedicated buffer.
    597 If INTERACTIVE is t, also display the buffer."
    598   (let ((buf (eldoc--format-doc-buffer docs)))
    599     (when interactive
    600       (display-buffer buf))))
    601 
    602 (defun eldoc-documentation-default ()
    603   "Show first doc string for item at point.
    604 Default value for `eldoc-documentation-strategy'."
    605   (run-hook-with-args-until-success 'eldoc-documentation-functions
    606                                     (eldoc--make-callback :patient)))
    607 
    608 (defun eldoc--documentation-compose-1 (eagerlyp)
    609   "Helper function for composing multiple doc strings.
    610 If EAGERLYP is non-nil show documentation as soon as possible,
    611 else wait for all doc strings."
    612   (run-hook-wrapped 'eldoc-documentation-functions
    613                     (lambda (f)
    614                       (let* ((callback (eldoc--make-callback
    615                                         (if eagerlyp :eager :patient)))
    616                              (str (funcall f callback)))
    617                         (if (or (null str) (stringp str)) (funcall callback str))
    618                         nil)))
    619   t)
    620 
    621 (defun eldoc-documentation-compose ()
    622   "Show multiple doc strings at once after waiting for all.
    623 Meant as a value for `eldoc-documentation-strategy'."
    624   (eldoc--documentation-compose-1 nil))
    625 
    626 (defun eldoc-documentation-compose-eagerly ()
    627   "Show multiple doc strings at once as soon as possible.
    628 Meant as a value for `eldoc-documentation-strategy'."
    629   (eldoc--documentation-compose-1 t))
    630 
    631 (defun eldoc-documentation-enthusiast ()
    632   "Show most important doc string produced so far.
    633 Meant as a value for `eldoc-documentation-strategy'."
    634   (run-hook-wrapped 'eldoc-documentation-functions
    635                     (lambda (f)
    636                       (let* ((callback (eldoc--make-callback :enthusiast))
    637                              (str (funcall f callback)))
    638                         (if (stringp str) (funcall callback str))
    639                         nil)))
    640   t)
    641 
    642 ;; JT@2020-07-10: ElDoc is pre-loaded, so in Emacs < 28 we can't
    643 ;; make the "old" `eldoc-documentation-function' point to the new
    644 ;; `eldoc-documentation-strategy', so we do the reverse.  This allows
    645 ;; for ElDoc to be loaded in those older Emacs versions and work with
    646 ;; whomever (major-modes, extensions, user) sets one or the other
    647 ;; variable.
    648 (defmacro eldoc--documentation-strategy-defcustom
    649     (main secondary value docstring &rest more)
    650   "Defcustom helper macro for sorting `eldoc-documentation-strategy'."
    651   (declare (indent 2))
    652   `(if (< emacs-major-version 28)
    653        (progn
    654          (defcustom ,secondary ,value ,docstring ,@more)
    655          (define-obsolete-variable-alias ',main ',secondary "eldoc-1.1.0"))
    656        (progn
    657          (defcustom ,main ,value ,docstring  ,@more)
    658          (defvaralias ',secondary ',main ,docstring))))
    659 
    660 (eldoc--documentation-strategy-defcustom eldoc-documentation-strategy
    661     eldoc-documentation-function
    662   #'eldoc-documentation-default
    663   "How to collect and organize results of `eldoc-documentation-functions'.
    664 
    665 This variable controls how `eldoc-documentation-functions', which
    666 specifies the sources of documentation, is queried and how its
    667 results are organized before being displayed to the user.  The
    668 following values are allowed:
    669 
    670 - `eldoc-documentation-default': calls functions in the special
    671   hook in order until one is found that produces a doc string
    672   value.  Display only that value;
    673 
    674 - `eldoc-documentation-compose': calls all functions in the
    675   special hook and displays all of the resulting doc strings
    676   together.  Wait for all strings to be ready, and preserve their
    677   relative as specified by the order of functions in the hook;
    678 
    679 - `eldoc-documentation-compose-eagerly': calls all functions in
    680   the special hook and display as many of the resulting doc
    681   strings as possible, as soon as possibl.  Preserving the
    682   relative order of doc strings;
    683 
    684 - `eldoc-documentation-enthusiast': calls all functions in the
    685   special hook and displays only the most important resulting
    686   docstring one at any given time.  A function appearing first in
    687   the special hook is considered more important.
    688 
    689 This variable can also be set to a function of no args that
    690 returns something other than a string or nil and allows for some
    691 or all of the special hook `eldoc-documentation-functions' to be
    692 run.  In that case, the strategy function should follow that
    693 other variable's protocol closely and endeavor to display the
    694 resulting doc strings itself.
    695 
    696 For backward compatibility to the \"old\" protocol, this variable
    697 can also be set to a function that returns nil or a doc string,
    698 depending whether or not there is documentation to display at
    699 all."
    700   :link '(info-link "(emacs) Lisp Doc")
    701   :type '(radio (function-item eldoc-documentation-default)
    702                 (function-item eldoc-documentation-compose)
    703                 (function-item eldoc-documentation-compose-eagerly)
    704                 (function-item eldoc-documentation-enthusiast)
    705                 (function :tag "Other function"))
    706   :version "28.1")
    707 
    708 (defun eldoc--supported-p ()
    709   "Non-nil if an ElDoc function is set for this buffer."
    710   (and (not (memq eldoc-documentation-strategy '(nil ignore)))
    711        (or eldoc-documentation-functions
    712            ;; The old API had major modes set `eldoc-documentation-function'
    713            ;; to provide eldoc support.  It's impossible now to determine
    714            ;; reliably whether the `eldoc-documentation-strategy' provides
    715            ;; eldoc support (as in the old API) or whether it just provides
    716            ;; a way to combine the results of the
    717            ;; `eldoc-documentation-functions' (as in the new API).
    718            ;; But at least if it's set buffer-locally it's a good hint that
    719            ;; there's some eldoc support in the current buffer.
    720            (local-variable-p 'eldoc-documentation-strategy))))
    721 
    722 (defvar eldoc--enthusiasm-curbing-timer nil
    723   "Timer used by the `eldoc-documentation-enthusiast' strategy.
    724 When a doc string is encountered, it must endure a certain amount
    725 of time unchallenged until it is displayed to the user.  This
    726 prevents blinking if a lower priority docstring comes in shortly
    727 before a higher priority one.")
    728 
    729 (defalias 'eldoc #'eldoc-print-current-symbol-info)
    730 
    731 ;; This variable should be unbound, but that confuses
    732 ;; `describe-symbol' for some reason.
    733 (defvar eldoc--make-callback nil "Helper for function `eldoc--make-callback'.")
    734 
    735 ;; JT@2020-07-08: the below docstring for the internal function
    736 ;; `eldoc--invoke-strategy' could be moved to
    737 ;; `eldoc-documentation-strategy' or thereabouts if/when we decide to
    738 ;; extend or publish the `make-callback' protocol.
    739 (defun eldoc--make-callback (method)
    740   "Make callback suitable for `eldoc-documentation-functions'.
    741 The return value is a function FN whose lambda list is (STRING
    742 &rest PLIST) and can be called by those functions.  Its
    743 responsibility is always to register the docstring STRING along
    744 with options specified in PLIST as the documentation to display
    745 for each particular situation.
    746 
    747 METHOD specifies how the callback behaves relative to other
    748 competing elements in `eldoc-documentation-functions'.  It can
    749 have the following values:
    750 
    751 - `:enthusiast' says to display STRING as soon as possible if
    752   there's no higher priority doc string;
    753 
    754 - `:patient' says to display STRING along with all other
    755    competing strings but only when all of all
    756    `eldoc-documentation-functions' have been collected;
    757 
    758 - `:eager' says to display STRING along with all other competing
    759   strings so far, as soon as possible."
    760   (funcall eldoc--make-callback method))
    761 
    762 (defun eldoc--invoke-strategy (interactive)
    763   "Invoke `eldoc-documentation-strategy' function.
    764 
    765 If INTERACTIVE is non-nil, the request came directly from a user
    766 command, otherwise it came from ElDoc's idle
    767 timer, `eldoc-timer'.
    768 
    769 That function's job is to run the `eldoc-documentation-functions'
    770 special hook, using the `run-hook' family of functions.  ElDoc's
    771 built-in strategy functions play along with the
    772 `eldoc--make-callback' protocol, using it to produce a callback
    773 argument to feed the functions that the user places in
    774 `eldoc-documentation-functions'.  Whenever the strategy
    775 determines it has information to display to the user, this
    776 function passes responsibility to the functions in
    777 `eldoc-display-functions'.
    778 
    779 Other third-party values of `eldoc-documentation-strategy' should
    780 not use `eldoc--make-callback'.  They must find some alternate
    781 way to produce callbacks to feed to
    782 `eldoc-documentation-function' and should endeavour to display
    783 the docstrings eventually produced, using
    784 `eldoc-display-functions'."
    785   (let* (;; How many callbacks have been created by the strategy
    786          ;; function and passed to elements of
    787          ;; `eldoc-documentation-functions'.
    788          (howmany 0)
    789          ;; How many calls to callbacks we're still waiting on.  Used
    790          ;; by `:patient'.
    791          (want 0)
    792          ;; The doc strings and corresponding options registered so
    793          ;; far.
    794          (docs-registered '()))
    795     (cl-labels
    796         ((register-doc
    797           (pos string plist)
    798           (when (and string (> (length string) 0))
    799             (push (cons pos (cons string plist)) docs-registered)))
    800          (display-doc
    801           ()
    802           (run-hook-with-args
    803            'eldoc-display-functions (mapcar #'cdr
    804                                             (setq docs-registered
    805                                                   (sort docs-registered
    806                                                         (lambda (a b) (< (car a) (car b))))))
    807            interactive))
    808          (make-callback
    809           (method)
    810           (let ((pos (prog1 howmany (cl-incf howmany))))
    811             (cl-ecase method
    812               (:enthusiast
    813                (lambda (string &rest plist)
    814                  (when (and string (cl-loop for (p) in docs-registered
    815                                             never (< p pos)))
    816                    (setq docs-registered '())
    817                    (register-doc pos string plist))
    818                  (when (and (timerp eldoc--enthusiasm-curbing-timer)
    819                             (memq eldoc--enthusiasm-curbing-timer
    820                                   timer-list))
    821                    (cancel-timer eldoc--enthusiasm-curbing-timer))
    822                  (setq eldoc--enthusiasm-curbing-timer
    823                        (run-at-time (unless (zerop pos) 0.3)
    824                                     nil #'display-doc))
    825                  t))
    826               (:patient
    827                (cl-incf want)
    828                (lambda (string &rest plist)
    829                  (register-doc pos string plist)
    830                  (when (zerop (cl-decf want)) (display-doc))
    831                  t))
    832               (:eager
    833                (lambda (string &rest plist)
    834                  (register-doc pos string plist)
    835                  (display-doc)
    836                  t))))))
    837       (let* ((eldoc--make-callback #'make-callback)
    838              (res (funcall eldoc-documentation-strategy)))
    839         ;; Observe the old and the new protocol:
    840         (cond (;; Old protocol: got string, output immediately;
    841                (stringp res) (register-doc 0 res nil) (display-doc))
    842               (;; Old protocol: got nil, clear the echo area;
    843                (null res) (eldoc--message nil))
    844               (;; New protocol: trust callback will be called;
    845                t))))))
    846 
    847 (defun eldoc-print-current-symbol-info (&optional interactive)
    848   "Document thing at point."
    849   (interactive '(t))
    850   (let (token)
    851     (cond (interactive
    852            (eldoc--invoke-strategy t))
    853           ((not (equal (setq token (eldoc--request-state))
    854                        eldoc--last-request-state))
    855            (let ((non-essential t))
    856              (setq eldoc--last-request-state token)
    857              ;; Only keep looking for the info as long as the user hasn't
    858              ;; requested our attention.  This also locally disables
    859              ;; inhibit-quit.
    860              (while-no-input
    861                (eldoc--invoke-strategy nil)))))))
    862 
    863 
    864 ;; This section only affects ElDoc output to the echo area, as in
    865 ;; `eldoc-display-in-echo-area'.
    866 ;;
    867 ;; When point is in a sexp, the function args are not reprinted in the echo
    868 ;; area after every possible interactive command because some of them print
    869 ;; their own messages in the echo area; the eldoc functions would instantly
    870 ;; overwrite them unless it is more restrained.
    871 ;; These functions do display-command table management.
    872 
    873 (defun eldoc-add-command (&rest cmds)
    874   "Add each of CMDS to the obarray `eldoc-message-commands'."
    875   (dolist (name cmds)
    876     (and (symbolp name)
    877          (setq name (symbol-name name)))
    878     (set (intern name eldoc-message-commands) t)))
    879 
    880 (defun eldoc-add-command-completions (&rest names)
    881   "Pass every prefix completion of NAMES to `eldoc-add-command'."
    882   (dolist (name names)
    883     (apply #'eldoc-add-command (all-completions name obarray 'commandp))))
    884 
    885 (defun eldoc-remove-command (&rest cmds)
    886   "Remove each of CMDS from the obarray `eldoc-message-commands'."
    887   (dolist (name cmds)
    888     (and (symbolp name)
    889          (setq name (symbol-name name)))
    890     (unintern name eldoc-message-commands)))
    891 
    892 (defun eldoc-remove-command-completions (&rest names)
    893   "Pass every prefix completion of NAMES to `eldoc-remove-command'."
    894   (dolist (name names)
    895     (apply #'eldoc-remove-command
    896            (all-completions name eldoc-message-commands))))
    897 
    898 ;; Prime the command list.
    899 (eldoc-add-command-completions
    900  "back-to-indentation"
    901  "backward-" "beginning-of-" "delete-other-windows" "delete-window"
    902  "down-list" "end-of-" "exchange-point-and-mark" "forward-" "goto-"
    903  "handle-select-window" "indent-for-tab-command" "left-" "mark-page"
    904  "mark-paragraph" "mouse-set-point" "move-" "move-beginning-of-"
    905  "move-end-of-" "newline" "next-" "other-window" "pop-global-mark"
    906  "previous-" "recenter" "right-" "scroll-" "self-insert-command"
    907  "split-window-" "up-list")
    908 
    909 ;;;; ChangeLog:
    910 
    911 
    912 
    913 (provide 'eldoc)
    914 
    915 ;;; eldoc.el ends here