Yi Tang Data Science and Emacs

etags - Build a TAG for Multiple R Packages

Here is what tried to build a TAG for multiple R packages. It enable me to jump to a location where the function/variable is defined and modify if I want to.

Useful variable and functions

ess-r-package-library-path
default path to find packages, should be a list
ess-r-package-root-file
if the folder has DESCRIPTION file, then the folder is a R package.
(ess-build-tags-for-directory DIR TAGFILE)
build tag on DIR to TARGET.
tags-table-list
List of file names of tags tables to search.
(visit-tags-table FILE &optional LOCAL)
Tell tags commands to use tags table file.
;; new variable 
(defvar ess-r-package-library-tags nil
  "A TAG file for multiple R packages.")

(setq ess-r-package-library-path '("~/tmp/feather/R" "~/tmp/RPostgres/"))
(setq ess-r-package-library-tags "~/tmp/all_tags")

(dolist (pkg-path ess-r-package-library-path)
  (let ((pkg-name (ess-r-package--find-package-name pkg-path)))
    (unless (and pkg-name pkg-path
                 (file-exists-p (expand-file-name ess-r-package-root-file pkg-path)))
      (error "Not a valid package. No '%s' found in `%s'." ess-r-package-root-file pkg-path))
    (ess-build-tags-for-directory pkg-path ess-r-package-library-tags)
    ))

Note the workhorse is ess-build-tags-for-directory which does what it means. The core of this function use find and etags program. The find program will find files with extension .cpp, R, nw etc, and then feed to (using pipe) to the etags program which generate a TAG table. These two steps are demonstrated in the following snippet, which is grabbed from the source code of ess-build-tags-for-directory.

(setq find-cmd (format "find %s -type f -size 1M \\( -regex \".*\\.\\(cpp\\|jl\\|[RsrSch]\\(nw\\)?\\)$\" \\)" (car ess-r-package-library-path)))

(setq regs (delq nil (mapcar (lambda (l)
                               (if (string-match "'" (cadr l))
                                   nil ;; remove for time being
                                 (format "/%s/\\%d/"
                                         (replace-regexp-in-string "/" "\\/" (nth 1 l) t)
                                         (nth 2 l))))
                             imenu-generic-expression)))
(setq tags-cmd (format "etags -o %s --regex='%s' -" "~/lala"
                       (mapconcat 'identity regs "' --regex='")))

(setq sh-cmd (format "%s | %s" find-cmd tags-cmd))
(shell-command sh-cmd)

Note when they are used in Emacs, the tags-table-list variable is appended with the path to the new TAG table. So that the user can use xref-find-definitions (M-.) to jump (if the point is under a word) or select which function/variable to jump to. The users then check the function/variable definition, or modify it if it is necessary. Then call xref-pop-marker-stack (M-,) to jump back.

If you have any questions or comments, please post them below. If you liked this post, you can share it with your followers or follow me on Twitter!
comments powered by Disqus