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.
;; Author: Jens Petersen <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
;; 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
;; 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
;; following code in your init file:
;;
;; ;;; find-func
;; (load "find-function")
;; (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)
;; (load "find-func")
;;
;; and away you go! It does pretty much what you would expect,
;; putting the cursor at the definition of the function at point.
;; and away you go! The default given keybindings as the ones
;; 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
;; "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:
(require 'loadhist)
;;; User variables:
(defgroup find-function nil
"Find the definition of the elisp function near point."
:prefix "find-function"
"Finds the definition of the Emacs Lisp symbol near point."
;; :prefix "find-function"
:group 'lisp)
(defcustom find-function-function 'function-at-point
"*The function used by `find-function' to select the function near
point.
(defcustom find-function-regexp
"^\\s-*(def[^cgv\W]\\w+\\*?\\s-+%s\\(\\s-\\|$\\)"
"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'."
:type 'function
Please send improvements and fixes to the maintainer."
: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)
(defcustom find-function-source-path nil
@ -82,71 +88,92 @@ default."
;;; Functions:
;;;###autoload
(defun find-function-noselect (function &optional path)
"Returns list (BUFFER POINT) pointing to the definition of FUNCTION.
(defcustom find-function-recenter-line 1
"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
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.
If the optional argument PATH is given, the library where FUNCTION is
defined is searched in PATH instead of `load-path' (see
`find-function-source-path')."
(and (subrp (symbol-function function))
(error "%s is a primitive function" function))
If the file where FUNCTION is defined is not known, then it is
searched for in `find-function-source-path' if non `nil', otherwise
in `load-path'."
(if (not 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))
library aliases)
aliases)
(while (symbolp def)
(or (eq def function)
(if aliases
(setq aliases (concat aliases
(format ", which is an alias for %s"
(format ", which is an alias for `%s'"
(symbol-name def))))
(setq aliases (format "an alias for %s" (symbol-name
def)))))
(setq aliases (format "`%s' an alias for `%s'"
function (symbol-name def)))))
(setq function (symbol-function function)
def (symbol-function function)))
(if aliases
(message aliases))
(setq library
(cond ((eq (car-safe def) 'autoload)
(nth 1 def))
((describe-function-find-file function))))
(if (null 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))))))))
(let ((library
(cond ((eq (car-safe def) 'autoload)
(nth 1 def))
((symbol-file function)))))
(find-function-search-for-symbol function nil library))))
(defun function-at-point ()
(or (condition-case ()
@ -174,108 +201,164 @@ defined is searched in PATH instead of `load-path' (see
(and (symbolp obj) (fboundp obj) obj))))
(error nil))))
(defun find-function-read-function ()
"Read and return a function, defaulting to the one near point.
(defun find-function-read (&optional variable-p)
"Read and return an interned symbol, defaulting to the one near point.
The function named by `find-function-function' is used to select the
default function."
(let ((fn (funcall find-function-function))
If the optional VARIABLE-P is nil, then a function is gotten
defaulting to the value of the function `function-at-point', otherwise
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)
val)
(setq val (completing-read
(if fn
(format "Find function (default %s): " fn)
"Find function: ")
obarray 'fboundp t))
(if (equal symb 0)
(setq symb nil))
(setq val (if variable-p
(completing-read
(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 "")
fn (intern val)))))
symb
(intern val)))))
(defun find-function-do-it (function path switch-fn)
"Find Emacs Lisp FUNCTION in PATH and display it with SWITCH-FN.
Point is saved if FUNCTION is in the current buffer."
(defun find-function-do-it (symbol variable-p switch-fn)
"Find Emacs Lisp SYMBOL in a buffer and display it with SWITCH-FN.
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))
(buffer-point (find-function-noselect function path)))
(if buffer-point
(progn
(if (eq (current-buffer) (car buffer-point))
(push-mark orig-point))
(funcall switch-fn (car buffer-point))
(goto-char (elt buffer-point 1))
(recenter 0)))))
(orig-buffers (buffer-list))
(buffer-point (funcall (if variable-p
'find-variable-noselect
'find-function-noselect)
symbol)))
(when buffer-point
(funcall switch-fn (car buffer-point))
(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
(defun find-function (function &optional path)
(defun find-function (function)
"Find the definition of the function near point in the current window.
Finds the Emacs Lisp library containing the definition of the function
near point (selected by `find-function-function') and places point
before the definition. Point is saved if FUNCTION is in the current
buffer.
near point (selected by `function-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.
If the optional argument PATH is given, the library 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))
The library where FUNCTION 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))
(find-function-do-it function nil 'switch-to-buffer))
;;;###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.
Finds the Emacs Lisp package containing the definition of the function
near point (selected by `find-function-function') and places point
before the definition. Point is saved if FUNCTION is in the current
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))
See `find-function' for more details."
(interactive (find-function-read))
(find-function-do-it function nil 'switch-to-buffer-other-window))
;;;###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.
Finds the Emacs Lisp package containing the definition of the function
near point (selected by `find-function-function') and places point
before the definition. Point is saved if FUNCTION is in the current
buffer.
See `find-function' for more details."
(interactive (find-function-read))
(find-function-do-it function nil 'switch-to-buffer-other-frame))
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-frame))
(defun find-variable-noselect (variable)
"Returns a pair `(buffer . point)' pointing to the definition of SYMBOL.
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
(defun find-function-on-key (key)
"Find the function that KEY invokes. KEY is a string.
Point is saved if FUNCTION is in the current buffer."
(interactive "kFind function on key: ")
(save-excursion
(let ((modifiers (event-modifiers (aref key 0)))
window position)
;; For a mouse button event, go to the button it applies to
;; to get the right key bindings. And go to the right place
;; in case the keymap depends on where you clicked.
(if (or (memq 'click modifiers) (memq 'down modifiers)
(memq 'drag modifiers))
(setq window (posn-window (event-start (aref key 0)))
position (posn-point (event-start (aref key 0)))))
(if (windowp window)
(progn
(set-buffer (window-buffer window))
(goto-char position)))
;; Ok, now look up the key and name the command.
(let ((defn (key-binding key)))
(if (or (null defn) (integerp defn))
(message "%s is undefined" (key-description key))
(if (consp defn)
(message (if (windowp window)
"%s at that spot runs %s"
"%s runs %s")
(key-description key) (prin1-to-string defn))
(find-function-other-window defn)))))))
(let ((defn (key-binding key))
(key-desc (key-description key)))
(if (or (null defn) (integerp defn))
(message "%s is unbound" key-desc)
(if (consp defn)
(message "%s runs %s" key-desc (prin1-to-string defn))
(find-function-other-window defn)))))
;;;###autoload
(defun find-function-at-point ()
"Find directly the function at point in the other window."
(interactive)
(let ((symb (function-at-point)))
(when symb
(find-function-other-window symb))))
;;;###autoload
(defun find-variable-at-point ()
"Find directly the function at point in the other window."
(interactive)
(let ((symb (variable-at-point)))
(when (and symb (not (equal symb 0)))
(find-variable-other-window symb))))
(provide 'find-func)
;;; find-func.el ends here