Delightful project.el features

Global ignore list

The computer science community has created so many languages, dialects, frameworks, build systems and tools – all with their own assumptions, nuances and gotchas – making the task of coming up with a decent solution to project management tedious for the developer writing said solution as well as the user who has to consider and remember all these arbitrary conventions.

.gitignore solves this to some degree, though it's up to the language, framework, etc. to bundle a sensible template so developers can focus on the important stuff. Going out of your way to create this file for every new project, which at times doesn't need to be source-controlled, is just cumbersome.

This is where project-vc-ignores comes into play, it takes a list of patterns and instructs the project.el library to ignore them, for example:

(setq project-vc-ignores '("target/" "bin/" "obj/"))

This ignores the target/ directory generated by mvn and the bin/ and obj/ directories of dotnet. The trailing slash is important, it denotes a directory (regardless of depth).

Root markers

Emacs 29 is said to be one of the most feature-packed releases to date, and it certainly holds true for this library. This version introduces the project-vc-extra-root-markers variable that takes a list of files or glob patterns signaling the root of a project, for example:

(setq project-vc-extra-root-markers '("pom.xml" "*.csproj"))

Directories that contain a pom.xml file or files ending with a csproj suffix will now be considered as projects, without needing to be source-controlled, and we'll still be able to use all the handy features of project.el.

If your project is made up of multiple subprojects and each one contains the same root marker, you should refrain from using the above markers and consider something more general, e.g. .prj (and it can be an empty file). If you don't do this, any actions you perform will be limited to the subproject you're currently in.

Custom switch commands

project-switch-commands is a variable that determines the list of options displayed to the user when switching to a project with C-x p p, we can extend it as follows:

(add-to-list 'project-switch-commands '(magit-project-status "Magit" ?m))

C-x p p m should now take us to the magit-status view of the project we just visited, which it normally doesn't do. Additionally, it's very easy to extend project.el to support a workflow involving a to-do file at the root of the project directory.

Fine-tuned compilation

project-compile uses compile-command internally, so if your build system is complex then you might consider configuring it using directory variables, for example:

# .dir-locals.el
((nil . ((compile-command . "make --directory=doc/site"))))

This will tell make to look for the Makefile in the doc/site directory (relative to the project root).

If you want to run a specific target, prefixing the project-compile keybinding with C-u will write the value of compile-command to the minibuffer and prompt you to write something more specific.

The manual suggests adding a trailing space, probably to minimize the amount of keystrokes you have to type before finally performing your build operation.

Carefully killing buffers

If you feel a little uneasy about blindly killing every project buffer without getting a chance to say goodbye then project-kill-buffers-display-buffer-list, introduced in Emacs 29, is just the thing for you.

It is however hardwired to use buffer-menu, so attempting to alias the functions that it calls internally – specifically list-buffers-no-select – to the much cooler ibuffer will… break everything.

Finally, I highly recommend reading the project.el manual, because the various features and tricks I've just mentioned are merely a fraction of what this library is able to do.