From: João Távora Date: Sat, 6 Jun 2020 13:04:48 +0000 (+0100) Subject: Make more parts of Emacs use new Eldoc capabilities X-Git-Tag: emacs-28.0.90~7052 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1203626f472b0d99d2746f5999711137c0c1fd0c;p=emacs.git Make more parts of Emacs use new Eldoc capabilities Elisp-mode was doing a lot of work that can now be delegated to Eldoc. Flymake uses the new Eldoc functionality, too, installing a global documentation function that may report on diagnostics under point. CEDET's grammar.el was left as the only user of an Eldoc-internal function. That function was moved to grammar.el. That file is still, somewhat reprehensibly, using an internal function of elisp-mode.el, but this was left unchanged. In other situations, eldoc-documentation-functions is used or recommended. The only other places where the obsolete eldoc-documentation-function is still used is in libraries which are presumably meant to remain compatible with previous Emacs versions. * lisp/progmodes/elisp-mode.el (elisp-eldoc-funcall) (elisp-eldoc-var-docstring): New functions. (emacs-lisp-mode): Put two elements in eldoc-documentation-functions. * lisp/emacs-lisp/eldoc.el (eldoc--eval-expression-setup): Setup new Elisp eldoc-documentation-functions. * lisp/progmodes/flymake.el (flymake-mode): Use flymake-eldoc-function. (flymake-eldoc-function): New function. (Package-Requires): Require eldoc 1.1.0 * lisp/descr-text.el (describe-char-eldoc): Recommend eldoc-documentation-functions. * lisp/progmodes/cfengine.el (cfengine3-documentation-function): Recommend eldoc-documentation-functions * lisp/progmodes/octave.el (inferior-octave-mode): Use eldoc-documentation-functions. * lisp/cedet/semantic/grammar.el (semantic--docstring-format-sym-doc): New function. (semantic-grammar-eldoc-get-macro-docstring): Adjust. --- diff --git a/lisp/cedet/semantic/grammar.el b/lisp/cedet/semantic/grammar.el index 2c3b24b9b16..1ed18339a72 100644 --- a/lisp/cedet/semantic/grammar.el +++ b/lisp/cedet/semantic/grammar.el @@ -1663,6 +1663,42 @@ Select the buffer containing the tag's definition, and move point there." (defvar semantic-grammar-eldoc-last-data (cons nil nil)) +(defun semantic--docstring-format-sym-doc (prefix doc &optional face) + "Combine PREFIX and DOC, and shorten the result to fit in the echo area. + +When PREFIX is a symbol, propertize its symbol name with FACE +before combining it with DOC. If FACE is not provided, just +apply the nil face. + +See also: `eldoc-echo-area-use-multiline-p'." + ;; Hoisted from old `eldoc-docstring-format-sym-doc'. + ;; 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 + ;; description. + (when (symbolp prefix) + (setq prefix (concat (propertize (symbol-name prefix) 'face face) ": "))) + (let* ((ea-multi eldoc-echo-area-use-multiline-p) + ;; Subtract 1 from window width since emacs will not write + ;; any chars to the last column, or in later versions, will + ;; cause a wraparound and resize of the echo area. + (ea-width (1- (window-width (minibuffer-window)))) + (strip (- (+ (length prefix) + (length doc)) + ea-width))) + (cond ((or (<= strip 0) + (eq ea-multi t) + (and ea-multi (> (length doc) ea-width))) + (concat prefix doc)) + ((> (length doc) ea-width) + (substring (format "%s" doc) 0 ea-width)) + ((>= strip (string-match-p ":? *\\'" prefix)) + doc) + (t + ;; Show the end of the partial symbol name, rather + ;; than the beginning, since the former is more likely + ;; to be unique given package namespace conventions. + (concat (substring prefix strip) doc))))) + (defun semantic-grammar-eldoc-get-macro-docstring (macro expander) "Return a one-line docstring for the given grammar MACRO. EXPANDER is the name of the function that expands MACRO." @@ -1681,19 +1717,18 @@ EXPANDER is the name of the function that expands MACRO." (setq doc (eldoc-function-argstring expander)))) (when doc (setq doc - (eldoc-docstring-format-sym-doc + (semantic--docstring-format-sym-doc macro (format "==> %s %s" expander doc) 'default)) (setq semantic-grammar-eldoc-last-data (cons expander doc))) doc)) ((fboundp 'elisp-get-fnsym-args-string) ;; Emacs≥25 - (elisp-get-fnsym-args-string - expander nil - (concat (propertize (symbol-name macro) + (concat (propertize (symbol-name macro) 'face 'font-lock-keyword-face) " ==> " (propertize (symbol-name macro) 'face 'font-lock-function-name-face) - ": "))))) + ": " + (elisp-get-fnsym-args-string expander nil ))))) (define-mode-local-override semantic-idle-summary-current-symbol-info semantic-grammar-mode () diff --git a/lisp/descr-text.el b/lisp/descr-text.el index 1dbbd421489..22cfccb1fb2 100644 --- a/lisp/descr-text.el +++ b/lisp/descr-text.el @@ -929,10 +929,12 @@ Otherwise return a description formatted by of `eldoc-echo-area-use-multiline-p' variable and width of minibuffer window for width limit. -This function is meant to be used as a value of -`eldoc-documentation-function' variable." +This function can be used as a value of +`eldoc-documentation-functions' variable." (let ((ch (following-char))) (when (and (not (zerop ch)) (or (< ch 32) (> ch 127))) + ;; TODO: investigate if the new `eldoc-documentation-functions' + ;; API could significantly improve this. (describe-char-eldoc--format ch (unless (eq eldoc-echo-area-use-multiline-p t) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index 34f37f76d48..ab8dd6a73b5 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -229,7 +229,10 @@ expression point is on." :lighter eldoc-minor-mode-string ;; Setup `eldoc', similar to `emacs-lisp-mode'. FIXME: Call ;; `emacs-lisp-mode' itself? (add-hook 'eldoc-documentation-functions - #'elisp-eldoc-documentation-function nil t) + #'elisp-eldoc-var-docstring nil t) + (add-hook 'eldoc-documentation-functions + #'elisp-eldoc-funcall nil t) + (setq eldoc-documentation-strategy 'eldoc-documentation-default) (eldoc-mode +1)) ;;;###autoload @@ -656,39 +659,6 @@ documentation themselves." (;; got something else, trust callback will be called t))))))))) -;; 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 -;; description. -(defun eldoc-docstring-format-sym-doc (prefix doc &optional face) - "Combine PREFIX and DOC, and shorten the result to fit in the echo area. - -When PREFIX is a symbol, propertize its symbol name with FACE -before combining it with DOC. If FACE is not provided, just -apply the nil face. - -See also: `eldoc-echo-area-use-multiline-p'." - (when (symbolp prefix) - (setq prefix (concat (propertize (symbol-name prefix) 'face face) ": "))) - (let* ((ea-multi eldoc-echo-area-use-multiline-p) - ;; Subtract 1 from window width since emacs will not write - ;; any chars to the last column, or in later versions, will - ;; cause a wraparound and resize of the echo area. - (ea-width (1- (window-width (minibuffer-window)))) - (strip (- (+ (length prefix) (length doc)) ea-width))) - (cond ((or (<= strip 0) - (eq ea-multi t) - (and ea-multi (> (length doc) ea-width))) - (concat prefix doc)) - ((> (length doc) ea-width) - (substring (format "%s" doc) 0 ea-width)) - ((>= strip (string-match-p ":? *\\'" prefix)) - doc) - (t - ;; Show the end of the partial symbol name, rather - ;; than the beginning, since the former is more likely - ;; to be unique given package namespace conventions. - (concat (substring prefix strip) doc))))) - ;; When point is in a sexp, the function args are not reprinted in the echo ;; area after every possible interactive command because some of them print ;; their own messages in the echo area; the eldoc functions would instantly diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el index 9a6d81ce064..acf70a5ad90 100644 --- a/lisp/progmodes/cfengine.el +++ b/lisp/progmodes/cfengine.el @@ -1296,8 +1296,8 @@ Calls `cfengine-cf-promises' with \"-s json\"." (defun cfengine3-documentation-function (&rest _ignored) "Document CFengine 3 functions around point. -Intended as the value of `eldoc-documentation-function', which see. -Use it by enabling `eldoc-mode'." +Intended as the value of `eldoc-documentation-functions', which +see. Use it by enabling `eldoc-mode'." (let ((fdef (cfengine3--current-function))) (when fdef (cfengine3-format-function-docstring fdef)))) diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 5e32b25fd30..6df54111911 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -280,7 +280,9 @@ Blank lines separate paragraphs. Semicolons start comments. electric-pair-text-pairs)) (add-hook 'electric-pair-mode-hook #'emacs-lisp-set-electric-text-pairs)) (add-hook 'eldoc-documentation-functions - #'elisp-eldoc-documentation-function nil t) + #'elisp-eldoc-var-docstring nil t) + (add-hook 'eldoc-documentation-functions + #'elisp-eldoc-funcall 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 @@ -1403,22 +1405,27 @@ which see." or argument string for functions. 2 - `function' if function args, `variable' if variable documentation.") -(defun elisp-eldoc-documentation-function (_ignored &rest _also-ignored) - "Contextual documentation function for Emacs Lisp. -Intended to be placed in `eldoc-documentation-functions' (which -see)." - (let ((current-symbol (elisp--current-symbol)) - (current-fnsym (elisp--fnsym-in-current-sexp))) - (cond ((null current-fnsym) - nil) - ((eq current-symbol (car current-fnsym)) - (or (apply #'elisp-get-fnsym-args-string current-fnsym) - (elisp-get-var-docstring current-symbol))) - (t - (or (elisp-get-var-docstring current-symbol) - (apply #'elisp-get-fnsym-args-string current-fnsym)))))) - -(defun elisp-get-fnsym-args-string (sym &optional index prefix) +(defun elisp-eldoc-funcall (callback &rest _ignored) + "Document function call at point. +Intended for `eldoc-documentation-functions' (which see)." + (let* ((sym-info (elisp--fnsym-in-current-sexp)) + (fn-sym (car sym-info))) + (when fn-sym + (funcall callback (apply #'elisp-get-fnsym-args-string sym-info) + :thing fn-sym + :face (if (functionp fn-sym) + 'font-lock-function-name-face + 'font-lock-keyword-face))))) + +(defun elisp-eldoc-var-docstring (callback &rest _ignored) + "Document variable at point. +Intended for `eldoc-documentation-functions' (which see)." + (let ((sym (elisp--current-symbol))) + (when sym (funcall callback (elisp-get-var-docstring sym) + :thing sym + :face 'font-lock-variable-name-face)))) + +(defun elisp-get-fnsym-args-string (sym &optional index) "Return a string containing the parameter list of the function SYM. If SYM is a subr and no arglist is obtainable from the docstring or elsewhere, return a 1-line docstring." @@ -1444,20 +1451,13 @@ or elsewhere, return a 1-line docstring." ;; Stringify, and store before highlighting, downcasing, etc. (elisp--last-data-store sym (elisp-function-argstring args) 'function)))))) - ;; Highlight, truncate. + ;; Highlight (if argstring (elisp--highlight-function-argument - sym argstring index - (or prefix - (concat (propertize (symbol-name sym) 'face - (if (functionp sym) - 'font-lock-function-name-face - 'font-lock-keyword-face)) - ": ")))))) - -(defun elisp--highlight-function-argument (sym args index prefix) - "Highlight argument INDEX in ARGS list for function SYM. -In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'." + sym argstring index)))) + +(defun elisp--highlight-function-argument (sym args index) + "Highlight argument INDEX in ARGS list for function SYM." ;; FIXME: This should probably work on the list representation of `args' ;; rather than its string representation. ;; FIXME: This function is much too long, we need to split it up! @@ -1560,7 +1560,6 @@ In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'." (when start (setq doc (copy-sequence args)) (add-text-properties start end (list 'face argument-face) doc)) - (setq doc (eldoc-docstring-format-sym-doc prefix doc)) doc))) ;; Return a string containing a brief (one-line) documentation string for @@ -1573,9 +1572,7 @@ In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'." (t (let ((doc (documentation-property sym 'variable-documentation t))) (when doc - (let ((doc (eldoc-docstring-format-sym-doc - sym (elisp--docstring-first-line doc) - 'font-lock-variable-name-face))) + (let ((doc (elisp--docstring-first-line doc))) (elisp--last-data-store sym doc 'variable))))))) (defun elisp--last-data-store (symbol doc type) diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 4ca5c657650..58e8d56f6e3 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -6,7 +6,7 @@ ;; Maintainer: João Távora ;; Version: 1.0.8 ;; Keywords: c languages tools -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "26.1") (eldoc "1.1.0")) ;; This is a GNU ELPA :core package. Avoid functionality that is not ;; compatible with the version of Emacs recorded above. @@ -1002,6 +1002,7 @@ special *Flymake log* buffer." :group 'flymake :lighter (add-hook 'after-change-functions 'flymake-after-change-function nil t) (add-hook 'after-save-hook 'flymake-after-save-hook nil t) (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t) + (add-hook 'eldoc-documentation-functions 'flymake-eldoc-function nil t) ;; If Flymake happened to be alrady already ON, we must cleanup ;; existing diagnostic overlays, lest we forget them by blindly @@ -1019,6 +1020,7 @@ special *Flymake log* buffer." :group 'flymake :lighter (remove-hook 'after-save-hook 'flymake-after-save-hook t) (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t) ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t) + (remove-hook 'eldoc-documentation-functions 'flymake-eldoc-function t) (mapc #'delete-overlay (flymake--overlays)) @@ -1086,6 +1088,14 @@ START and STOP and LEN are as in `after-change-functions'." (flymake-mode) (flymake-log :warning "Turned on in `flymake-find-file-hook'"))) +(defun flymake-eldoc-function (report-doc &rest _) + "Document diagnostics at point. +Intended for `eldoc-documentation-functions' (which see)." + (let ((diags (flymake-diagnostics (point)))) + (when diags + (funcall report-doc + (mapconcat #'flymake-diagnostic-text diags "\n"))))) + (defun flymake-goto-next-error (&optional n filter interactive) "Go to Nth next Flymake diagnostic that matches FILTER. Interactively, always move to the next diagnostic. With a prefix diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el index 2cf305c4041..e07f818a68a 100644 --- a/lisp/progmodes/octave.el +++ b/lisp/progmodes/octave.el @@ -755,7 +755,7 @@ Key bindings: (setq font-lock-defaults '(inferior-octave-font-lock-keywords nil nil)) (setq-local info-lookup-mode 'octave-mode) - (setq-local eldoc-documentation-function 'octave-eldoc-function) + (add-hook 'eldoc-documentation-functions 'octave-eldoc-function nil t) (setq-local comint-input-ring-file-name (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist"))