Emacs Tags for R


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.

Using rtags

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.Rd
R 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).

  -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/src
where /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 TAB
will 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,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
which 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 ()
  (find-tag "" t))

(global-set-key (kbd "C->") 'find-next-tag)

Last modified: Tue Jun 1 11:41:48 IST 2010