Eclipse to Emacs: Navigating your source tree
Two other things I like about the Eclipse development environment are the ability to jump to a function definition and the ability to open any resource in the workspace. Fortunately, these shortcuts are easy to duplicate in Emacs.
Exuberant Ctags is a utility that builds an index of the function definitions in your source code. You can use this index to jump to any function definition using editors such as vi or emacs. To index your Drupal source code, for example, go to the root of your source directory and use a command like this:
find . -name \*.module -o -name \*.php -o -name \*.inc -o -name \*.install -o -name \*.engine -o -name \*.profile | etags -l php -
To use this index in Emacs, add the following code to your ~/.emacs, changing drupal-project-path as necessary:
(defvar drupal-project-path "~/proj/example" "*Base path for your project") (require 'etags) (setq tags-file-name (expand-file-name "TAGS" drupal-project-path))
Evaluate the code. You can then use M-. (find-tag) to jump to the declaration of a function in your project.
To open any resource in your source tree with a few keystrokes, index the files with filecache and use ido to open the file. Ido is well worth learning how to use. Here's the code I use, taken almost directly from the filecache documentation:
(require 'filecache)
(require 'ido)
(defun file-cache-ido-find-file (file)
"Using ido, interactively open file from file cache'.
First select a file, matched using ido-switch-buffer against the contents
in `file-cache-alist'. If the file exist in more than one
directory, select directory. Lastly the file is opened."
(interactive (list (file-cache-ido-read "File: "
(mapcar
(lambda (x)
(car x))
file-cache-alist))))
(let* ((record (assoc file file-cache-alist)))
(find-file
(expand-file-name
file
(if (= (length record) 2)
(car (cdr record))
(file-cache-ido-read
(format "Find %s in dir: " file) (cdr record)))))))
(defun file-cache-ido-read (prompt choices)
(let ((ido-make-buffer-list-hook
(lambda ()
(setq ido-temp-list choices))))
(ido-read-buffer prompt)))
(ido-mode t)
;; Change this to filter out your version control files
(add-to-list 'file-cache-filter-regexps "\\.svn-base$")
(if drupal-project-path
(file-cache-add-directory-using-find drupal-project-path))
(global-set-key (kbd "ESC ESC f") 'file-cache-ido-find-file)
This turns ESC ESC f into a handy shortcut for finding files anywhere in your project tree. Read the source code (ido.el) for more information on ido shortcuts.
Good luck and have fun!
(UPDATE: Added "." to the find command – two people suggested it! =) )
(UPDATE: Forced etags to detect files as php and added .engine and .profile to the list of extensions)
(UPDATE: Added version control filter for file-cache)
it's probably just a typo, but you should have a pathname before the expression in 'find'. e.g. 'find ~/ -name …'
It is all right, thank you, but how do I navigate back and forth?
Say I was in file BfromA.cpp then went to spec of the class in BfromA.hpp by find-tag
and then to the file A.hpp to the father class, again by find-tag.
Is there any way to go "back" to BfromA.cpp without mentioning it explicitly – just go "back"
and then again go "forward" to A.hpp explicitly?
Thank you very much
@Nick
When you go to the other file after using the find-tag, you end up switching buffers. This means the last buffer is simply a C-x b RET away. Unfortunately, it also means that if you go to another definition, then you have to return to the buffer more explicitly.
With that said, hopefully Sacha will have a good answer to that question
FWIW, I have just started using the etags and find-tag feature, and it is very helpful. It was also extremely fast adding the tag index, which was a pleasant surprise.
Great post!
The same can be achieved with my vps package
http://ozymandias.dk/emacs/emacs.html#vps
@Eric
Hi!
I know this way, but it falls into "explicit" navigation.
I think there should be some way to hook find-tag with emacs bookmarks and then
it is possible to navigate through them.
After find-tag you can go back with pop-tag-mark bound to M-* usually. I don't know of a way to go forwards again other than by M-. on the same keyword. I use etags-select-find-tag-at-point instead of find-tag:
___
M-. runs the command etags-select-find-tag-at-point
which is an interactive Lisp function in `etags-select.el'.
It is bound to M-..
(etags-select-find-tag-at-point)
Do a find-tag-at-point, and display all exact matches. If only one match is
found, see the `etags-select-no-select-for-one-match' variable to decide what
to do.
___
I also find tags-apropos quite useful.
I use M-. with interactive arg (C-u) to find next tag and `pop-tag-mark' (bound to M-* by default) to get back to previous tag.
You can go back with M-*. There is no forward command, so you use M-. go to the same function again.
The path is not required with the find command on GNU/Linux, I think – or at least the one that I've got installed. =) I should put that in, though, as other systems require it. Thanks!
Hi Sacha,
I am absolutely certain that any geek reading this will be using some form of version control in their source trees…. at work I use Subversion and to exclude all the junk svn files 'find' will pull in I added the following before the file-cache find command:
(add-to-list 'file-cache-filter-regexps "\\.svn-base$")
Regards
Arjen
Arjen: Thanks for pointing that out! I ended up adding that line to my ~/.emacs before I read your comment. Much nicer. Now if I can just get it to sort by frequency of access…
I tried the command:
find -name \*.module -o -name \*.php -o -name \*.inc -o -name \*.install | etags -
and I get an error:
etags: Unknown option -
Was the command truncated from the post or something? what's the parameter?
Is there a way to automate the etags generation from within emacs so I don't have to remember this command every time I start a project?
There is actually an error in the post.
find needs a first argument that says where to look for these files:
find -name \*.module -o -name \*.php -o -name \*.inc -o -name \*.install | etags -
should be
find . -name \*.module -o -name \*.php -o -name \*.inc -o -name \*.install | etags -
notice the dot between find and the -name,
<laugh> Okay, everyone else has a find that requires a path… Updated!
There's an etags that comes with Emacs, and there's an etags which comes with Exuberant Ctags. I'm using the one from Exuberant CTags. Don't know if that makes a difference…
You can also enable flymake to check your PHP source code for errors as you type it, I posted the elisp code for that on my blog:
http://blog.nethazard.net/2008/07/31/php-syntax-check-as-you-type-with-emacs/
fixed it!
In my version of exhuberant Ctags i would have to use the command like this:
find . -name \*.module -o -name \*.php -o -name \*.inc -o -name \*.install | etags -L -
With the Exuberant CTags from Sourceforge, I just found out that you should probably make it etags -l php -. =)
Totally! Next, I'm going to go into more detail about Xdebug and GEBEN…
With the Exuberant CTags from the Ubuntu Hardy repositories the command is:
etags –language-force=php -L -
[...] she could be more productive in Emacs then in Eclipse in her current project, read about it here, here and [...]
etags isn't finding my class methods in my php files. Do you have a regex that you use to find the public class methods?
I've got a problem: I use php 5 and I think etags supports only php4. Bad
Hi,
I following the above instruction.
But when I enable filecache adn ido in .emacs, my emacs goes to 100% for > 5 minutes, for some reason. I have to kill the email using System monitor.
Can you please tell em how to fix it? I am running on ubuntu.
There is some confusion between etags and http://ctags.sourceforge.net/
or at least they are not the same in Debian.
I generate my tags using something like
SRC=~/.emacs.d
cd $SRC
ctags-exuberant -e –recurse=yes –links=yes –verbose=no
No need for find.
And unlike etags it supports recursion in the one command.
Do you think that you might have some symbolic links that cause a loop? That's the first thing I think of…
[...] Chua wrote a post about navigating your source tree using ido and filecache. I'm not sure what additional benefits filecache offers over vanilla ido as ido finds files [...]