semantic code search for emacs lisp
Emacs Lisp Other
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
test
.gitignore
.travis.yml
CHANGELOG.md
Cask
Makefile
README.md
bench.sh
elisp-refs-bench.el
elisp-refs.el
refs_filtered.png
refs_screenshot.png

README.md

elisp-refs

Build Status Coverage Status MELPA

elisp-refs is an intelligent code search for Emacs lisp.

It can find references to functions, macros or variables. Unlike a dumb text search, elisp-refs actually parses the code, so it's never confused by comments or variables with the same name as functions.

screenshot

This is particularly useful for finding all the places a function is used, or finding examples of usage.

Interested readers may enjoy my blog post: Searching A Million Lines Of Lisp.

Installation

Install from MELPA (recommended) or just add elisp-refs to your load-path.

Commands available

  • elisp-refs-function (find function calls)
  • elisp-refs-macro (find macro calls)
  • elisp-refs-variable (find variable references)
  • elisp-refs-special (find special form calls)
  • elisp-refs-symbol (find all references to a symbol)

These command search all the files currently loaded in your Emacs instance.

If called with a prefix, you can limit search results to specific directories. For example:

C-u M-x elisp-refs-macro RET pcase RET ~/.emacs.d/elpa/magit-20160927.510 RET

will search for uses of pcase in magit:

filtering screenshot

Semantic analysis

elisp-refs has street smarts: given (defun foo (bar) (baz)), it understands that bar is a variable and baz is a function.

elisp-refs understands the following forms:

  • defun defsubst defmacro cl-defun
  • lambda
  • let let*
  • funcall apply
  • sharp quoted expressions (e.g. #'some-func)

Limitations

elisp-refs understands elisp special forms, and a few common macros. However, it cannot understand arbitrary macros.

Therefore elisp-refs will assume that (other-macro (foo bar)) is a function call to foo. If this is incorrect, you may wish to use the command elisp-refs-symbol to find all references to the foo symbol.

If other-macro is a common macro, please consider submitting a patch to elisp-refs--function-p to make elisp-refs smarter.

elisp-refs also does not support indirect calls.

;; Since we do a simple syntax tree walk, this isn't treated as a
;; call to foo.
(let ((x (symbol-function 'foo)))
  (funcall x))

;; Similarly, indirect function calls are not treated as
;; function calls.
(defun call-func (x)
  (funcall x))
(call-func 'foo)

;; However, if you use sharp quoting, elisp-refs knows it's a function
reference!
(call-func #'foo)

Running tests

You can run the tests with:

$ cask install
$ cask exec ert-runner

Performance

elisp-refs is CPU-intensive elisp and has been carefully optimised. You can run the benchmark script with:

$ cask install
$ ./bench.sh

New features are carefully measured to ensure performance does not get worse.

See elisp-refs-bench.el for more details.

Alternative Projects

xref-find-references: This command is included in Emacs 25.1, but it's based on a text search. It is confused by comments and strings, and cannot distinguish between functions and variables.

xrefs-find-references is also line oriented, so it does not show the whole sexp that matched your search. Since it requires text files, it doesn't search built-in .el.gz files.

TAGS: It is possible to record function references in TAGS files. Whilst universal-ctags (formerly known as exuberant-ctags) does provide the ability to find references, it is not supported in its lisp parser.

etags, the TAGS implementation shipped with Emacs, cannot find references (to my knowledge).

el-search allows you to search for arbitrary forms in elisp files. It's slower, but a much more general tool. Its design greatly influenced elisp-refs.

elisp-slime-nav finds definitions, not references. It's a great complementary tool.