Friday, June 12, 2009

Emacs Tip #30: igrep

Finding text in files is an everyday (every hour) occurrence for most programmers. And in Unix-land, people generally use grep to do the searching.

Of course Emacs has an interface to grep, which now (as of Emacs 22) even has interfaces for using both find and grep together to search through directory structures (grep-find, rgrep).

But, before those existed, someone wrote a nice package igrep.el, which has a very intuitive (IMO) interface.

M-x igrep-find RET RET /search/in/here/*.cxx RET

which will search for regexp in all the files with the extension .cxx underneath the /search/in/here/ directory.

As you'd expect, the results of the search show up in a buffer, and clicking on any one of them jumps you to that spot in the file. And the standard M-x next-error (aka C-x `) will jump you to the next match.

About the only thing I don't like is that the paths returned in the results are the fully expanded path. In other words, when the paths to the files are really long, most of the result buffer is taken up with just the pathname. So I wrote this little snippet of code which post-processes the buffer to trim the names relative to the search path entered (in the example above, all the /search/in/here/ would be removed from the file names.

(defun my-shorten-filenames-in-compilation (buffer &optional stat)
"remove the absolute filenames if they match the default-directory"
(interactive "b")
(set-buffer buffer)
(goto-char (point-min))
(let ((buffer-read-only nil)
(base-dir (if (re-search-forward "find \\([^ ]+\\) " nil t)
(if (string-match "/$" (match-string 1))
(match-string 1)
(concat (match-string 1) "/"))
(setq default-directory base-dir)
(while (re-search-forward (concat "^" default-directory) nil t)
(replace-match "")))))

(add-hook 'compilation-finish-functions 'my-shorten-filenames-in-compilation)

I do realize that the built-in M-x rgrep does this automatically, I just prefer the igrep interface.

1 comment:

TTK said...

I was looking for this for long time :) I'll give it a try today.