Guest User

Untitled

a guest
Apr 20th, 2018
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.30 KB | None | 0 0
  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
Add Comment
Please, Sign In to add comment