A very simple but effective thing, eldoc-mode is a MinorMode which shows you, in the echo area, the argument list of the function call you are currently writing. Very handy. By NoahFriedman. Part of Emacs.


ElDoc works for EmacsLisp and certain other language modes that implement support for ElDoc. These include

ElDoc runs each element of the function arglist through a filter function stored in the eldoc-argument-case variable, which defaults to upcase. This is why the arguments are capitalized by default. [This only applies for Emacs Lisp unless a custom eldoc-documentation-function explicitly uses it.] But wouldn’t it be cool if these arguments were highlighted in font-lock-variable-name-face? Just do something like this:

 (defun ted-frob-eldoc-argument-list (string)
   "Upcase and fontify STRING for use with `eldoc-mode'."
   (propertize (upcase string)
               'face 'font-lock-variable-name-face))
 (setq eldoc-argument-case 'ted-frob-eldoc-argument-list)

(You need Emacs 21 or later for function ‘propertize’. For Emacs 20, use ‘put-text-property’ instead.)

Installing ElDoc

One useful way to enable this minor mode is to put the following in your .emacs:

     (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
     (add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
     (add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)

How to implement support

Your mode need only supply 1 function to support eldoc-mode which you tell ElDoc about like this.

[You should use introspection where the language system supports it. See the Emacs 22 Python mode for an example (or Haskell mode and Erlang mode with Distel, for which Eldoc was generalized).]

    (set (make-local-variable 'eldoc-documentation-function)

The function you point to need not be complex.

  (defun tal-eldoc-function ()
    "Returns a doc string appropriate for the current context, or nil."
    (symbol-value (intern-soft (upcase (thing-at-point 'symbol))

For the above, doc strings are stored in an obarray created like this.

  (setq tal-eldoc-obarray (make-vector 41 0))
  ;; Most of these set commands are actually stored in a file
  ;; and loaded for quick access to library function help
  (set (intern "STEPMOM" tal-eldoc-obarray)
  (set (intern "STOP" tal-eldoc-obarray)
  (set (intern "STRING_UPSHIFT_" tal-eldoc-obarray)
  (set (intern "SUSPENDPROCESS" tal-eldoc-obarray)
  ;; help for current module functions are created dynamically
  ;; by a fairly simple function.

You can look at TalMode to see one method of creating and maintaining such doc strings.

Highlighting Eldoc Arguments in EmacsLisp

(defun eldoc-get-arg-index ()
    (let ((fn (eldoc-fnsym-in-current-sexp))
          (i 0))
      (unless (memq (char-syntax (char-before)) '(32 39)) ; ? , ?'
        (condition-case err
            (backward-sexp)             ;for safety
          (error 1)))
      (condition-case err
          (while (not (equal fn (eldoc-current-symbol)))
            (setq i (1+ i))
        (error 1))
      (max 0 i))))

(defun eldoc-highlight-nth-arg (doc n)
  (cond ((null doc) "")
        ((<= n 0) doc)
         (let ((i 0))
            (lambda (arg)
              (if (member arg '("&optional" "&rest"))
                    (if (= i n)
                        (put-text-property 0 (length arg) 'face 'underline arg))
                  (setq i (1+ i)))))
            (split-string doc) " ")))))

(defadvice eldoc-get-fnsym-args-string (around highlight activate)
  (setq ad-return-value (eldoc-highlight-nth-arg ad-do-it

I roughly implemented. – rubikitch

EmacsFromCVS now contains something like that. – nschum

Highlighting Eldoc Arguments in tal-mode

Here’s an example of highlighting the param in a function help string corresponding to the param near to point.

This would be better using a string-indexed hash table rather than an obarray.
    loc := dnumout( output_buf, counter, 10, cntr_width, no_flags );

With point near cntr_width the help string looks like this.


All the comments make the function look bigger than it is.

  (defun tal-eldoc-function ()
  "Returns a documentation string appropriate for the current context or nil."
  (let ((begin (point))
        (count -1)
    ;; if thing-at-point has a doc string, return it, we're done.
    (if (and (setq word (thing-at-point 'symbol))
             (setq word (symbol-value (intern-soft (upcase word)
      ;; Otherwise see if we're within (parens) and if so, count the
      ;; number of commas between point and the open paren.
        (when (and (condition-case ()
                       (or (backward-up-list) t)
                     (error nil))
                   (eq ?\( (char-after))) 
          (skip-syntax-backward "-")
          (if (setq word (thing-at-point 'symbol))
              (while (progn (setq count (1+ count))
                            (search-forward "," begin t))))))
      ;; if the word prior to the open paren has a doc string use it.
      (when (and word
                 (setq word (copy-sequence
                              (intern-soft (upcase word)
        ;; if the doc string has an open paren, highlight the word (if
        ;; any) that follows the same number of comma's counted above.
        (when (and (> count -1)
                    "(" word
                    ;; this tries to skip parens from int(32) type
                    ;; proc/subproc declarations.
                    (string-match ")\\s-\\(sub\\)?proc\\b" word)))
          (while (and (> count 0)
                      (string-match "," word (match-end 0))
                      (setq count (1- count))))
          (when (= count 0)
            (if (string-match "\\w+\\(:\\w+\\)?" word (match-end 0))
                ;; found something needing to be made bold
                (put-text-property (match-beginning 0) (match-end 0)
                                   'face 'bold word))))

Add docstring to ElDoc output

I like to get a little documentation as well, so I add the first line of the doc string to ElDoc’s output

  (defadvice eldoc-get-fnsym-args-string (after add-dacstring (sym)
                                                activate compile)
    "Add a doc string to ElDoc's modeline information."
    (let ((doc (eldoc-docstring-first-line
                (cdr (help-split-fundoc (documentation sym t) sym)))))
      (when (and doc (not (equal doc "")))
        (setq ad-return-value
              (concat ad-return-value
                      (if (> (+ (length ad-return-value) (length doc) 4)
                             (frame-width)) "\n" "    ")


for Emacs version 24.4 use (elisp documentation only):

  (with-eval-after-load 'elisp-mode
      (defadvice elisp--get-fnsym-args-string (after add-docstring activate compile)
        "Add a 1st line of docstring to ElDoc's function information."
        (when ad-return-value
          (let* ((doc (elisp--docstring-first-line (documentation (ad-get-arg 0) t)))
                 (w (frame-width))
                 (color-doc (propertize doc 'face 'font-lock-comment-face)))
            (when (and doc (not (string= doc "")))
              (setq ad-return-value (concat ad-return-value " " color-doc))
              (when (> (length doc) w)
                (setq ad-return-value (substring ad-return-value 0 (1- w))))))  

– ukaszg

Good idea! I found it a bit hard to quickly scan to the docstring with so much information in the minibuffer area, so I tried to fix that by using different faces and changing the formatting a bit. I came up with this variation, which produces output like:

  format (STRING &rest OBJECTS): Format a string out of a format-string
                                 and arguments.

with the docstring fontified using font-lock-doc-face (the same one used for docstrings in emacs-lisp-mode).

Not quite finished: the code shrinking the string to fit on one line is a dumb copy-paste from eldoc-docstring-format-sym-doc. So if your minibuffer is not as wide as mine this may not work very well.

  (defadvice eldoc-highlight-function-argument
    (around my-formatting (sym args index) compile activate preactivate)
    "Replace original to apply my style of formatting."
    ;; HACK: intercept the call to eldoc-docstring-format-sym-doc at the
    ;; end of the adviced function. This is obviously brittle, but the
    ;; alternative approach of copy/pasting the original also has
    ;; downsides...
    (flet ((eldoc-docstring-format-sym-doc
            (sym doc face)
            (let* ((function-name (propertize (symbol-name sym)
                                              'face face))
                   (spec (format "%s %s" function-name doc))
                   (docstring (or (eldoc-docstring-first-line
                                   (documentation sym t))
                   (docstring (propertize docstring
                                          'face 'font-lock-doc-face))
                   ;; TODO: currently it strips from the start of spec by
                   ;; character instead of whole arguments at a time.
                   (fulldoc (format "%s: %s" spec docstring))
                   (ea-width (1- (window-width (minibuffer-window)))))
              (cond ((or (<= (length fulldoc) ea-width)
                         (eq eldoc-echo-area-use-multiline-p t)
                         (and eldoc-echo-area-use-multiline-p
                              (> (length docstring) ea-width)))
                    ((> (length docstring) ea-width)
                     (substring docstring 0 ea-width))
                    ((>= (- (length fulldoc) (length spec)) ea-width)
                     ;; 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.
                     (setq spec (substring spec (- (length fulldoc) ea-width)))
                     (format "%s: %s" spec docstring))))))

Show argument list only after SPC

A hack to make Eldoc show the argument list in the echo area only after you type SPC. (Like in SlimeMode.)

(setq eldoc-documentation-function
      (lambda ()
        (when (eql last-command-event 32)
          (let (eldoc-documentation-function)

Context elisp help in the *Help* buffer


Update : 23 Oct 2008 - Added lisp-interaction-mode to the context help modes

The default eldoc output for functions is a little lacking for new programmers. I wrote this to provide context help on the function or variable under the cursor. You can toggle it on or off - change key binding to suit…

(defun rgr/toggle-context-help ()
  "Turn on or off the context help.
Note that if ON and you hide the help buffer then you need to
manually reshow it. A double toggle will make it reappear"
  (with-current-buffer (help-buffer)
    (unless (local-variable-p 'context-help)
      (set (make-local-variable 'context-help) t))
    (if (setq context-help (not context-help))
	   (if (not (get-buffer-window (help-buffer)))
	       (display-buffer (help-buffer)))))
    (message "Context help %s" (if context-help "ON" "OFF"))))

(defun rgr/context-help ()
  "Display function or variable at point in *Help* buffer if visible.
Default behaviour can be turned off by setting the buffer local
context-help to false"
  (let ((rgr-symbol (symbol-at-point))) ; symbol-at-point http://www.emacswiki.org/cgi-bin/wiki/thingatpt%2B.el
    (with-current-buffer (help-buffer)
     (unless (local-variable-p 'context-help)
       (set (make-local-variable 'context-help) t))
     (if (and context-help (get-buffer-window (help-buffer))
       (if (fboundp  rgr-symbol)
           (describe-function rgr-symbol) 
	 (if (boundp  rgr-symbol) (describe-variable rgr-symbol)))))))

(defadvice eldoc-print-current-symbol-info
  (around eldoc-show-c-tag activate)
	((eq major-mode 'emacs-lisp-mode) (rgr/context-help) ad-do-it)
	((eq major-mode 'lisp-interaction-mode) (rgr/context-help) ad-do-it)
	((eq major-mode 'apropos-mode) (rgr/context-help) ad-do-it)
	(t ad-do-it)))

(global-set-key (kbd "C-c h") 'rgr/toggle-context-help)

PHP support

Fetches function documentation from the net on demand:

(require 'xml)

(setq my-php-function-doc-hash (make-hash-table :test 'equal))

(defun my-php-fetch-function-doc (function)
  (let ((doc (gethash function my-php-function-doc-hash 'nope)))
    (when (eq doc 'nope)
      (setq doc nil)

      (let ((buf (url-retrieve-synchronously (concat "http://php.net/manual-lookup.php?pattern=" function))))
        (with-current-buffer buf
          (goto-char (point-min))
          (let (desc)
            (when (re-search-forward "<div class=\"methodsynopsis dc-description\">\\(\\(.\\|\n\\)*?\\)</div>" nil t)
              (setq desc
                     " +" " "
                      "\n" ""
                      (replace-regexp-in-string "<.*?>" "" (match-string-no-properties 1)))))
              (when (re-search-forward "<p class=\"para rdfs-comment\">\\(\\(.\\|\n\\)*?\\)</p>" nil t)
                (setq desc
                      (concat desc "\n\n"
                               " +" " "
                                "\n" ""
                                (replace-regexp-in-string "<.*?>" "" (match-string-no-properties 1))))))))

            (if desc
                (setq doc (xml-substitute-special desc)))))

        (kill-buffer buf))

      (puthash function doc my-php-function-doc-hash))


(defun my-php-eldoc-function ()
  (let ((symbol (thing-at-point 'symbol)))
    (if (and symbol
             (not (eq (elt symbol 0) ?$)))
        (my-php-fetch-function-doc symbol))))

PHP Eldoc Plugin


CSS Eldoc Plugin


Python + Rope support

Eldoc support for Python using Rope extension. Allow highlihting of current position in argument list, integration with flyspell(propely show errors in minibuffer). Advice for message function can be avoided I it is possible to switch off Pymacs traces in minibuffer(this advice just don’t execute real message function in case of calling rope, because some indetifiers in source code cause Rope traces).

(defun rope-eldoc-function ()
  (let* ((win-conf (current-window-configuration))
         (resize-mini-windows nil)
         (disable-python-trace t)
         class fun args result-type
         (flymake-message (python-flymake-show-help))
         (initial-point (point))
         (paren-range (let (tmp)
                          (setq tmp (vimpulse-paren-range 0 ?\( nil t))
                          (if (and tmp (>= (point) (car tmp)) (<= (point) (cadr tmp)))
         (result (save-excursion
                   ;; check if we on the border of args list - lparen or rparen
                   (if paren-range
                       (goto-char (car paren-range)))
                   (call-interactively 'rope-show-doc)
                   (set-buffer "*rope-pydoc*")
                   (goto-char (point-min))
                   (if (or (equal (point-max) 1)
                           (not (re-search-forward "\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)(.*):" (point-at-eol) t))
                           (and (current-message) (string-match-p "BadIdentifierError" (current-message))))
                     (let (result)
                       ;; check if this is class definition
                       (if (looking-at "class \\([a-zA-Z_]+[a-zA-Z0-9_]*\\)(.*):")
                             (goto-char (point-at-eol))
                             (re-search-forward (buffer-substring (match-beginning 1) (match-end 1)))))
                       (goto-char (point-at-bol))
                       (setq result (buffer-substring (point) (point-at-eol)))

                       ;; check if exist better description of function
                       (goto-char (point-at-eol))
                       (string-match "\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)(.*)" result) ;get function name
                       (if (re-search-forward (concat (match-string 1 result) "(.*)") nil t)
                             (goto-char (point-at-bol))
                             (setq result (buffer-substring (point) (point-at-eol)))))

                       ;; return result
         (arg-position (save-excursion
                         (if paren-range
                             (count-matches "," (car paren-range) (point))))))
    ;; save window configuration
    (set-window-configuration win-conf)
    ;; process main result
    (if result
          (setq result-type (nth 1 (split-string result "->")))
          (setq result (nth 0 (split-string result "->")))
          (setq result (split-string result "("))
          (setq fun (nth 1 (split-string (nth 0 result) "\\.")))
          (setq class (nth 0 (split-string (nth 0 result) "\\.")))
          ;; process args - highlight current function argument
          (setq args (nth 0 (split-string (nth 1 result) ")")))

          ;; highlight current argument
          (if args
                (setq args (split-string args ","))
                (setq args (let ((num -1))
                                          (setq num (+ 1 num))
                                          (if (equal num arg-position) (propertize x 'face 'eldoc-highlight-function-argument) x)))

          ;; create string for type signature
          (setq result
                 (propertize "Signature: " 'face 'flymake-message-face)

                 (if fun
                     (concat (propertize (org-trim class) 'face 'font-lock-type-face)
                             (propertize (org-trim fun) 'face 'font-lock-function-name-face))
                   (propertize (org-trim class) 'face 'font-lock-function-name-face))

                 " (" args ")"

                 (if result-type
                     (concat " -> " (org-trim result-type)))

    ;; create final result
    (if (and (null flymake-message) (null result))
      (concat flymake-message
              (if (and result flymake-message) "\n")

(defvar disable-python-trace nil)

(defadvice message(around message-disable-python-trace activate)
  (if disable-python-trace

(defface flymake-message-face
  '((((class color) (background light)) (:foreground "#b2dfff"))
    (((class color) (background dark))  (:foreground "#b2dfff")))
  "Flymake message face")

(defun python-flymake-show-help ()
  (when (get-char-property (point) 'flymake-overlay)
    (let ((help (get-char-property (point) 'help-echo)))
      (if help
          (format (concat (propertize "Error: " 'face 'flymake-message-face) "%s") help)))))

For using this function you should add following code to python-mode-hook:

(set (make-local-variable 'eldoc-documentation-function) 'rope-eldoc-function)

El Doc on Mouseover Hover

See http://emacs.stackexchange.com/questions/22132/help-buffer-on-hover-possible

CategoryModes CategoryProgrammerUtils