Jake McCrary

Emacs: Generating project shortcuts

I’m now writing Clojure nearly 100% of my time and as a result am spending more time in Emacs. I’m working in a few different projects and wanted a quicker way to jump between them. My first attempt at this ended with me defining many functions that looked like the following.

1
2
3
(defun b/test-refresh ()
  (interactive)
  (find-file "~/src/jakemcc/lein-test-refresh/test-refresh/project.clj"))

After writing a couple of these I decided the computer could do this better than I could and decided to write some code to automate it. A sample of my directory structure is shown below.

1
2
3
4
5
jakemcc/
├── bookrobot
│   └── project.clj
└── lein-autoexpect
    └── project.clj

Taking advantage of this structure I wrote some Emacs lisp to walk a directory and define functions that open up any found project.clj files.

1
2
3
4
5
6
7
8
9
10
11
12
;; -*- lexical-binding: t -*-

(defun open-file-fn (file)
  (lambda ()
    (interactive)
    (find-file file)))

(defun create-project-shortcuts (prefix base)
  (dolist (elt (directory-files base))
    (let ((project (concat base "/" elt "/project.clj")))
      (when (file-exists-p project)
        (fset (intern (concat prefix elt)) (open-file-fn project))))))

open-file-fn creates an anonymous interactive function (meaning the function can be called interactively) that opens file. It takes advantage of the feature in Emacs 24 that enables lexical scoping by adding ;; -*- lexical-binding: t -*- to the top of your Emacs lisp file. This lets the anonymous function capture file.

create-project-shortcuts takes in a prefix and a base directory. It searches base for directories that contain a project.clj file. For each found project.clj file a function is created (using fset) with the name of the containing directory prefixed by prefix.

With those two functions defined all that is left is to call create-project-shortcuts.

1
(create-project-shortcuts "b/" "~/src/jakemcc")

Now b/bookrobot and b/lein-autoexpect are available after hitting M-x.

I’ve used this code to create quick shortcuts to all of my work and non-work projects. It has been immensely useful for jumping around projects.

Comments