dotemacs

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

eldoc.el (44188B)


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