lisp service

(format T "Hello World") 
« Back to blog

Code Project Management in Emacs, Part 1

I have mostly converted entirely to using Emacs as my primary text/code editor, but one of the few things I always found a bit lacking was Emacs' ability to manage code projects (or at least, my knowledge of whatever ability Emacs has). Though Emacs is great with tags (and if you are using Slime, finding function definitons and usages is fairly easy), I would find myself constantly going back to Textmate to do things like see a listing of all my files or search for certain bits of code in my project. 

I finally decided this must stop.

I started with trying to make it easier to find files in Emacs. This is not directly related to project management in Emacs, but it seemed like something that could be tied in (and plus, I've wanted to do this for a while). I toyed around with a few things (icicles and ido - Divia settled on icicles), but finally decided on anything.  Anything is, as many others have mentioned, like Quicksilver for Emacs. Essentially, it lets you operate by first picking an "object" (where an object can pretty much be anything - some examples are files, buffers, or Emacs commands) and then commit and action on that object (like open in new frame for a file). Bill Clementson has a great writeup of how anything works here.

Installing anything isn't too difficult (if only I could mean that sentence literally for Lisp). Configuring it, however, can take some time - not because it is hard, but because there are so many things you can do with it. There are a variety of "sources" that anything uses which describe different actions/objects you can do when you invoke anything. These sources can be set up in your .emacs file.

So, at first, my .emacs file looked as follows:

 
;; anything setup 
(require 'anything-config) 
(global-set-key "\C-u" 'anything)
(global-set-key "\C-c\C-u" 'universal-argument) 
(setq anything-sources '(anything-c-source-buffers+ 
       anything-c-source-locate 
       anything-c-source-recentf 
       anything-c-source-org-headline 
 			 anything-c-source-buffer-not-found)) 

 
As you can see above, I set control-U to invoke anything easily. This worked great - I could now type in the first part of any file I wanted, and it would search for it very fast anywhere in my directory (the anything-c-source-locate source does this). The problem now was that I was getting too many results for a given file name candidate. What I realized I do about 80% of the time is look for files in one of two project directories. So, I added two custom sources in anything-config.el:
 
 
(defvar anything-contentrees-c-source-file-search 
 '((name . "Contentrees Search") 
  (candidates . (lambda () 
          (let ((args 
              (format "'%s' \( -path \*/.svn \) -prune 
-o -iregex '.*%s.*' -print" 
                  (get-source-directory "contentrees") 
                  anything-pattern))) 
          (start-process-shell-command "file-search-process" nil 
                  "find" args)))) 
  (type . file) 
  (requires-pattern . 4) 
  (delayed)) 
 "Source for searching matching files in contentrees recursively.") 
 
(defvar anything-weblocks-saikat-c-source-file-search 
 '((name . "Weblocks-saikat Search") 
  (candidates . (lambda () 
          (let ((args 
              (format "'%s' \( -path \*/.svn \) -prune 
-o -iregex '.*%s.*' -print" 
                  (get-source-directory "weblocks-saikat") 
                  anything-pattern))) 
          (start-process-shell-command "file-search-process" nil 
                  "find" args)))) 
  (type . file) 
  (requires-pattern . 4) 
  (delayed)) 
 "Source for searching matching files in weblocks-saikat recursively.") 

Then, in my .emacs, I changed my anything setup to:

 
;; anything setup 
(require 'anything-config) 
(global-set-key "\C-u" 'anything) 
(setq anything-sources '(anything-c-source-buffers+ 
       anything-weblocks-saikat-c-source-file-search 
       anything-contentrees-c-source-file-search 
       anything-c-source-locate 
       anything-c-source-recentf 
       anything-c-source-org-headline 
 			 anything-c-source-buffer-not-found)) 

Now, when I invoke anything and start typing in a word, I first get a list of possible buffers with that name followed by files in my two project directories, followed by a locate on my entire home directory, which is pretty much exactly what I wanted (and I got the added benefit of anything actions on these files, making it easier to do things like open the file in a new frame when I want). Note that I had to remap the command to make prefix arguments to C-c C-u.

One BIG caveat to using anything: I was using anything in Aquamacs at first, but it would constantly move my current window to the top right corner of my screen and resize it. After some research, it seemed like Aquamacs just doesn't really work with anything, so I had to switch to Carbon Emacs. Carbon Emacs is fine, although it handles frames and buffers the "true Emacs" way (whereas Aquamacs attaches buffers to frames), and this has taken some getting used to. 

Next, I want to get fuzzy matching working with anything, start using proel, and get Mercurial working from within Emacs.

Loading mentions Retweet

Comments (7)

Apr 17, 2009
andrew said...
Ctrl-u is normally used for prefix arguments, do you rebind that? Vc-mode should already support mercurial.
Apr 17, 2009
Thanks for pointing out the prefix argument thing rebinding, I had forgotten to mention it. Edited above to show my rebinding for universal-argument.
Also thanks for the tip on Vc-mode. I hadn't really looked into VCS support for Emacs yet, but will look it up when I do.
Apr 17, 2009
Mikhail said...
BTW, you can try to use 'ack' tool to do search within files. It automatically ignores VCS dirs, temp files, etc.
Apr 17, 2009
Thanks for the suggestion Mikhail - don't have time to try it now, but I'll try to switch out the searching in anything and proel to use ack instead of grep/find. Right now, the grep in proel excludes my VCS dirs, so that's not a huge problem, but it seems like ack might still be nicer.
Apr 21, 2009
Liwp said...
Emacs also supports find&grep out of the box. M-x lgrep will run grep on all the files in the local directory. M-x rgrep will run grep on all files in the current directory and all subdirectories. Both commands will ask interactively for the pattern to look for, the file pattern to use and the root directory. Very useful.
Apr 21, 2009
Ah, true that is useful out of the box. I just noticed, however, that most of the time I was running find or rgrep, I was navigating away from my current directory to my project directory and running it. Proel's grep is basically just a function that does this for me. This is of course not a hard function to write, but Proel seemed to come with a few other features, so I decided I might as well try it (I talk more about Proel in part 2 and 3 of this series). Similarly with find - I didn't want to keep navigating to the directory I wanted to run find in, and anything seemed to give me a way around this (in addition to giving me a bunch of other useful little things).

Leave a comment...

 
Got an account with one of these? Login here, or just enter your comment below.
Posterous-login    Connect    twitter