Optimizing repetitive operations is one of my obsessions. I can’t
stand following long sequences of steps to make the computer do what I
want. The whole point of computers is to have them do more work for
As a developer with several ongoing projects, I frequently find myself
switching contexts as one project becomes blocked (read: I lose
interest) and I want to move on another. Typically that means unloading
a bunch of files from my editor and loading others. Some IDEs, and even
editors such as TextMate, use a “project” file to manage the files that
belong to a project. Some go so far as to use the project file as a hint
for how to build the library or application.
Using a project file typically involves pre-defining the members of a
project, and then managing the project file as another artifact of the
project itself. To switch contexts, you simply close one project file
and all of its related code files, then open another. A good editor will
even remember which files were open when the project was last in use,
and restore your workspace to the same state. A great editor will let
you automate the steps needed to switch contexts by loading different
I’ve been an emacs user for something like 10 years now. I use vi
frequently, and TextMate regularly as well, but most of the time I live
in emacs for text editing and development tasks. The implementation of
project files I use with emacs is desktop-mode. I like desktop-mode
because instead of forcing me to pre-declare all of the files in my
project, it assumes that all open buffers should be remembered. There
are alternatives (there are always alternatives in emacs, right?).
Setup of desktop-mode is straightforward:
- Run customize-group on the “desktop” group.
- Turn desktop-save-mode on to enable the minor mode.
3. Optionally change the base name for desktop files in
desktop-base-file-name. I like using “emacs.desktop” so the file is
not hidden and I know exactly what it contains.
4. Set a default search path for the desktop file in desktop-path.
I set my path to include ~/emacs, but this is only the default. We
will be saving a separate desktop in each virtualenv.
5. Set desktop-save to “Always save”. There are other values that
work, but some require interaction with the editor during the context
move to confirm file saves, and I want to avoid that.
There are a few other options that may be useful to tweak, depending
on the other features of emacs you use. For example, I set
desktop-clear-preserve-buffers so clearing the desktop does not delete
the *Messages*, *Org Agenda*, or *scratch* buffers since
those are related to emacs operation and not limited to any one project.
The next step is to set up the tool chain so emacs loads a new desktop
when you change virtualenvs from the command line.
In addition to making it simpler to manage multiple virtual
environments, virtualenvwrapper adds several hook points to
trigger changes outside of the virtual environment when various events
occur. For example, each time you run workon to change environments,
the predeactivate and postactivate hooks are run. The most
interesting of these for our purposes is the postactivate hook,
called right after the new environment is activated.
I usually add a cd command to the environment-specific postactivate
script (in $VIRTUAL_ENV/bin/postactivate) to move my shell session
to the working directory for that project and change the $PATH,
making it easier to run the tests for my project from the shell. For
In addition to the virtualenv-specific hook, there is also a global
postactivate script, and that’s the one I use to switch contexts in
emacs. Edit $WORKON_HOME/postactivate to add these lines:
# Change emacs' desktop directory
emacsclient -e "(desktop-change-dir "$VIRTUAL_ENV")" >/dev/null
The function desktop-change-dir tells emacs where to save the
desktop session file. By changing the directory each time we change
environments, we can have a separate desktop file in each environment.
Changing the directory automatically saves the old desktop first, of
course, so the old project status is preserved until you come back to
Now that the hook is configured, the next step is to initialize the
desktop for your projects. For each project, run workon to activate
it, then open several files from that project. As you workon the
next project, the session will be saved in
$VIRTUAL_ENV/emacs.desktop (assuming you set your
desktop-base-file-name to emacs.desktop). Once you have initialized a
few virtualenvs, switch back to the first. Emacs should load the desktop
file for that environment and restore the buffers you were editing.
The example above works for emacs, but other editors may need to use
the predeactivate hook to save a project file before loading the new
one from postactivate. There are global and local versions of both
hooks; refer to the virtualenvwrapper documentation for more details.