Emacs: Working with multiple source trees

As a developer, I often find myself working with multiple trees of source code. Sometimes, I’m comparing the trunk and the branches. Sometimes, I’m copying ideas from one place to another. Sometimes, I’m working on one project and an urgent defect comes in for a different project. With good development environments such as Eclipse, I’d still need to click on the project or directory in order to change my context, and then use a keyboard shortcut to find the resource in that tree.

With an awesome development environment like my customized Emacs, however, I can easily juggle multiple source trees. Here’s the macro I wrote to make setting this up much easier:

(defmacro sacha/file-cache-setup-tree (prefix shortcut directories)
  "Set up the file-cache tree for PREFIX using the keyboard SHORTCUT.
DIRECTORIES should be a list of directory names."
  `(let ((file-cache-alist nil)
	 (directories ,directories))
     (file-cache-clear-cache)
     (while directories
       (file-cache-add-directory-using-find (car directories))
       (setq directories (cdr directories)))
     (setq ,(intern (concat "sacha/file-cache-" prefix "-alist")) file-cache-alist)
     (defun ,(intern (concat "sacha/file-cache-ido-find-" prefix)) ()
       (interactive)
       (let ((file-cache-alist ,(intern (concat "sacha/file-cache-" prefix "-alist"))))
	 (call-interactively 'file-cache-ido-find-file)))
     (global-set-key (kbd ,shortcut)
		     (quote ,(intern (concat "sacha/file-cache-ido-find-" prefix))))))

With that, I can use the following to map C-c p to finding files in my personal directories:

(sacha/file-cache-setup-tree
 "personal"
 "C-c p"
 '("/var/www/html/drupal"
   "~/elisp"
   "~/personal"))

I’ve also set up keyboard shortcuts for the other trees I’m working on.

You’ll need file-cache, ido, and probably something like this:

(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)))
(add-to-list 'file-cache-filter-regexps "docs/html")
(add-to-list 'file-cache-filter-regexps "\\.svn-base$")
(add-to-list 'file-cache-filter-regexps "\\.dump$")

AutoHotkey scripts for switching to windows

Muscle memory helps you be more efficient. Here’s some AutoHotkey code I use to toggle Chrome (F10), Windows Live Writer (F11), or my Freemind mindmap for Life (F12). Make your own! =)

F10::
WinGetActiveTitle, Title
If Instr(Title, "Google Chrome") > 0
{
   WinMinimize, A
}
Else If WinExist("ahk_class Chrome_WindowImpl_0")
{
   WinActivate
   WinMaximize
}
Else 
{
   Run, "C:\Documents and Settings\Administrator\Local Settings\Application 

Data\Google\Chrome\Application\chrome.exe"
}
return
F11::
WinGetActiveTitle, Title
If Instr(Title, "Windows Live Writer") > 0
{
   WinMinimize, A
}
Else If WinExist("ahk_class WindowsForms10.Window.8.app.0.33c0d9d")
{
   WinActivate
   WinMaximize
}
Else 
{
   Run, "C:\Program Files\Windows Live\Writer\WindowsLiveWriter.exe"
}
return
F12::
WinGetActiveTitle, Title
If InStr(Title, "Life.mm") > 0
{
   WinMinimize, A
}
Else IfWinExist Life.mm
{
   WinActivate
   WinMaximize
}
Else 
{
   Run, c:\sacha\Life.mm"
}
return