daily pastebin goal
45%
SHARE
TWEET

Untitled

a guest Apr 20th, 2018 79 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;;; eldoc.el --- show function arglist or variable docstring in echo area
  2.  
  3. ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  4. ;;   2005, 2006, 2007 Free Software Foundation, Inc.
  5.  
  6. ;; Copyright (C) 2009 KOBAYASHI Shigeru <shigeru.kb@gmail.com>
  7.  
  8. ;; Author: Noah Friedman <friedman@splode.com>
  9. ;; Maintainer: friedman@splode.com
  10. ;; Keywords: extensions
  11. ;; Created: 1995-10-06
  12.  
  13. ;; This file is `NOT' part of GNU Emacs.
  14.  
  15. ;; GNU Emacs is free software; you can redistribute it and/or modify
  16. ;; it under the terms of the GNU General Public License as published by
  17. ;; the Free Software Foundation; either version 3, or (at your option)
  18. ;; any later version.
  19.  
  20. ;; GNU Emacs is distributed in the hope that it will be useful,
  21. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. ;; GNU General Public License for more details.
  24.  
  25. ;; You should have received a copy of the GNU General Public License
  26. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  27. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  28. ;; Boston, MA 02110-1301, USA.
  29.  
  30. ;;; Commentary:
  31.  
  32. ;; This program was inspired by the behavior of the "mouse documentation
  33. ;; window" on many Lisp Machine systems; as you type a function's symbol
  34. ;; name as part of a sexp, it will print the argument list for that
  35. ;; function.  Behavior is not identical; for example, you need not actually
  36. ;; type the function name, you need only move point around in a sexp that
  37. ;; calls it.  Also, if point is over a documented variable, it will print
  38. ;; the one-line documentation for that variable instead, to remind you of
  39. ;; that variable's meaning.
  40.  
  41. ;; One useful way to enable this minor mode is to put the following in your
  42. ;; .emacs:
  43. ;;
  44. ;;      (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
  45. ;;      (add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
  46. ;;      (add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)
  47.  
  48. ;; Major modes for other languages may use Eldoc by defining an
  49. ;; appropriate function as the buffer-local value of
  50. ;; `eldoc-documentation-function'.
  51.  
  52. ;;; Code:
  53.  
  54. (eval-when-compile
  55.   (require 'cl))
  56.  
  57. ;; For fundoc-usage handling functions. (require Emacs22 or later)
  58. (require 'help-fns)
  59.  
  60. (defgroup eldoc nil
  61.   "Show function arglist or variable docstring in echo area."
  62.   :group 'lisp
  63.   :group 'extensions)
  64.  
  65. (defcustom eldoc-idle-delay 0.20
  66.   "*Number of seconds of idle time to wait before printing."
  67.   :type 'number
  68.   :group 'eldoc)
  69.  
  70. ;;;###autoload
  71. (defcustom eldoc-minor-mode-string " ElDoc"
  72.   "*String to display in mode line when Eldoc Mode is enabled; nil for none."
  73.   :type '(choice string (const :tag "None" nil))
  74.   :group 'eldoc)
  75.  
  76. (defcustom eldoc-arglist-case 'upcase
  77.   "Case to display argument names of functions, as a symbol."
  78.   :type '(radio (function-item upcase)
  79.                 (function-item downcase)
  80.                 function)
  81.   :group 'eldoc)
  82.  
  83. (defcustom eldoc-use-multiline-p nil
  84.   "*Allow long eldoc messages to resize echo area display."
  85.   :type 'boolean
  86.   :group 'eldoc)
  87.  
  88. (defface eldoc-highlight-arglist
  89.     '((t (:inherit highlight)))
  90.   "Face used for the argument at point in a function's argument list."
  91.   :group 'eldoc)
  92.  
  93. (defstruct eldoc-last-data
  94.   (symbol nil             :type symbol)
  95.   (doc    "Undocumented." :type string)
  96.   (type   'variable       :type symbol))
  97.  
  98. (lexical-let ((cache (make-eldoc-last-data)))
  99.  
  100.   (defun eldoc-cache-symbol () #1=(eldoc-last-data-symbol cache))
  101.   (defun eldoc-cache-doc    () #2=(eldoc-last-data-doc    cache))
  102.   (defun eldoc-cache-type   () #3=(eldoc-last-data-type   cache))
  103.  
  104.   (defun eldoc-update-cache (symbol doc type)
  105.     (setf #1# symbol
  106.           #2# doc
  107.           #3# type))
  108.   )
  109.  
  110. (defvar eldoc-last-message nil)
  111.  
  112. ;;; User interface
  113.  
  114. ;;;###autoload
  115. (define-minor-mode eldoc-mode
  116.     "Displays information about a function or variable at point."
  117.   :group 'eldoc
  118.   :lighter eldoc-minor-mode-string
  119.   (setq eldoc-last-message nil)
  120.   (cond
  121.     ;; ON
  122.     (eldoc-mode
  123.      (eldoc-start-timer)
  124.      (add-hook 'pre-command-hook 'eldoc-pre-command-refresh-echo-area t))
  125.     ;; OFF
  126.     (t
  127.      (eldoc-stop-timer)
  128.      (remove-hook 'pre-command-hook 'eldoc-pre-command-refresh-echo-area))))
  129.  
  130. ;;;###autoload
  131. (defun turn-on-eldoc-mode ()
  132.   "Unequivocally turn on ElDoc mode (see command `eldoc-mode')."
  133.   (interactive)
  134.   (eldoc-mode 1))
  135.  
  136. ;;;###autoload
  137. (defun turn-off-eldoc-mode ()
  138.   (interactive)
  139.   (eldoc-mode -1))
  140.  
  141.  
  142. ;;; Timer
  143. (defvar eldoc-timer nil
  144.   "eldoc's timer object.")
  145.  
  146. (defun eldoc-start-timer ()
  147.   (when eldoc-timer
  148.     (cancel-timer eldoc-timer))
  149.   (setq eldoc-timer
  150.         (run-with-idle-timer eldoc-idle-delay t
  151.                              'eldoc-autodoc-at-point)))
  152.  
  153. (defun eldoc-stop-timer ()
  154.   (when eldoc-timer
  155.     (cancel-timer eldoc-timer)
  156.     (setq eldoc-timer nil)))
  157.  
  158. ;;; Echo
  159.  
  160. (defun eldoc-message (doc)
  161.   (when doc
  162.     (setq doc (substring doc 0 (string-match "\n" doc))))
  163.   (setq eldoc-last-message doc)
  164.   (when eldoc-last-message
  165.     ;; suppress log output
  166.     (let ((message-log-max nil)
  167.           (message-truncate-lines (null eldoc-use-multiline-p)))
  168.       (message "%s" eldoc-last-message))))
  169.  
  170. ;; This function goes on pre-command-hook for XEmacs or when using idle
  171. ;; timers in Emacs.  Motion commands clear the echo area for some reason,
  172. ;; which make eldoc messages flicker or disappear just before motion
  173. ;; begins.  This function reprints the last eldoc message immediately
  174. ;; before the next command executes, which does away with the flicker.
  175. ;; This doesn't seem to be required for Emacs 19.28 and earlier.
  176. (defun eldoc-pre-command-refresh-echo-area ()
  177.   (if (eldoc-enable-display-p)
  178.       (eldoc-message eldoc-last-message)
  179.       (setq eldoc-last-message nil)))
  180.  
  181. (defun eldoc-enable-display-p ()
  182.   "Check various conditions about the current environment that might make
  183. it undesirable to print eldoc messages right this instant."
  184.   (and eldoc-mode
  185.        (not executing-kbd-macro)
  186.        (not (and (boundp 'edebug-active) edebug-active))
  187.        ;; Having this mode operate in an active minibuffer/echo area causes
  188.        ;; interference with what's going on there.
  189.        (not cursor-in-echo-area)
  190.        (not (eq (selected-window) (minibuffer-window)))
  191.        (or (null (current-message))
  192.            (string-equal (current-message) eldoc-last-message))
  193.        (not (active-minibuffer-window))))
  194.  
  195. ;;; Find symbol
  196.  
  197. ;;;###autoload
  198. (defvar eldoc-documentation-function nil
  199.   "If non-nil, function to call to return doc string.
  200. The function of no args should return a one-line string for displaying
  201. doc about a function etc. appropriate to the context around point.
  202. It should return nil if there's no doc appropriate for the context.
  203. Typically doc is returned if point is on a function-like name or in its
  204. arg list.
  205.  
  206. This variable is expected to be made buffer-local by modes (other than
  207. Emacs Lisp mode) that support Eldoc.")
  208.  
  209. (defun eldoc-autodoc-at-point ()
  210.   (when (eldoc-enable-display-p)
  211.     (condition-case err
  212.         (if eldoc-documentation-function
  213.             (eldoc-message (funcall eldoc-documentation-function))
  214.             (let ((current-symbol (eldoc-current-symbol)))
  215.               (destructuring-bind (fnsym index)
  216.                   (eldoc-parse-fnsym) ;; (eldoc-fnsym-in-current-sexp)
  217.                 (let ((doc (cond
  218.                              ;; Function -> Variable
  219.                              ((eq current-symbol fnsym)
  220.                               (or #1=(eldoc-get-fnsym-args-string fnsym index)
  221.                                   #2=(eldoc-get-var-docstring current-symbol)))
  222.                              ;; Variable -> Function
  223.                              (t
  224.                               (or #2# #1#)))))
  225.                   (eldoc-message doc)))))
  226.       ;; This is run from post-command-hook or some idle timer thing,
  227.       ;; so we need to be careful that errors aren't ignored.
  228.       (error (message "eldoc error: %s" err)) )))
  229.  
  230. (defun eldoc-get-fnsym-args-string (sym &optional index)
  231.   "Return a string containing the parameter list of the function SYM.
  232. If SYM is a subr and no arglist is obtainable from the docstring
  233. or elsewhere, return a 1-line docstring.  The former calls
  234. `eldoc-arglist-case'; the latter gives the function name
  235. `font-lock-function-name-face', and optionally highlights
  236. argument number INDEX."
  237.   (when (fboundp sym)
  238.     (let* ((docstring (documentation sym t))
  239.            (list (help-split-fundoc docstring sym))
  240.            (args (car list))
  241.            (doc  (cdr list)))
  242.       (cond
  243.         ;; Find from cache
  244.         ((and (eq sym (eldoc-cache-symbol))
  245.               (eq 'function (eldoc-cache-type)))
  246.          (setq args (eldoc-cache-doc)))
  247.         ;; Find arglist from docstring (builtin, autoload, etc.)
  248.         (args
  249.          ;; e.g. "(setq [SYM VAL]...)" -> "[SYM VAL]..."
  250.          (if (string-match "\\`[^ )]* ?\\(.*\\))\\'" args)
  251.              (setq args (match-string 1 args))))
  252.         (t
  253.          ;; User defined function
  254.          ;; `nil' means function has no argment.
  255.          (setq args (help-function-arglist sym))))
  256.       (setq args (format "%s" (or args "")))
  257.       ;; Stringify, and store before highlighting, downcasing, etc.
  258.       ;; (eldoc-last-data-store sym args 'function)
  259.       (eldoc-update-cache sym args 'function)
  260.       ;; Change case, highlight, truncate.
  261.       (format "(%s %s): %s"
  262.               (propertize (symbol-name sym) 'face 'font-lock-function-name-face)
  263.               (eldoc-highlight-arglist
  264.                sym
  265.                (eldoc-arglist-case
  266.                 (replace-regexp-in-string "[][()]+" "" args))
  267.                index)
  268.               (or doc docstring "Undocumented.")))))
  269.  
  270. (defun eldoc-arglist-case (argstring)
  271.   (mapconcat (lambda (str)
  272.                (if (memq (intern str)
  273.                          (eval-when-compile
  274.                            lambda-list-keywords))
  275.                    str
  276.                    (funcall eldoc-arglist-case str)))
  277.              (split-string argstring)
  278.              " "))
  279.  
  280. ;; FIXME: (point {}) -> "args-out-of-range -1 0"
  281. (defun* eldoc-highlight-arglist (sym argstring &optional (index 1))
  282.   "Highlight argument INDEX in ARGSTRING list for function SYM."
  283.   (declare (ignore sym))
  284.   (let ((start nil)
  285.         (end    0)
  286.         (face  'eldoc-highlight-arglist))
  287.     ;; Find the current argument in the argument string.  We need to
  288.     ;; handle `&rest' and informal `...' properly.
  289.     ;;
  290.     ;; FIXME: What to do with optional arguments, like in
  291.     ;;        (defun NAME ARGLIST [DOCSTRING] BODY...) case?
  292.     ;;        The problem is there is no robust way to determine if
  293.     ;;        the current argument is indeed a docstring.
  294.     (while (<= 1 index)
  295.       (cond ((string-match "[^ ()]+" argstring end)
  296.              (progn
  297.                (setq start (match-beginning 0)
  298.                      end   (match-end 0))
  299.                (let ((argument (match-string 0 argstring)))
  300.                  (cond ((member argument '("&rest" "&body"))
  301.                         ;; All the rest arguments are the same.
  302.                         (setq index 1))
  303.                        ((string= argument "&optional"))
  304.                        ((string-match "\\.\\.\\.$" argument)
  305.                         (setq index 0))
  306.                        (t
  307.                         (decf index))))))
  308.             (t
  309.              (setq end   (length argstring)
  310.                    start (1- end)
  311.                    face  'font-lock-warning-face
  312.                    index 0))))
  313.     (when start
  314.       (add-text-properties start end `(face ,face) argstring))
  315.     argstring))
  316.  
  317. (defun eldoc-get-var-docstring (sym)
  318.   "Return a string containing a brief documentation string for the variable."
  319.   (when sym
  320.     (or (and (eq sym (eldoc-cache-symbol))
  321.              (eq 'variable (eldoc-cache-type))
  322.              (eldoc-cache-doc))
  323.         (let ((doc (documentation-property sym 'variable-documentation t)))
  324.           (when doc
  325.             (setq doc (format "%s: %s"
  326.                               (propertize (symbol-name sym)
  327.                                           'face
  328.                                           'font-lock-variable-name-face)
  329.                               doc))
  330.             (eldoc-update-cache sym doc 'variable)
  331.             doc)))))
  332.  
  333. (defun eldoc-inside-string-p (&optional point)
  334.   (or point (setq point (point)))
  335.   (save-excursion
  336.     (goto-char point)
  337.     (let* ((lim (or (save-excursion
  338.                       (beginning-of-defun)
  339.                       (point))
  340.                     (point-min)))
  341.            (state (parse-partial-sexp lim point)))
  342.       ;; 8. character address of start of comment or string; nil if not in one.
  343.       (nth 8 state))))
  344.  
  345. (defun* eldoc-parse-fnsym ()
  346.   "Return list of function-symbol (or nil) and point-of-argindex."
  347.   (save-excursion
  348.     (let ((parse-sexp-ignore-comments t)))
  349.     (goto-char (or (eldoc-inside-string-p) (point)))
  350.     (let ((index 0)
  351.           (opoint (point)))
  352.       ;; set point beginning-of-sexp
  353.       (ignore-errors (up-list -1) (forward-char))
  354.       (let ((op (eldoc-current-symbol)))
  355.         (if (null op)
  356.             '(nil 0)
  357.             (condition-case err
  358.                 (loop
  359.                    (forward-sexp)
  360.                    (if (<= opoint (point))
  361.                        (return #1=`(,op ,index)))
  362.                    (incf index))
  363.               (error #1#)))))))
  364.  
  365. (defun eldoc-current-symbol ()
  366.   "Returns nil unless current word is an interned symbol."
  367.   (let ((c (following-char)))
  368.     (and c
  369.          (memq (char-syntax c) '(?w ?_)) ; word or symbol
  370.          (intern-soft (current-word)))))
  371.  
  372. (provide 'eldoc)
  373.  
  374. ;;; eldoc.el ends here
RAW Paste Data
Top