Require `loadhist'. Variable

(find-function-function) variable removed.
(find-function-regexp): New variable, taken from former constant
in `find-function-noselect'.  Can now find function definitions
with parameters on a new line.
(find-variable-regexp): New variable.
(find-function-recenter-line): New variable.
(find-function-after-hook): New variable.
(find-function-search-for-symbol): subroutine, from
of `find-function-noselect'
(find-function-search-for-symbol): `regexp-quote' the symbol name:
needed to find-function `mapcar*' for example.
(find-function-noselect): Improved docstring.  Don't include
`library' in let.
Use `symbol-file' instead of `describe-symbol-find-file'
(find-function-read): Renamed from `find-function-read-function'.
With optional arg now read a variable.
(find-function-read): Separate `completing-read' calls for
variables and functions.
(find-function-do-it): If buffer found was already current push
mark. Added parameter to indicate if a variable is being searched for.
(find-function-do-it): Mention new `find-function-recenter-line'
and `find-function-after-hook' in docstring.  Use them.
(find-function): Remove optional arg.  Use `find-function-do-it'
and `find-function-read'.
(find-function-other-window): ditto.
(find-function-other-frame): ditto.
(find-function): Mention `find-function-recenter-line' and
`find-function-after-hook' in docstring.
(find-function-other-window): Remove most of docstring and add
reference to `find-function' instead.
(find-function-other-frame): Ditto.
(find-variable-noselect): New function for finding the point of
definition of variables, modeled on `find-function-noselect'.
(find-variable-noselect): Use `symbol-file' instead of
`describe-symbol-find-file'.
(find-variable): New function.
(find-variable-other-window): Ditto.
(find-variable-other-frame): Ditto.
(find-variable): Mention `find-function-recenter-line' and
`find-function-after-hook' in docstring.
(find-variable-other-window): Remove most of docstring and add
reference to `find-variable' instead.
(find-variable-other-frame): Ditto.
(find-function-on-key): Simplified.  Removed stuff now taken care
of by interactive "k".
(find-function-at-point): New function.
(find-variable-at-point): Ditto.
This commit is contained in:
Richard M. Stallman 1998-06-29 17:23:25 +00:00
parent 8a2df9371a
commit 2cd6a032aa

View file

@ -1,10 +1,10 @@
;;; find-func.el --- find the definition of the elisp function near point ;;; find-func.el --- find the definition of the Emacs Lisp function near point
;; Copyright (C) 1997 Free Software Foundation, Inc. ;; Copyright (C) 1997 Free Software Foundation, Inc.
;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp> ;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp>
;; Maintainer: petersen@kurims.kyoto-u.ac.jp ;; Maintainer: petersen@kurims.kyoto-u.ac.jp
;; Keywords: emacs-lisp, help, functions ;; Keywords: emacs-lisp, functions, variables
;; Created: 97/07/25 ;; Created: 97/07/25
;; This file is part of GNU Emacs. ;; This file is part of GNU Emacs.
@ -28,46 +28,52 @@
;; ;;
;; The funniest thing about this is that I can't imagine why a package ;; The funniest thing about this is that I can't imagine why a package
;; so obviously useful as this hasn't been written before!! ;; so obviously useful as this hasn't been written before!!
;; This probably belongs in "help.el" or somewhere like that.
;; ;;
;; Put this file in your `load-path', byte-compile it and add the ;; Put this file in your `load-path', byte-compile it and add the
;; following code in your init file: ;; following code in your init file:
;; ;;
;; ;;; find-func ;; ;;; find-func
;; (load "find-function") ;; (load "find-func")
;; (global-set-key [(control ?c) ?f] 'find-function)
;; (global-set-key [(control ?c) ?4 ?f] 'find-function-other-window)
;; (global-set-key [(control ?c) ?5 ?f] 'find-function-other-frame)
;; (global-set-key [(control ?c) ?k] 'find-function-on-key)
;; ;;
;; and away you go! It does pretty much what you would expect, ;; and away you go! The default given keybindings as the ones
;; putting the cursor at the definition of the function at point. ;; protected by autoload cookies at the bottom of this file. It does
;; pretty much what you would expect, putting the cursor at the
;; definition of the function or variable at point.
;; ;;
;; The code is adapted from `describe-function', `describe-key' ;; The code started out from `describe-function', `describe-key'
;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's ;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
;; "fff.el"). ;; "fff.el").
;;; To do:
;;
;; o custom?
;;
;; o improve handling of advice'd functions? (at the moment it goes to
;; the advice, not the actual definition)
;;;; Code: ;;;; Code:
(require 'loadhist)
;;; User variables: ;;; User variables:
(defgroup find-function nil (defgroup find-function nil
"Find the definition of the elisp function near point." "Finds the definition of the Emacs Lisp symbol near point."
:prefix "find-function" ;; :prefix "find-function"
:group 'lisp) :group 'lisp)
(defcustom find-function-function 'function-at-point (defcustom find-function-regexp
"*The function used by `find-function' to select the function near "^\\s-*(def[^cgv\W]\\w+\\*?\\s-+%s\\(\\s-\\|$\\)"
point. "The regexp used by `find-function' to search for a function
definition. Note it must contain a `%s' at the place where `format'
should insert the function name. The default value avoids `defconst',
`defgroup', `defvar'.
For example `function-at-point' or `function-called-at-point'." Please send improvements and fixes to the maintainer."
:type 'function :type 'regexp
:group 'find-function)
(defcustom find-variable-regexp
"^\\s-*(def[^uma\W]\\w+\\*?\\s-+%s\\(\\s-\\|$\\)"
"The regexp used by `find-variable' to search for a variable definition.
It should match right up to the variable name. The default value
avoids `defun', `defmacro', `defalias', `defadvice'.
Please send improvements and fixes to the maintainer."
:type 'regexp
:group 'find-function) :group 'find-function)
(defcustom find-function-source-path nil (defcustom find-function-source-path nil
@ -82,71 +88,92 @@ default."
;;; Functions: ;;; Functions:
;;;###autoload ;;;###autoload
(defun find-function-noselect (function &optional path) (defcustom find-function-recenter-line 1
"Returns list (BUFFER POINT) pointing to the definition of FUNCTION. "The window line-number from which to start displaying a symbol definition.
A value of nil implies center the beginning of the definition.
See the function `center-to-window-line' for more information, and
`find-function' and `find-variable'."
:group 'find-function)
(defcustom find-function-after-hook nil
"Hook run after finding symbol definition.
See the functions `find-function' and `find-variable'."
:group 'find-function)
;;; Functions:
(defun find-function-search-for-symbol (symbol variable-p library)
"Search for SYMBOL in LIBRARY.
If VARIABLE-P is nil, `find-function-regexp' is used, otherwise
`find-variable-regexp' is used."
(if (null library)
(error "Don't know where `%s' is defined" symbol))
(if (string-match "\\.el\\(c\\)\\'" library)
(setq library (substring library 0 (match-beginning 1))))
(let* ((path find-function-source-path)
(filename (if (file-exists-p library)
library
;; use `file-name-sans-extension' here? (if it gets fixed)
(if (string-match "\\(\\.el\\)\\'" library)
(setq library (substring library 0
(match-beginning 1))))
(or (locate-library (concat library ".el") t path)
(locate-library library t path)))))
(if (not filename)
(error "The library \"%s\" is not in the path." library))
(with-current-buffer (find-file-noselect filename)
(save-match-data
(let ((regexp (format (if variable-p
find-variable-regexp
find-function-regexp)
(regexp-quote (symbol-name symbol))))
(syn-table (syntax-table)))
(unwind-protect
(progn
(set-syntax-table emacs-lisp-mode-syntax-table)
(goto-char (point-min))
(if (re-search-forward regexp nil t)
(progn
(beginning-of-line)
(cons (current-buffer) (point)))
(error "Cannot find definition of `%s' in library \"%s\""
symbol library)))
(set-syntax-table syn-table)))))))
(defun find-function-noselect (function)
"Returns a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
Finds the Emacs Lisp library containing the definition of FUNCTION Finds the Emacs Lisp library containing the definition of FUNCTION
in a buffer and places point before the definition. The buffer is in a buffer and the point of the definition. The buffer is
not selected. not selected.
If the optional argument PATH is given, the library where FUNCTION is If the file where FUNCTION is defined is not known, then it is
defined is searched in PATH instead of `load-path' (see searched for in `find-function-source-path' if non `nil', otherwise
`find-function-source-path')." in `load-path'."
(and (subrp (symbol-function function))
(error "%s is a primitive function" function))
(if (not function) (if (not function)
(error "You didn't specify a function")) (error "You didn't specify a function"))
(and (subrp (symbol-function function))
(error "%s is a primitive function" function))
(let ((def (symbol-function function)) (let ((def (symbol-function function))
library aliases) aliases)
(while (symbolp def) (while (symbolp def)
(or (eq def function) (or (eq def function)
(if aliases (if aliases
(setq aliases (concat aliases (setq aliases (concat aliases
(format ", which is an alias for %s" (format ", which is an alias for `%s'"
(symbol-name def)))) (symbol-name def))))
(setq aliases (format "an alias for %s" (symbol-name (setq aliases (format "`%s' an alias for `%s'"
def))))) function (symbol-name def)))))
(setq function (symbol-function function) (setq function (symbol-function function)
def (symbol-function function))) def (symbol-function function)))
(if aliases (if aliases
(message aliases)) (message aliases))
(setq library (let ((library
(cond ((eq (car-safe def) 'autoload) (cond ((eq (car-safe def) 'autoload)
(nth 1 def)) (nth 1 def))
((describe-function-find-file function)))) ((symbol-file function)))))
(if (null library) (find-function-search-for-symbol function nil library))))
(error "`%s' is not in `load-history'" function))
(if (string-match "\\(\\.elc?\\'\\)" library)
(setq library (substring library 0 (match-beginning 1))))
(let* ((path (or path find-function-source-path))
(compression (or (rassq 'jka-compr-handler file-name-handler-alist)
(member 'crypt-find-file-hook find-file-hooks)))
(filename (or (locate-library (concat library ".el")
t path)
(locate-library library t path)
(if compression
(or (locate-library (concat library ".el.gz")
t path)
(locate-library (concat library ".gz")
t path))))))
(if (not filename)
(error "The library \"%s\" is not in the path." library))
(save-excursion
(set-buffer (find-file-noselect filename))
(save-match-data
(let (;; avoid defconst, defgroup, defvar (any others?)
(regexp (format "^\\s-*(def[^cgv\W]\\w+\\s-+%s\\s-"
(regexp-quote (symbol-name function))))
(syntable (syntax-table)))
(set-syntax-table emacs-lisp-mode-syntax-table)
(goto-char (point-min))
(if (prog1
(re-search-forward regexp nil t)
(set-syntax-table syntable))
(progn
(beginning-of-line)
(list (current-buffer) (point)))
(error "Cannot find definition of %s" function))))))))
(defun function-at-point () (defun function-at-point ()
(or (condition-case () (or (condition-case ()
@ -174,108 +201,164 @@ defined is searched in PATH instead of `load-path' (see
(and (symbolp obj) (fboundp obj) obj)))) (and (symbolp obj) (fboundp obj) obj))))
(error nil)))) (error nil))))
(defun find-function-read-function () (defun find-function-read (&optional variable-p)
"Read and return a function, defaulting to the one near point. "Read and return an interned symbol, defaulting to the one near point.
The function named by `find-function-function' is used to select the If the optional VARIABLE-P is nil, then a function is gotten
default function." defaulting to the value of the function `function-at-point', otherwise
(let ((fn (funcall find-function-function)) a variable is asked for, with the default coming from
`variable-at-point'."
(let ((symb (funcall (if variable-p
'variable-at-point
'function-at-point)))
(enable-recursive-minibuffers t) (enable-recursive-minibuffers t)
val) val)
(setq val (completing-read (if (equal symb 0)
(if fn (setq symb nil))
(format "Find function (default %s): " fn) (setq val (if variable-p
"Find function: ") (completing-read
obarray 'fboundp t)) (concat "Find variable"
(if symb
(format " (default %s)" symb))
": ")
obarray 'boundp t nil)
(completing-read
(concat "Find function"
(if symb
(format " (default %s)" symb))
": ")
obarray 'fboundp t nil)))
(list (if (equal val "") (list (if (equal val "")
fn (intern val))))) symb
(intern val)))))
(defun find-function-do-it (function path switch-fn) (defun find-function-do-it (symbol variable-p switch-fn)
"Find Emacs Lisp FUNCTION in PATH and display it with SWITCH-FN. "Find Emacs Lisp SYMBOL in a buffer and display it with SWITCH-FN.
Point is saved if FUNCTION is in the current buffer." If VARIABLE-P is nil, a function definition is searched for, otherwise
a variable definition is searched for. The start of a definition is
centered according to the variable `find-function-recenter-line'.
See also `find-function-after-hook'.
Point is saved in the buffer if it is one of the current buffers."
(let ((orig-point (point)) (let ((orig-point (point))
(buffer-point (find-function-noselect function path))) (orig-buffers (buffer-list))
(if buffer-point (buffer-point (funcall (if variable-p
(progn 'find-variable-noselect
(if (eq (current-buffer) (car buffer-point)) 'find-function-noselect)
(push-mark orig-point)) symbol)))
(funcall switch-fn (car buffer-point)) (when buffer-point
(goto-char (elt buffer-point 1)) (funcall switch-fn (car buffer-point))
(recenter 0))))) (when (memq (car buffer-point) orig-buffers)
(push-mark orig-point))
(goto-char (cdr buffer-point))
(recenter find-function-recenter-line)
(run-hooks find-function-after-hook))))
;;;###autoload ;;;###autoload
(defun find-function (function &optional path) (defun find-function (function)
"Find the definition of the function near point in the current window. "Find the definition of the function near point in the current window.
Finds the Emacs Lisp library containing the definition of the function Finds the Emacs Lisp library containing the definition of the function
near point (selected by `find-function-function') and places point near point (selected by `function-at-point') in a buffer and
before the definition. Point is saved if FUNCTION is in the current places point before the definition. Point is saved in the buffer if
buffer. it is one of the current buffers.
If the optional argument PATH is given, the library where FUNCTION is The library where FUNCTION is defined is searched for in
defined is searched in PATH instead of `load-path'" `find-function-source-path', if non `nil', otherwise in `load-path'.
(interactive (find-function-read-function)) See also `find-function-recenter-line' and `find-function-after-hook'."
(find-function-do-it function path 'switch-to-buffer)) (interactive (find-function-read))
(find-function-do-it function nil 'switch-to-buffer))
;;;###autoload ;;;###autoload
(defun find-function-other-window (function &optional path) (defun find-function-other-window (function)
"Find the definition of the function near point in the other window. "Find the definition of the function near point in the other window.
Finds the Emacs Lisp package containing the definition of the function See `find-function' for more details."
near point (selected by `find-function-function') and places point (interactive (find-function-read))
before the definition. Point is saved if FUNCTION is in the current (find-function-do-it function nil 'switch-to-buffer-other-window))
buffer.
If the optional argument PATH is given, the package where FUNCTION is
defined is searched in PATH instead of `load-path'"
(interactive (find-function-read-function))
(find-function-do-it function path 'switch-to-buffer-other-window))
;;;###autoload ;;;###autoload
(defun find-function-other-frame (function &optional path) (defun find-function-other-frame (function)
"Find the definition of the function near point in the another frame. "Find the definition of the function near point in the another frame.
Finds the Emacs Lisp package containing the definition of the function See `find-function' for more details."
near point (selected by `find-function-function') and places point (interactive (find-function-read))
before the definition. Point is saved if FUNCTION is in the current (find-function-do-it function nil 'switch-to-buffer-other-frame))
buffer.
If the optional argument PATH is given, the package where FUNCTION is (defun find-variable-noselect (variable)
defined is searched in PATH instead of `load-path'" "Returns a pair `(buffer . point)' pointing to the definition of SYMBOL.
(interactive (find-function-read-function))
(find-function-do-it function path 'switch-to-buffer-other-frame)) Finds the Emacs Lisp library containing the definition of SYMBOL
in a buffer and the point of the definition. The buffer is
not selected.
The library where VARIABLE is defined is searched for in
`find-function-source-path', if non `nil', otherwise in `load-path'."
(if (not variable)
(error "You didn't specify a variable"))
(let ((library (symbol-file variable)))
(find-function-search-for-symbol variable 'variable library)))
;;;###autoload
(defun find-variable (variable)
"Find the definition of the variable near point in the current window.
Finds the Emacs Lisp library containing the definition of the variable
near point (selected by `variable-at-point') in a buffer and
places point before the definition. Point is saved in the buffer if
it is one of the current buffers.
The library where VARIABLE is defined is searched for in
`find-function-source-path', if non `nil', otherwise in `load-path'.
See also `find-function-recenter-line' and `find-function-after-hook'."
(interactive (find-function-read 'variable))
(find-function-do-it variable t 'switch-to-buffer))
;;;###autoload
(defun find-variable-other-window (variable)
"Find the definition of the variable near point in the other window.
See `find-variable' for more details."
(interactive (find-function-read 'variable))
(find-function-do-it variable t 'switch-to-buffer-other-window))
;;;###autoload
(defun find-variable-other-frame (variable)
"Find the definition of the variable near point in the another frame.
See `find-variable' for more details."
(interactive (find-function-read 'variable))
(find-function-do-it variable t 'switch-to-buffer-other-frame))
;;;###autoload ;;;###autoload
(defun find-function-on-key (key) (defun find-function-on-key (key)
"Find the function that KEY invokes. KEY is a string. "Find the function that KEY invokes. KEY is a string.
Point is saved if FUNCTION is in the current buffer." Point is saved if FUNCTION is in the current buffer."
(interactive "kFind function on key: ") (interactive "kFind function on key: ")
(save-excursion (let ((defn (key-binding key))
(let ((modifiers (event-modifiers (aref key 0))) (key-desc (key-description key)))
window position) (if (or (null defn) (integerp defn))
;; For a mouse button event, go to the button it applies to (message "%s is unbound" key-desc)
;; to get the right key bindings. And go to the right place (if (consp defn)
;; in case the keymap depends on where you clicked. (message "%s runs %s" key-desc (prin1-to-string defn))
(if (or (memq 'click modifiers) (memq 'down modifiers) (find-function-other-window defn)))))
(memq 'drag modifiers))
(setq window (posn-window (event-start (aref key 0))) ;;;###autoload
position (posn-point (event-start (aref key 0))))) (defun find-function-at-point ()
(if (windowp window) "Find directly the function at point in the other window."
(progn (interactive)
(set-buffer (window-buffer window)) (let ((symb (function-at-point)))
(goto-char position))) (when symb
;; Ok, now look up the key and name the command. (find-function-other-window symb))))
(let ((defn (key-binding key)))
(if (or (null defn) (integerp defn)) ;;;###autoload
(message "%s is undefined" (key-description key)) (defun find-variable-at-point ()
(if (consp defn) "Find directly the function at point in the other window."
(message (if (windowp window) (interactive)
"%s at that spot runs %s" (let ((symb (variable-at-point)))
"%s runs %s") (when (and symb (not (equal symb 0)))
(key-description key) (prin1-to-string defn)) (find-variable-other-window symb))))
(find-function-other-window defn)))))))
(provide 'find-func) (provide 'find-func)
;;; find-func.el ends here ;;; find-func.el ends here