[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#28257: 26.0.50; [PATCH] expose eldoc functions in a hook

From: Mark Oteiza
Subject: bug#28257: 26.0.50; [PATCH] expose eldoc functions in a hook
Date: Fri, 14 Feb 2020 17:54:15 -0500

Thanks Noam and Stefan for the catches.  New patch below.

On 14/02/20 at 09:50am, Stefan Monnier wrote:
> > +*** 'eldoc-documentation-function' is now a custom variable.
> I think this should be expanded to clarify that packages should stop
> using this var and use `eldoc-documentation-functions` instead.
> <...snip...>

 doc/emacs/programs.texi      | 24 ++++++++++++--
 etc/NEWS                     | 12 +++++++
 lisp/emacs-lisp/eldoc.el     | 75 ++++++++++++++++++++++++++++++++++----------
 lisp/hexl.el                 |  6 ++--
 lisp/ielm.el                 |  4 +--
 lisp/progmodes/cfengine.el   | 15 +++++----
 lisp/progmodes/elisp-mode.el |  4 +--
 lisp/progmodes/octave.el     |  3 +-
 lisp/progmodes/python.el     |  6 ++--
 9 files changed, 113 insertions(+), 36 deletions(-)

diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index 683374c615..8e2a22b2ff 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -1269,9 +1269,27 @@ Lisp Doc
 for a function, it shows the argument list, and for a variable it
 shows the first line of the variable's documentation string.  To
 toggle Eldoc mode, type @kbd{M-x eldoc-mode}.  There's also a Global
-Eldoc mode, which is turned on by default, and affects buffers, such
-as @samp{*scratch*}, whose major mode is Emacs Lisp or Lisp
-Interaction (@w{@kbd{M-x global-eldoc-mode}} to turn it off globally).
+Eldoc mode, which is turned on by default, and affects buffers whose
+major mode sets the variables described below.  Use @w{@kbd{M-x
+global-eldoc-mode}} to turn it off globally.
+@vindex eldoc-documentation-function
+@vindex eldoc-documentation-functions
+  These variables can be used to configure ElDoc mode:
+@table @code
+@item eldoc-documentation-function
+This variable holds the function which is used to retrieve
+documentation for the item at point from the functions in the hook
+@code{eldoc-documentation-functions}.  By default,
+@code{eldoc-documentation-function} returns the first documentation
+string produced by the @code{eldoc-documentation-functions} hook.
+@item eldoc-documentation-functions
+This abnormal hook holds documentation functions.  It acts as a
+collection of backends for ElDoc. This is what modes should use to
+register their documentation functions with ElDoc.
+@end table
 @node Hideshow
 @section Hideshow minor mode
diff --git a/etc/NEWS b/etc/NEWS
index b0e17c7c03..793be515c5 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -120,6 +120,18 @@ To revert to the previous behaviour,
 unconditionally aborts the current edebug instrumentation with the
 supplied error message.
+** ElDoc
+*** New hook 'eldoc-documentation-functions' to be used for registering
+doc string functions.  This makes the results of all doc string
+functions accessible to the user through the existing single function hook
+*** 'eldoc-documentation-function' is now a custom variable.
+Modes should use the new hook instead of this variable to register
+their backends.
 ** Tramp
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 7a7b8ec164..d96e569fca 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -40,9 +40,9 @@
 ;;      (add-hook 'ielm-mode-hook 'eldoc-mode)
 ;;      (add-hook 'eval-expression-minibuffer-setup-hook 'eldoc-mode)
-;; Major modes for other languages may use ElDoc by defining an
-;; appropriate function as the buffer-local value of
-;; `eldoc-documentation-function'.
+;; Major modes for other languages may use ElDoc by adding an
+;; appropriate function to the buffer-local value of
+;; `eldoc-documentation-functions'.
 ;;; Code:
@@ -222,8 +222,8 @@ global-eldoc-mode
 (defun eldoc--eval-expression-setup ()
   ;; Setup `eldoc', similar to `emacs-lisp-mode'.  FIXME: Call
   ;; `emacs-lisp-mode' itself?
-  (add-function :before-until (local 'eldoc-documentation-function)
-                #'elisp-eldoc-documentation-function)
+  (add-hook 'eldoc-documentation-functions
+            #'elisp-eldoc-documentation-function nil t)
   (eldoc-mode +1))
@@ -235,7 +235,11 @@ turn-on-eldoc-mode
 (defun eldoc--supported-p ()
   "Non-nil if an ElDoc function is set for this buffer."
-  (not (memq eldoc-documentation-function '(nil ignore))))
+  (let ((hook 'eldoc-documentation-functions))
+    (and (not (memq eldoc-documentation-function '(nil ignore)))
+         (or (and (local-variable-p hook)
+                  (buffer-local-value hook (current-buffer)))
+             (default-value hook)))))
 (defun eldoc-schedule-timer ()
@@ -347,8 +351,46 @@ eldoc-display-message-no-interference-p
   (not (or executing-kbd-macro (bound-and-true-p edebug-active))))
-(defvar eldoc-documentation-function #'ignore
+(defvar eldoc-documentation-functions nil
+  "Hook for functions to call to return doc string.
+Each function should accept no arguments and return a one-line
+string for displaying doc about a function etc. appropriate to
+the context around point.  It should return nil if there's no doc
+appropriate for the context.  Typically doc is returned if point
+is on a function-like name or in its arg list.
+Major modes should modify this hook locally, for example:
+  (add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t)
+so that the global value (i.e. the default value of the hook) is
+taken into account if the major mode specific function does not
+return any documentation.")
+(defun eldoc-documentation-default ()
+  "Show first doc string for item at point.
+Default value for `eldoc-documentation-function'."
+  (let ((res (run-hook-with-args-until-success 
+    (when res
+      (if eldoc-echo-area-use-multiline-p res
+        (truncate-string-to-width
+         res (1- (window-width (minibuffer-window))))))))
+(defun eldoc-documentation-compose ()
+  "Show multiple doc string results at once.
+Meant as a value for `eldoc-documentation-function'."
+  (let (res)
+    (run-hook-wrapped
+     'eldoc-documentation-functions
+     (lambda (f)
+       (let ((str (funcall f)))
+         (when str (push str res))
+         nil)))
+    (when res
+      (setq res (mapconcat #'identity (nreverse res) ", "))
+      (if eldoc-echo-area-use-multiline-p res
+        (truncate-string-to-width
+         res (1- (window-width (minibuffer-window))))))))
+(defcustom eldoc-documentation-function #'eldoc-documentation-default
   "Function to call to return doc string.
 The function of no args should return a one-line string for displaying
 doc about a function etc. appropriate to the context around point.
@@ -359,14 +401,12 @@ eldoc-documentation-function
 The result is used as is, so the function must explicitly handle
 the variables `eldoc-argument-case' and `eldoc-echo-area-use-multiline-p',
 and the face `eldoc-highlight-function-argument', if they are to have any
-Major modes should modify this variable using `add-function', for example:
-  (add-function :before-until (local \\='eldoc-documentation-function)
-                #\\='foo-mode-eldoc-function)
-so that the global documentation function (i.e. the default value of the
-variable) is taken into account if the major mode specific function does not
-return any documentation.")
+  :link '(info-link "(emacs) Lisp Doc")
+  :type '(radio (function-item eldoc-documentation-default)
+                (function-item eldoc-documentation-compose)
+                (function :tag "Other function"))
+  :group 'eldoc)
 (defun eldoc-print-current-symbol-info ()
   "Print the text produced by `eldoc-documentation-function'."
@@ -381,7 +421,8 @@ eldoc-print-current-symbol-info
         ;; Only keep looking for the info as long as the user hasn't
         ;; requested our attention.  This also locally disables inhibit-quit.
-          (eldoc-message (funcall eldoc-documentation-function)))))))
+          (let ((fun eldoc-documentation-function))
+            (when fun (eldoc-message (funcall fun)))))))))
 ;; If the entire line cannot fit in the echo area, the symbol name may be
 ;; truncated or eliminated entirely from the output to make room for the
diff --git a/lisp/hexl.el b/lisp/hexl.el
index 58518e7416..cf7118f208 100644
--- a/lisp/hexl.el
+++ b/lisp/hexl.el
@@ -367,8 +367,8 @@ hexl-mode
     (add-hook 'change-major-mode-hook #'hexl-maybe-dehexlify-buffer nil t)
     ;; Set a callback function for eldoc.
-    (add-function :before-until (local 'eldoc-documentation-function)
-                  #'hexl-print-current-point-info)
+    (add-hook 'eldoc-documentation-functions
+              #'hexl-print-current-point-info nil t)
     (eldoc-add-command-completions "hexl-")
     (eldoc-remove-command "hexl-save-buffer"
@@ -455,6 +455,8 @@ hexl-revert-buffer-function
     ;; 2. reset change-major-mode-hook in case that `hexl-mode'
     ;; previously added hexl-maybe-dehexlify-buffer to it.
     (remove-hook 'change-major-mode-hook #'hexl-maybe-dehexlify-buffer t)
+    (remove-hook 'eldoc-documentation-functions
+                 #'hexl-print-current-point-info t)
     (setq major-mode 'fundamental-mode)
diff --git a/lisp/ielm.el b/lisp/ielm.el
index 41675c011d..fc06ebfa2d 100644
--- a/lisp/ielm.el
+++ b/lisp/ielm.el
@@ -541,8 +541,8 @@ inferior-emacs-lisp-mode
   (set (make-local-variable 'completion-at-point-functions)
          ielm-complete-filename elisp-completion-at-point))
-  (add-function :before-until (local 'eldoc-documentation-function)
-                #'elisp-eldoc-documentation-function)
+  (add-hook 'eldoc-documentation-functions
+            #'elisp-eldoc-documentation-function nil t)
   (set (make-local-variable 'ielm-prompt-internal) ielm-prompt)
   (set (make-local-variable 'comint-prompt-read-only) ielm-prompt-read-only)
   (setq comint-get-old-input 'ielm-get-old-input)
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el
index 9ddb2ab2bb..a94a6666bb 100644
--- a/lisp/progmodes/cfengine.el
+++ b/lisp/progmodes/cfengine.el
@@ -1390,12 +1390,15 @@ cfengine3-mode
                  (when buffer-file-name
                    (shell-quote-argument buffer-file-name)))))
-  ;; For emacs < 25.1 where `eldoc-documentation-function' defaults to
-  ;; nil.
-  (or eldoc-documentation-function
-      (setq-local eldoc-documentation-function #'ignore))
-  (add-function :before-until (local 'eldoc-documentation-function)
-                #'cfengine3-documentation-function)
+  (if (boundp 'eldoc-documentation-functions)
+      (add-hook 'eldoc-documentation-functions
+                #'cfengine3-documentation-function nil t)
+    ;; For emacs < 25.1 where `eldoc-documentation-function' defaults
+    ;; to nil.
+    (or eldoc-documentation-function
+        (setq-local eldoc-documentation-function #'ignore))
+    (add-function :before-until (local 'eldoc-documentation-function)
+                  #'cfengine3-documentation-function))
   (add-hook 'completion-at-point-functions
             #'cfengine3-completion-function nil t)
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 2617a6e4cc..813b628bc3 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -250,8 +250,8 @@ emacs-lisp-mode
     (add-hook 'electric-pair-mode-hook #'emacs-lisp-set-electric-text-pairs))
   (setq-local electric-quote-string t)
   (setq imenu-case-fold-search nil)
-  (add-function :before-until (local 'eldoc-documentation-function)
-                #'elisp-eldoc-documentation-function)
+  (add-hook 'eldoc-documentation-functions
+            #'elisp-eldoc-documentation-function nil t)
   (add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
   (setq-local project-vc-external-roots-function #'elisp-load-path-roots)
   (add-hook 'completion-at-point-functions
diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el
index 9e03956254..352c1810d1 100644
--- a/lisp/progmodes/octave.el
+++ b/lisp/progmodes/octave.el
@@ -619,8 +619,7 @@ octave-mode
   (add-hook 'before-save-hook 'octave-sync-function-file-names nil t)
   (setq-local beginning-of-defun-function 'octave-beginning-of-defun)
   (and octave-font-lock-texinfo-comment (octave-font-lock-texinfo-comment))
-  (add-function :before-until (local 'eldoc-documentation-function)
-                'octave-eldoc-function)
+  (add-hook 'eldoc-documentation-functions 'octave-eldoc-function nil t)
   (easy-menu-add octave-mode-menu))
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index a2d85d0bef..67383b3415 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -5544,8 +5544,10 @@ python-mode
       ;; Emacs<25
       (set (make-local-variable 'eldoc-documentation-function)
-    (add-function :before-until (local 'eldoc-documentation-function)
-                  #'python-eldoc-function))
+    (if (boundp 'eldoc-documentation-functions)
+        (add-hook 'eldoc-documentation-functions #'python-eldoc-function nil t)
+      (add-function :before-until (local 'eldoc-documentation-function)
+                    #'python-eldoc-function)))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]