Emacs: favourite directories implementation
Today, I have finally taken a look at one of the simple features I always missed in Emacs: the ability to define a set of "favourite directories." That is, a set of named directories that one can use in the minibuffer when prompted for instance to open a file. Given a set of such dirs:
emacs-src -> /enter/your/path/to/emacs/sources projects -> /path/to/some/company/projects now -> @projects/the/project/I/am/working/on
one can use the following path in the minibuffer to open a file, for instance using C-x C-f:
@emacs-src/lisp/files.el @emacs-src/src/alloc.c @projects/great/README @now/src/some/stuff.txt
Doing so, completion is available for both directory names and files under their target directories. For instance, to open the third file above, you only have to type:
C-x C-f @ p <tab> g <tab> R <tab> <enter>
The implementation I have just written is really simple, but useful yet. It implements all described above (including recursive defined directories, as the '@now' above.) Thanks to Emacs, I am still suprised by the facility to implement such a feature!
The code was written on GNU Emacs 22.1 on Windows, but should work on any platform, and I think on Emacs 21 as well.
;; TODO: Make a custom variable. (defvar drkm-fav:favourite-directories-alist '(("saxon-src" . "y:/Saxon/saxon-resources9-0-0-1/source/net/sf/saxon") ("kernow-src" . "~/xslt/kernow/svn-2007-09-29/kernow/trunk/src/net/sf/kernow")) "See `drkm-fav:handler'.") (defvar drkm-fav::fav-dirs-re ;; TODO: Is tehre really no other way (than mapcar) to get the list ;; of the keys of an alist?!? (concat "^@" (regexp-opt (mapcar 'car drkm-fav:favourite-directories-alist) t)) "Internal variable that stores a regex computed from `drkm-fav:favourite-directories-alist'. WARNING: This is not updated automatically if the later variable is changed.") (defun drkm-fav:handler (primitive &rest args) "Magic handler for favourite directories. With this handler installed into `file-name-handler-alist', it is possible to use shortcuts for often used directories. It uses the mapping in the alist `drkm-fav:favourite-directories-alist'. Once installed, say you have the following alist in the mapping variable: ((\"dir-1\" . \"~/some/real/dir\") (\"dir-2\" . \"c:/other/dir/for/windows/users\")) You can now use \"@dir-1\" while opening a file with C-x C-f for instance, with completion for the abbreviation names themselves as well as for files under the target directory." (cond ;; expand-file-name ((and (eq primitive 'expand-file-name) (string-match drkm-fav::fav-dirs-re (car args))) (replace-match (cdr (assoc (match-string 1 (car args)) drkm-fav:favourite-directories-alist)) t t (car args))) ;; file-name-completion ((and (eq primitive 'file-name-completion) (string-match "^@\\([^/]*\\)$" (car args))) (let ((compl (try-completion (match-string 1 (car args)) drkm-fav:favourite-directories-alist))) (cond ((eq t compl) (concat "@" (match-string 1 (car args)) "/")) ((not compl) nil) (t (concat "@" compl))))) ;; file-name-all-completions ((and (eq primitive 'file-name-all-completions) (string-match "^@\\([^/]*\\)$" (car args))) (all-completions (match-string 1 (car args)) drkm-fav:favourite-directories-alist)) ;; Handle any primitive we don't know about (from the info node ;; (info "(elisp)Magic File Names")). (t (let ((inhibit-file-name-handlers (cons 'drkm-fav:handler (and (eq inhibit-file-name-operation primitive) inhibit-file-name-handlers))) (inhibit-file-name-operation primitive)) (apply primitive args))))) ;; Actually plug the feature into Emacs. (push '("\\`@" . drkm-fav:handler) file-name-handler-alist)