Finding stuff

jplindstrom on 2008-12-21T21:38:54

If you work with even a moderately large code base, it's very important to have a way to easily find stuff in it. Otherwise you'll inevitably break things when you change something and are unaware of all the places that thing is used.

By trying to keep things well factored you can try to keep related things in one place...

...but there are many ways to slice the abstractions, for example across the domain (Person, MoneyAccount) and technical responsibilities (MVC layers, tests).

If you use a statically typed language the IDE can keep track of things for you...

...but there are usually lots of ways to represent something outside of the core programming language; SQL files, XML data files, test data, config files.

grep-find and ack

For a long time, I just used the Emacs grep-find command and ack. In Emacs, the current working directory is the cwd of the current buffer, so I used to switch to the *svn-status* buffer which has the project root directory as cwd, and run grep-find from there.

With the command history, it's easy to reuse and adapt a command line useful for grep-mode to understand (file name and line number):

ack --nogroup --nocolor -- SEARCH_TERM

Add --perl, --xml, --yaml or --all according to taste.

Navigating to matching lines is very convenient. Either hit Return in the *grep* buffer, or C-c C-c in a source file to jump to the next match.

This is extremely powerful when combined with keyboard macros to make complex project-wide edits.

(Clever trick: record the macro so that the last thing it does is to position point at the next place to edit. That way you can eyeball the text to make sure it's safe to run the macro again.)

So this is useful, but still a few too many key strokes to get to the actual search.

project-root

The project-root package is one way to define the concept of a project in Emacs. This piece of .emacs config defines a sensible Perl setup:

(require 'project-root)
(setq project-roots
      '(("Generic Perl Project"
         :root-contains-files ("t" "lib"))))

(global-set-key (kbd "C-c p g")       'project-root-grep)
(global-set-key (kbd "C-c p a")       'project-root-ack)
(global-set-key (kbd "C-c p C-x C-f") 'project-root-find-file)

With that you can use:

  • C-c p g or C-c p a to find stuff, similar to what I described above.

  • C-c p C-x C-f to open a file relative to the project root. This is especially useful for opening file names you copy from other shells, tests, error messages, etc.

project-root also provides the with-project-root macro for running any existing function programmatically, and the project-root-execute-extended-command defun. If you bind the last one to a key, you can use that as a prefix to run anything from the root directory.

Very handy.

PerlySense

Devel::PerlySense also has a concept of a project. Since the PerlySense backend is editor neutral, it doesn't use project-root. And since release 0.0170 there is support for Finding Code in the project using ack.

In addition to the general ability to ack through the code base, it also provides a few useful Perl specific searches.

Find with Ack

[ Screenshot ]

C-o f a -- Ack through the source and display the hits in a *grep* buffer.

Before running ack you'll get to edit the command line with a sensible default chosen from:

  • the active region

  • the word at point (with the -w whole word option)

Remember that earlier searches are available in the command history, just like with grep.

Tip: You can jump from a source file to the next hit with C-c C-c (type C-h m in the *grep* buffer to see the mode documentation).

Tip: if you need to find something else while browsing the *grep* buffer, you can easily rename the current *grep* buffer to something else using M-x rename-buffer.

Find sub declarations

[ Screenshot ]

C-o f s -- Ack the Project for sub declarations of the method, or word at point.

I.e. look for lines with sub NAME.

The point can be either on the method ($self->st|ore), or on the object ($us|er_agent->get()).

Find method calls

[ Screenshot ]

C-o f c -- Ack the Project for method calls to the method, or word at point.

I.e. look for lines with -ENAME.

Elisp

For elisp programmers, there's the ps/with-project-dir macro similar to with-project-root.


New Version?

Ovid on 2008-12-21T22:50:52

I hope those screenshots mean that you have a new version of Devel::CoverX::Covered coming out :)

Re:New Version?

jplindstrom on 2008-12-21T23:31:45

Um, not really...

What would you expect to be in that version?

project-root

philip-jackson on 2008-12-22T21:47:50

Sure sounds like whoever wrote project-root.el is a very handsome person.