;;; find-func.el --- find the definition of the Emacs Lisp function near point -*- lexical-binding:t -*-
-;; Copyright (C) 1997, 1999, 2001-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1999, 2001-2016 Free Software Foundation, Inc.
;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp>
;; Maintainer: petersen@kurims.kyoto-u.ac.jp
foo\\|\\(?:[^icfgv]\\|g[^r]\\)\\(\\w\\|\\s_\\)+\\*?\\)\\|easy-mmode-define-[a-z-]+\\|easy-menu-define\\|\
menu-bar-make-toggle\\)"
find-function-space-re
- "\\('\\|\(quote \\)?%s\\(\\s-\\|$\\|\(\\|\)\\)")
+ "\\('\\|(quote \\)?%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',
:group 'find-function
:version "22.1")
+(defcustom find-feature-regexp
+ (concat ";;; Code:")
+ "The regexp used by `xref-find-definitions' when searching for a feature definition.
+Note it must contain a `%s' at the place where `format'
+should insert the feature name."
+ ;; We search for ";;; Code" rather than (feature '%s) because the
+ ;; former is near the start of the code, and the latter is very
+ ;; uninteresting. If the regexp is not found, just goes to
+ ;; (point-min), which is acceptable in this case.
+ :type 'regexp
+ :group 'xref
+ :version "25.0")
+
+(defcustom find-alias-regexp
+ "(defalias +'%s"
+ "The regexp used by `xref-find-definitions' to search for an alias definition.
+Note it must contain a `%s' at the place where `format'
+should insert the feature name."
+ :type 'regexp
+ :group 'xref
+ :version "25.0")
+
(defvar find-function-regexp-alist
'((nil . find-function-regexp)
(defvar . find-variable-regexp)
- (defface . find-face-regexp))
+ (defface . find-face-regexp)
+ (feature . find-feature-regexp)
+ (defalias . find-alias-regexp))
"Alist mapping definition types into regexp variables.
Each regexp variable's value should actually be a format string
to be used to substitute the desired symbol name into the regexp.
LIBRARY should be a string (the name of the library)."
;; If the library is byte-compiled, try to find a source library by
;; the same name.
- (if (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
- (setq library (replace-match "" t t library)))
+ (when (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
+ (setq library (replace-match "" t t library)))
(or
(locate-file library
- (or find-function-source-path load-path)
- (find-library-suffixes))
+ (or find-function-source-path load-path)
+ (find-library-suffixes))
(locate-file library
- (or find-function-source-path load-path)
- load-file-rep-suffixes)
+ (or find-function-source-path load-path)
+ load-file-rep-suffixes)
(when (file-name-absolute-p library)
(let ((rel (find-library--load-name library)))
(when rel
(locate-file rel
(or find-function-source-path load-path)
load-file-rep-suffixes)))))
+ (find-library--from-load-path library)
(error "Can't find library %s" library)))
+(defun find-library--from-load-path (library)
+ ;; In `load-history', the file may be ".elc", ".el", ".el.gz", and
+ ;; LIBRARY may be "foo.el" or "foo", so make sure that we get all
+ ;; potential matches, and then see whether any of them lead us to an
+ ;; ".el" or an ".el.gz" file.
+ (let* ((elc-regexp "\\.el\\(c\\(\\..*\\)?\\)\\'")
+ (suffix-regexp
+ (concat "\\("
+ (mapconcat 'regexp-quote (find-library-suffixes) "\\'\\|")
+ "\\|" elc-regexp "\\)\\'"))
+ (potentials
+ (mapcar
+ (lambda (entry)
+ (if (string-match suffix-regexp (car entry))
+ (replace-match "" t t (car entry))
+ (car entry)))
+ (seq-filter
+ (lambda (entry)
+ (string-match
+ (concat "\\`"
+ (regexp-quote
+ (replace-regexp-in-string suffix-regexp "" library))
+ suffix-regexp)
+ (file-name-nondirectory (car entry))))
+ load-history)))
+ result)
+ (dolist (file potentials)
+ (dolist (suffix (find-library-suffixes))
+ (when (not result)
+ (cond ((file-exists-p file)
+ (setq result file))
+ ((file-exists-p (concat file suffix))
+ (setq result (concat file suffix)))))))
+ result))
+
(defvar find-function-C-source-directory
(let ((dir (expand-file-name "src" source-directory)))
(if (file-accessible-directory-p dir) dir))
(declare-function ad-get-advice-info "advice" (function))
(defun find-function-advised-original (func)
- "Return the original function symbol of an advised function FUNC.
-If FUNC is not the symbol of an advised function, just returns FUNC."
+ "Return the original function definition of an advised function FUNC.
+If FUNC is not a symbol, return it. Else, if it's not advised,
+return the symbol's function definition."
(or (and (symbolp func)
- (featurep 'advice)
- (let ((ofunc (cdr (assq 'origname (ad-get-advice-info func)))))
- (and (fboundp ofunc) ofunc)))
+ (featurep 'nadvice)
+ (let ((ofunc (advice--symbol-function func)))
+ (if (advice--p ofunc)
+ (advice--cd*r ofunc)
+ ofunc)))
func))
(defun find-function-C-source (fun-or-var file type)
(cons (current-buffer) (match-beginning 0))))
;;;###autoload
-(defun find-library (library)
+(defun find-library (library &optional other-window)
"Find the Emacs Lisp source of LIBRARY.
-LIBRARY should be a string (the name of the library)."
+LIBRARY should be a string (the name of the library). If the
+optional OTHER-WINDOW argument (i.e., the command argument) is
+specified, pop to a different window before displaying the
+buffer."
(interactive
(let* ((dirs (or find-function-source-path load-path))
(suffixes (find-library-suffixes))
(when (and def (not (test-completion def table)))
(setq def nil))
(list
- (completing-read (if def (format "Library name (default %s): " def)
+ (completing-read (if def
+ (format "Library name (default %s): " def)
"Library name: ")
- table nil nil nil nil def))))
- (let ((buf (find-file-noselect (find-library-name library))))
- (condition-case nil (switch-to-buffer buf) (error (pop-to-buffer buf)))))
+ table nil nil nil nil def)
+ current-prefix-arg)))
+ (prog1
+ (funcall (if other-window
+ 'pop-to-buffer
+ 'pop-to-buffer-same-window)
+ (find-file-noselect (find-library-name library)))
+ (run-hooks 'find-function-after-hook)))
;;;###autoload
(defun find-function-search-for-symbol (symbol type library)
If VERBOSE is non-nil, and FUNCTION is an alias, display a
message about the whole chain of aliases."
(let ((def (if (symbolp function)
- (symbol-function (find-function-advised-original function))))
+ (find-function-advised-original function)))
aliases)
;; FIXME for completeness, it might be nice to print something like:
;; foo (which is advised), which is an alias for bar (which is advised).
(not verbose)
(setq aliases (if aliases
(concat aliases
- (format ", which is an alias for `%s'"
- (symbol-name def)))
- (format "`%s' is an alias for `%s'"
- function (symbol-name def)))))
- (setq function (symbol-function (find-function-advised-original function))
- def (symbol-function (find-function-advised-original function))))
+ (format-message
+ ", which is an alias for `%s'"
+ (symbol-name def)))
+ (format-message "`%s' is an alias for `%s'"
+ function (symbol-name def)))))
+ (setq function (find-function-advised-original function)
+ def (find-function-advised-original function)))
(if aliases
(message "%s" aliases))
(cons function
(interactive (find-function-read 'defface))
(find-function-do-it face 'defface 'switch-to-buffer))
-;;;###autoload
-(defun find-function-on-key (key)
+(defun find-function-on-key-do-it (key find-fn)
"Find the function that KEY invokes. KEY is a string.
-Set mark before moving, if the buffer already existed."
- (interactive "kFind function on key: ")
+Set mark before moving, if the buffer already existed.
+
+FIND-FN is the function to call to navigate to the function."
(let (defn)
(save-excursion
(let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
(message "%s is unbound" key-desc)
(if (consp defn)
(message "%s runs %s" key-desc (prin1-to-string defn))
- (find-function-other-window defn))))))
+ (funcall find-fn defn))))))
+
+;;;###autoload
+(defun find-function-on-key (key)
+ "Find the function that KEY invokes. KEY is a string.
+Set mark before moving, if the buffer already existed."
+ (interactive "kFind function on key: ")
+ (find-function-on-key-do-it key #'find-function))
+
+;;;###autoload
+(defun find-function-on-key-other-window (key)
+ "Find, in the other window, the function that KEY invokes.
+See `find-function-on-key'."
+ (interactive "kFind function on key: ")
+ (find-function-on-key-do-it key #'find-function-other-window))
+
+;;;###autoload
+(defun find-function-on-key-other-frame (key)
+ "Find, in the other frame, the function that KEY invokes.
+See `find-function-on-key'."
+ (interactive "kFind function on key: ")
+ (find-function-on-key-do-it key #'find-function-other-frame))
;;;###autoload
(defun find-function-at-point ()
(define-key ctl-x-4-map "F" 'find-function-other-window)
(define-key ctl-x-5-map "F" 'find-function-other-frame)
(define-key ctl-x-map "K" 'find-function-on-key)
+ (define-key ctl-x-4-map "K" 'find-function-on-key-other-window)
+ (define-key ctl-x-5-map "K" 'find-function-on-key-other-frame)
(define-key ctl-x-map "V" 'find-variable)
(define-key ctl-x-4-map "V" 'find-variable-other-window)
(define-key ctl-x-5-map "V" 'find-variable-other-frame))