aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Távora2020-09-06 15:37:02 +0100
committerJoão Távora2020-10-24 18:02:28 +0100
commit4c543a724f2caff41d97a323bd4fffe3e86e8471 (patch)
tree2525691df42cf40b7677cbef71c6cecfa0807afa
parent8c2382d309b437dca94d453e4bd5f3169bb36bfb (diff)
downloademacs-4c543a724f2caff41d97a323bd4fffe3e86e8471.tar.gz
emacs-4c543a724f2caff41d97a323bd4fffe3e86e8471.zip
Introduce eldoc-display-functions
See bug#43609. * lisp/emacs-lisp/eldoc.el (eldoc--request-state): Add comment. (eldoc--last-request-state): No longer buffer-local. (eldoc--request-docs-p): Delete. (eldoc-display-functions): New user variable. (eldoc--doc-buffer-docs): New variable. (eldoc-display-message-p): Rework. (eldoc--format-doc-buffer): Rework from eldoc--handle-docs. (eldoc-display-in-echo-area, eldoc-display-in-buffer): New user-visible function. (eldoc--invoke-strategy): Take INTERACTIVE arg. Invoke eldoc-display-in-buffer (eldoc-print-current-symbol-info): Simplify. (Version): Bump to 1.11.0 * etc/NEWS: Mention eldoc-display-functions.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/emacs-lisp/eldoc.el268
2 files changed, 164 insertions, 111 deletions
diff --git a/etc/NEWS b/etc/NEWS
index a405c0dd3d7..8aa27fd651e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -650,6 +650,13 @@ may arrange for it to be produced asynchronously. The results of all
650doc string functions are accessible to the user through the user 650doc string functions are accessible to the user through the user
651option 'eldoc-documentation-strategy'. 651option 'eldoc-documentation-strategy'.
652 652
653*** New hook 'eldoc-display-functions'.
654This hook is intended to be used for displaying doc string. The
655functions receive the docstrings composed according to
656`eldoc-documentation-strategy' and are tasked with displaying it to
657the user. Examples of such functions would use the echo area, a
658separate buffer or a tooltip.
659
653+++ 660+++
654*** New user option 'eldoc-documentation-strategy'. 661*** New user option 'eldoc-documentation-strategy'.
655The built-in choices available for this user option let users compose 662The built-in choices available for this user option let users compose
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 9e38e5908ed..1b180f26c58 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -5,7 +5,7 @@
5;; Author: Noah Friedman <friedman@splode.com> 5;; Author: Noah Friedman <friedman@splode.com>
6;; Keywords: extensions 6;; Keywords: extensions
7;; Created: 1995-10-06 7;; Created: 1995-10-06
8;; Version: 1.10.0 8;; Version: 1.11.0
9;; Package-Requires: ((emacs "26.3")) 9;; Package-Requires: ((emacs "26.3"))
10 10
11;; This is a GNU ELPA :core package. Avoid functionality that is not 11;; This is a GNU ELPA :core package. Avoid functionality that is not
@@ -350,40 +350,26 @@ Also store it in `eldoc-last-message' and return that value."
350 ;; for us, but do note that the last-message will be gone. 350 ;; for us, but do note that the last-message will be gone.
351 (setq eldoc-last-message nil)))) 351 (setq eldoc-last-message nil))))
352 352
353(defvar-local eldoc--last-request-state nil 353;; The point of `eldoc--request-state' is not to over-request, which
354;; can happen if the idle timer is restarted on execution of command
355;; which is guaranteed not to change the conditions that warrant a new
356;; request for documentation.
357(defvar eldoc--last-request-state nil
354 "Tuple containing information about last ElDoc request.") 358 "Tuple containing information about last ElDoc request.")
355(defun eldoc--request-state () 359(defun eldoc--request-state ()
356 "Compute information to store in `eldoc--last-request-state'." 360 "Compute information to store in `eldoc--last-request-state'."
357 (list (current-buffer) (buffer-modified-tick) (point))) 361 (list (current-buffer) (buffer-modified-tick) (point)))
358 362
359(defun eldoc-display-message-p () 363(defun eldoc-display-message-p ()
360 (eldoc--request-docs-p (eldoc--request-state))) 364 "Tell if ElDoc can use the echo area."
365 (and (eldoc-display-message-no-interference-p)
366 (not this-command)
367 (eldoc--message-command-p last-command)))
368
361(make-obsolete 'eldoc-display-message-p 369(make-obsolete 'eldoc-display-message-p
362 "Use `eldoc-documentation-functions' instead." 370 "Use `eldoc-documentation-functions' instead."
363 "eldoc-1.6.0") 371 "eldoc-1.6.0")
364 372
365(defun eldoc--request-docs-p (request-state)
366 "Return non-nil when it is appropriate to request docs.
367REQUEST-STATE is a candidate for `eldoc--last-request-state'"
368 (and
369 ;; FIXME: The original idea behind this function is to protect the
370 ;; Echo area from ElDoc interference, but since that is only one of
371 ;; the possible outlets of ElDoc, this must soon be reworked.
372 (eldoc-display-message-no-interference-p)
373 (not (and eldoc--doc-buffer
374 (get-buffer-window eldoc--doc-buffer)
375 (equal request-state
376 (with-current-buffer
377 eldoc--doc-buffer
378 eldoc--last-request-state))))
379 ;; If this-command is non-nil while running via an idle
380 ;; timer, we're still in the middle of executing a command,
381 ;; e.g. a query-replace where it would be annoying to
382 ;; overwrite the echo area.
383 (not this-command)
384 (eldoc--message-command-p last-command)))
385
386
387;; Check various conditions about the current environment that might make 373;; Check various conditions about the current environment that might make
388;; it undesirable to print eldoc messages right this instant. 374;; it undesirable to print eldoc messages right this instant.
389(defun eldoc-display-message-no-interference-p () 375(defun eldoc-display-message-no-interference-p ()
@@ -416,43 +402,112 @@ about the context around point.
416 402
417To call the CALLBACK function, the hook function must pass it an 403To call the CALLBACK function, the hook function must pass it an
418obligatory argument DOCSTRING, a string containing the 404obligatory argument DOCSTRING, a string containing the
419documentation, followed by an optional list of keyword-value 405documentation, followed by an optional list of arbitrary
420pairs of the form (:KEY VALUE :KEY2 VALUE2...). KEY can be: 406keyword-value pairs of the form (:KEY VALUE :KEY2 VALUE2...).
421 407The information contained in these pairs is understood by members
422* `:thing', VALUE is a short string or symbol designating what is 408of `eldoc-display-functions', allowing the
423 being reported on. The documentation display engine can elect 409documentation-producing backend to cooperate with specific
424 to remove this information depending on space constraints; 410documentation-displaying frontends. For example, KEY can be:
425 411
426* `:face', VALUE is a symbol designating a face to use when 412* `:thing', VALUE being a short string or symbol designating what
427 displaying `:thing''s value. 413 is being reported on. It can, for example be the name of the
428 414 function whose signature is being documented, or the name of
429Major modes should modify this hook locally, for example: 415 the variable whose docstring is being documented.
416 `eldoc-display-in-echo-area', a member of
417 `eldoc-display-functions', sometimes omits this information
418 depending on space constraints;
419
420* `:face', VALUE being a symbol designating a face which both
421 `eldoc-display-in-echo-area' and `eldoc-display-in-buffer' will
422 use when displaying `:thing''s value.
423
424Finally, major modes should modify this hook locally, for
425example:
430 (add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t) 426 (add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t)
431so that the global value (i.e. the default value of the hook) is 427so that the global value (i.e. the default value of the hook) is
432taken into account if the major mode specific function does not 428taken into account if the major mode specific function does not
433return any documentation.") 429return any documentation.")
434 430
431(defvar eldoc-display-functions
432 '(eldoc-display-in-echo-area eldoc-display-in-buffer)
433 "Hook of functions tasked with displaying ElDoc results.
434Each function is passed two arguments: DOCS and INTERACTIVE. DOCS
435is a list (DOC ...) where DOC looks like (STRING :KEY VALUE :KEY2
436VALUE2 ...). STRING is a string containing the documentation's
437text and the remainder of DOC is an optional list of
438keyword-value pairs denoting additional properties of that
439documentation. For commonly recognized properties, see
440`eldoc-documentation-functions'.
441
442INTERACTIVE says if the request to display doc strings came
443directly from the user or from ElDoc's automatic mechanisms'.")
444
435(defvar eldoc--doc-buffer nil "Buffer displaying latest ElDoc-produced docs.") 445(defvar eldoc--doc-buffer nil "Buffer displaying latest ElDoc-produced docs.")
436 446
447(defvar eldoc--doc-buffer-docs nil "Documentation items in `eldoc--doc-buffer'.")
448
437(defun eldoc-doc-buffer (&optional interactive) 449(defun eldoc-doc-buffer (&optional interactive)
438 "Get latest *eldoc* help buffer. Interactively, display it."
439 (interactive (list t)) 450 (interactive (list t))
440 (prog1 451 "Display ElDoc documentation buffer.
441 (if (and eldoc--doc-buffer (buffer-live-p eldoc--doc-buffer)) 452This holds the results of the last documentation request."
442 eldoc--doc-buffer 453 (unless (buffer-live-p eldoc--doc-buffer)
443 (setq eldoc--doc-buffer (get-buffer-create "*eldoc*"))) 454 (setq eldoc--doc-buffer (get-buffer-create "*eldoc*")))
444 (when interactive (display-buffer eldoc--doc-buffer)))) 455 (when interactive
445 456 (display-buffer eldoc--doc-buffer)))
446 457
447(defun eldoc--handle-docs (docs) 458(defun eldoc--format-doc-buffer (docs)
448 "Display multiple DOCS in echo area. 459 "Ensure DOCS are displayed in an *eldoc* buffer."
449DOCS is a list of (STRING PLIST...). It is already sorted. 460 (interactive (list t))
450Honor most of `eldoc-echo-area-use-multiline-p'." 461 (eldoc-doc-buffer) ;; ensure buffer exists
451 ;; If there's nothing to report clear the echo area, but don't erase 462 (with-current-buffer eldoc--doc-buffer
452 ;; the last *eldoc* buffer. 463 (unless (eq docs eldoc--doc-buffer-docs)
453 (if (null docs) (eldoc--message nil) 464 (setq-local eldoc--doc-buffer-docs docs)
465 (let ((inhibit-read-only t)
466 (things-reported-on))
467 (erase-buffer) (setq buffer-read-only t)
468 (local-set-key "q" 'quit-window)
469 (cl-loop for (docs . rest) on docs
470 for (this-doc . plist) = docs
471 for thing = (plist-get plist :thing)
472 when thing do
473 (cl-pushnew thing things-reported-on)
474 (setq this-doc
475 (concat
476 (propertize (format "%s" thing)
477 'face (plist-get plist :face))
478 ": "
479 this-doc))
480 do (insert this-doc)
481 when rest do (insert "\n"))
482 ;; Maybe rename the buffer.
483 (rename-buffer (if things-reported-on
484 (format "*eldoc for %s*"
485 (mapconcat (lambda (s) (format "%s" s))
486 things-reported-on
487 ", "))
488 "*eldoc*")))))
489 eldoc--doc-buffer)
490
491(defun eldoc-display-in-echo-area (docs _interactive)
492 "Display DOCS in echo area.
493Honor `eldoc-echo-area-use-multiline-p' and
494`eldoc-prefer-doc-buffer'."
495 (cond
496 (;; Check if he wave permission to mess with echo area at all. For
497 ;; example, if this-command is non-nil while running via an idle
498 ;; timer, we're still in the middle of executing a command, e.g. a
499 ;; query-replace where it would be annoying to overwrite the echo
500 ;; area.
501 (or
502 (not (eldoc-display-message-no-interference-p))
503 this-command
504 (not (eldoc--message-command-p last-command))))
505 (;; If we do but nothing to report, clear the echo area.
506 (null docs)
507 (eldoc--message nil))
508 (t
509 ;; Otherwise, establish some parameters.
454 (let* 510 (let*
455 ;; Otherwise, establish some parameters.
456 ((width (1- (window-width (minibuffer-window)))) 511 ((width (1- (window-width (minibuffer-window))))
457 (val (if (and (symbolp eldoc-echo-area-use-multiline-p) 512 (val (if (and (symbolp eldoc-echo-area-use-multiline-p)
458 eldoc-echo-area-use-multiline-p) 513 eldoc-echo-area-use-multiline-p)
@@ -462,43 +517,12 @@ Honor most of `eldoc-echo-area-use-multiline-p'."
462 (float (truncate (* (frame-height) val))) 517 (float (truncate (* (frame-height) val)))
463 (integer val) 518 (integer val)
464 (t 1))) 519 (t 1)))
465 (things-reported-on)
466 (request eldoc--last-request-state)
467 single-doc single-doc-sym) 520 single-doc single-doc-sym)
468 ;; Then, compose the contents of the `*eldoc*' buffer.
469 (with-current-buffer (eldoc-doc-buffer)
470 ;; Set doc-buffer's `eldoc--last-request-state', too
471 (setq eldoc--last-request-state request)
472 (let ((inhibit-read-only t))
473 (erase-buffer) (setq buffer-read-only t)
474 (local-set-key "q" 'quit-window)
475 (cl-loop for (docs . rest) on docs
476 for (this-doc . plist) = docs
477 for thing = (plist-get plist :thing)
478 when thing do
479 (cl-pushnew thing things-reported-on)
480 (setq this-doc
481 (concat
482 (propertize (format "%s" thing)
483 'face (plist-get plist :face))
484 ": "
485 this-doc))
486 do (insert this-doc)
487 when rest do (insert "\n")))
488 ;; Rename the buffer.
489 (when things-reported-on
490 (rename-buffer (format "*eldoc for %s*"
491 (mapconcat (lambda (s) (format "%s" s))
492 things-reported-on
493 ", ")))))
494 ;; Finally, output to the echo area. I'm pretty sure nicer
495 ;; strategies can be used here, probably by splitting this
496 ;; function into some `eldoc-display-functions' special hook.
497 (let ((echo-area-message 521 (let ((echo-area-message
498 (cond 522 (cond
499 (;; We handle the `truncate-sym-name-if-fit' special 523 (;; To output to the echo area,We handle the
500 ;; case first, by checking if for a lot of special 524 ;; `truncate-sym-name-if-fit' special case first, by
501 ;; conditions. 525 ;; checking if for a lot of special conditions.
502 (and 526 (and
503 (eq 'truncate-sym-name-if-fit eldoc-echo-area-use-multiline-p) 527 (eq 'truncate-sym-name-if-fit eldoc-echo-area-use-multiline-p)
504 (null (cdr docs)) 528 (null (cdr docs))
@@ -514,7 +538,11 @@ Honor most of `eldoc-echo-area-use-multiline-p'."
514 ;; display that, we have one extra line to use. 538 ;; display that, we have one extra line to use.
515 (unless eldoc-display-truncation-message 539 (unless eldoc-display-truncation-message
516 (setq available (1+ available))) 540 (setq available (1+ available)))
517 (with-current-buffer (eldoc-doc-buffer) 541 ;; Else we format the *eldoc* buffer, then use some of
542 ;; its contents top section. I'm pretty sure smarter
543 ;; strategies can be used here that don't necessarily
544 ;; involve composing that entire buffer.
545 (with-current-buffer (eldoc--format-doc-buffer docs)
518 (cl-loop 546 (cl-loop
519 initially 547 initially
520 (goto-char (point-min)) 548 (goto-char (point-min))
@@ -543,11 +571,18 @@ Honor most of `eldoc-echo-area-use-multiline-p'."
543 "...")))))))) 571 "..."))))))))
544 ((= available 1) 572 ((= available 1)
545 ;; Truncate "brutally." ; FIXME: use `eldoc-prefer-doc-buffer' too? 573 ;; Truncate "brutally." ; FIXME: use `eldoc-prefer-doc-buffer' too?
546 (with-current-buffer (eldoc-doc-buffer) 574 (with-current-buffer (eldoc--format-doc-buffer docs)
547 (truncate-string-to-width 575 (truncate-string-to-width
548 (buffer-substring (goto-char (point-min)) (line-end-position 1)) width)))))) 576 (buffer-substring (goto-char (point-min)) (line-end-position 1)) width))))))
549 (when echo-area-message 577 (when echo-area-message
550 (eldoc--message echo-area-message)))))) 578 (eldoc--message echo-area-message)))))))
579
580(defun eldoc-display-in-buffer (docs interactive)
581 "Display DOCS in a dedicated buffer.
582If INTERACTIVE is t, also display the buffer."
583 (let ((buf (eldoc--format-doc-buffer docs)))
584 (when interactive
585 (display-buffer buf))))
551 586
552(defun eldoc-documentation-default () 587(defun eldoc-documentation-default ()
553 "Show first doc string for item at point. 588 "Show first doc string for item at point.
@@ -709,19 +744,29 @@ have the following values:
709 strings so far, as soon as possible." 744 strings so far, as soon as possible."
710 (funcall eldoc--make-callback method)) 745 (funcall eldoc--make-callback method))
711 746
712(defun eldoc--invoke-strategy () 747(defun eldoc--invoke-strategy (interactive)
713 "Invoke `eldoc-documentation-strategy' function. 748 "Invoke `eldoc-documentation-strategy' function.
714 749
750If INTERACTIVE is non-nil, the request came directly from a user
751command, otherwise it came from ElDoc's idle
752timer, `eldoc-timer'.
753
715That function's job is to run the `eldoc-documentation-functions' 754That function's job is to run the `eldoc-documentation-functions'
716special hook, using the `run-hook' family of functions. ElDoc's 755special hook, using the `run-hook' family of functions. ElDoc's
717built-in strategy functions play along with the 756built-in strategy functions play along with the
718`eldoc--make-callback' protocol, using it to produce callback to 757`eldoc--make-callback' protocol, using it to produce a callback
719feed to the functgions of `eldoc-documentation-functions'. 758argument to feed the functions that the user places in
720 759`eldoc-documentation-functions'. Whenever the strategy
721Other third-party strategy functions do not use 760determines it has information to display to the user, this
722`eldoc--make-callback'. They must find some alternate way to 761function passes responsibility to the functions in
723produce callbacks to feed to `eldoc-documentation-function' and 762`eldoc-display-functions'.
724should endeavour to display the docstrings eventually produced." 763
764Other third-party values of `eldoc-documentation-strategy' should
765not use `eldoc--make-callback'. They must find some alternate
766way to produce callbacks to feed to
767`eldoc-documentation-function' and should endeavour to display
768the docstrings eventually produced, using
769`eldoc-display-functions'."
725 (let* (;; How many callbacks have been created by the strategy 770 (let* (;; How many callbacks have been created by the strategy
726 ;; function and passed to elements of 771 ;; function and passed to elements of
727 ;; `eldoc-documentation-functions'. 772 ;; `eldoc-documentation-functions'.
@@ -739,11 +784,12 @@ should endeavour to display the docstrings eventually produced."
739 (push (cons pos (cons string plist)) docs-registered))) 784 (push (cons pos (cons string plist)) docs-registered)))
740 (display-doc 785 (display-doc
741 () 786 ()
742 (eldoc--handle-docs 787 (run-hook-with-args
743 (mapcar #'cdr 788 'eldoc-display-functions (mapcar #'cdr
744 (setq docs-registered 789 (setq docs-registered
745 (sort docs-registered 790 (sort docs-registered
746 (lambda (a b) (< (car a) (car b)))))))) 791 (lambda (a b) (< (car a) (car b))))))
792 interactive))
747 (make-callback 793 (make-callback
748 (method) 794 (method)
749 (let ((pos (prog1 howmany (cl-incf howmany)))) 795 (let ((pos (prog1 howmany (cl-incf howmany))))
@@ -786,22 +832,23 @@ should endeavour to display the docstrings eventually produced."
786(defun eldoc-print-current-symbol-info (&optional interactive) 832(defun eldoc-print-current-symbol-info (&optional interactive)
787 "Document thing at point." 833 "Document thing at point."
788 (interactive '(t)) 834 (interactive '(t))
789 (let ((token (eldoc--request-state))) 835 (let (token)
790 (cond (interactive 836 (cond (interactive
791 (eldoc--invoke-strategy)) 837 (eldoc--invoke-strategy t))
792 ((not (eldoc--request-docs-p token)) 838 ((not (equal (setq token (eldoc--request-state))
793 ;; Erase the last message if we won't display a new one. 839 eldoc--last-request-state))
794 (when eldoc-last-message
795 (eldoc--message nil)))
796 (t
797 (let ((non-essential t)) 840 (let ((non-essential t))
798 (setq eldoc--last-request-state token) 841 (setq eldoc--last-request-state token)
799 ;; Only keep looking for the info as long as the user hasn't 842 ;; Only keep looking for the info as long as the user hasn't
800 ;; requested our attention. This also locally disables 843 ;; requested our attention. This also locally disables
801 ;; inhibit-quit. 844 ;; inhibit-quit.
802 (while-no-input 845 (while-no-input
803 (eldoc--invoke-strategy))))))) 846 (eldoc--invoke-strategy nil)))))))
804 847
848
849;; This section only affects ElDoc output to the echo area, as in
850;; `eldoc-display-in-echo-area'.
851;;
805;; When point is in a sexp, the function args are not reprinted in the echo 852;; When point is in a sexp, the function args are not reprinted in the echo
806;; area after every possible interactive command because some of them print 853;; area after every possible interactive command because some of them print
807;; their own messages in the echo area; the eldoc functions would instantly 854;; their own messages in the echo area; the eldoc functions would instantly
@@ -833,7 +880,6 @@ should endeavour to display the docstrings eventually produced."
833 (apply #'eldoc-remove-command 880 (apply #'eldoc-remove-command
834 (all-completions name eldoc-message-commands)))) 881 (all-completions name eldoc-message-commands))))
835 882
836
837;; Prime the command list. 883;; Prime the command list.
838(eldoc-add-command-completions 884(eldoc-add-command-completions
839 "back-to-indentation" 885 "back-to-indentation"