Many text editors allow definitions of functions and other language
objects to be quickly and easily located in source files through a
tagging utility. This functionality requires the relevant source
files to be preprocessed, producing an index (or tag) file containing
the names and their corresponding locations. There are multiple tag
file formats, the most popular being the vi-style ctags format and the
and emacs-style etags format. Tag files in these formats are usually
generated by the ctags
and etags
utilities
respectively. Unfortunately, these programs do not recognize R code
syntax. They do allow tagging of arbitrary language files through
regular expressions, but this is not sufficient for R.
R 2.9.0 onwards provides the rtags
function as a
tagging utility for R code. It parses R code files (using R's parser)
and produces tags in Emacs' etags
format.
The API provided by rtags()
is described in the
online documentation. In practice, one would typically want to tag
not only R files, but also C/C++ files in a package (or the R
sources), and possibly the documentation files as well. C files can
be tagged by etags
, as can R documentation files using
its regular expression feature; e.g.,
$ etags -l none --regex='/\\alias[{]\([^{}]*\)[}]/\1/' foo.RdR provides a front-end script
R CMD rtags
to make this
typical use-case easier. The usage is given by
$ R CMD rtags --help Usage: R CMD rtags [options] [path] Tag C, R, and Rd files under the directory 'path' (pwd by default). Options: -h, --help print short help message and exit -v, --version print version info and exit -o, --output=FILE write output to FILE (default TAGS) --no-c do not tag C (.c, .h) files --no-R do not tag R (.R, .r, .S, .s) files --no-Rd do not tag Rd (.Rd) files -a --append append to output file (overwrites by default) -V, --verbose echo the name of files processed Report bugs to <deepayan.sarkar@r-project.org>.A typical sequence of calls to generate a TAGS file might be
$ R CMD rtags -o TAGS /path/to/Rpacks $ R CMD rtags.sh -o TAGS --append /path/to/R/trunk/srcwhere
/path/to/Rpacks
contains multiple R packages, and
/path/to/R/trunk
contains a checkout of the trunk of the
R svn tree.
Once the TAGS file is created, it can be loaded inside an Emacs
session using M-x visit-tags-table RET TAGS
. The
definition of a symbol can now be located using the M-.
keyboard shortcut (see the Emacs manual for more details)
rtags
can successfully tag normal R function declarations
of the form foo <- function(...)
. It also knows about
S4
constructs such as setClass
and
setMethod
. A special markup is used for S4
method definitions: for example, in the Matrix
package,
the solve
method with signature("CHMfactor",
"matrix")
will be tagged with the token
solve,CHMfactor,matrix
. This is useful because in
conjuntion with Emacs' tag completion feature, it can make locating
the method of interest much easier. For example,
M-. solve TAB TABwill list all possible completions in a separate buffer:
Click <mouse-2> on a completion to select it. In this buffer, type RET to select the completion near point. Possible completions are: solve solve,CHMfactor,ANY solve,CHMfactor,ANY-method solve,CHMfactor,ddenseMatrix solve,CHMfactor,ddenseMatrix-method solve,CHMfactor,dsparseMatrix solve,CHMfactor,dsparseMatrix-method solve,CHMfactor,matrix solve,CHMfactor,matrix-method solve,CHMfactor,numeric solve,CHMfactor,numeric-method . . .Note that one possible completion is
solve,CHMfactor,matrix-methodwhich points to the documentation file for this method. Generally, all
\alias
entries in documentation files are tagged,
usually resulting in duplicate entries for most function definitions.
In such cases, M-.
will bring up the first match, and
subsequent matches can be visited by the shortcut C-u M-.
(this is a standard Emacs feature).
You can have Emacs read your TAGS table (stored in, say,
~/rtags/TAGS
) during startup by putting the following in
your .emacs
file:
(visit-tags-table "~/rtags/TAGS")If you find yourself using
C-u M-.
frequently to visit
multiple locations of a tag, you might also find it useful to define a
simpler shortcut; e.g.,
(defun find-next-tag () (interactive) (find-tag "" t)) (global-set-key (kbd "C->") 'find-next-tag)