ctags etags gtags: How to Find Where a Function is Defined or Called?

By Xah Lee. Date:

if you work with a project new to you, that has tens of files or more in nested directories, you'll need this.

How do you quickly find where a function is called, or where a function is defined?

the classic tool for this is ctags. Basically, ctags is a shell command. Run it to create a index file, then you can use command to quickly jump to a identifier (function)'s definition.

(using grep is much slower, because everytime it needs to search all the files. That's why ctags creates a index files first, which is basically the one-shot search result of all function names.)

ctags index file is named tags.

The index file has a simple format, like this:


The fields are specified as follows:

Any identifier, not containing white space
One tab character, although many versions of vi can handle any amount of white space.
The name of the file where {tagname} is defined, relative to the current directory
Ex mode command that will take the editor to the location of the tag. For POSIX implementations of vi this may only be a search or a line number.

Variations: ctags, etags, gtags (GNU Global)

There are many improvements of the ctags tool. They include:

From emacs.
GNU GLOBAL from GNU, with command name gtags and global

The index file format are similar or compatible with ctags.

GNU Global home page is at: http://www.gnu.org/software/global/

Install gtags on Ubuntu Linux

# install gnu global
sudo apt-get install global

After intall, you have 2 commands:

Generate index file.
Locate identifiers.

See man gtags and man global

See the official gtags tutorial at http://www.gnu.org/software/global/globaldoc_toc.html

how to make etags Index Clojure Files?

there's this regex from http://nakkaya.com/2009/12/13/getting-etags-to-index-clojure-files/ and http://stackoverflow.com/questions/1481842/clojure-emacs-etags

find . \! -name '.*' -name '*.clj' | xargs etags --regex='/[ \t\(]*def[a-zA-Z!$%&*+\-.\/:<=>?@^_~]*[ \n\t]+\(\^{[^}]*}[ \n\t]+\|\)\([a-zA-Z!$%&*+\-.\/:<=>?@^_~]+\)/\2/s' --regex='/[ \t\(]*ns \([a-z.]+\)/\1/'

but it doesn't work for me

for now, just use emacs rgrep. [see Emacs: Searching for Text in Files (grep, find)]

or use this emacs command, which calls git grep.

(defvar gitgrep-history nil)

(defun gitgrep (@search-string)
"call git grep to search symbols in a project.

2014-11-19 by “Left Right” https://plus.google.com/113859563190964307534/posts/CyEsoyhkTVe
   (let (($sym (thing-at-point 'symbol)))
       "String to search for: "
       (list $sym
       'identity nil $sym gitgrep-history $sym))))
  (grep (format "git --no-pager grep -P -n '%s'" @search-string)))