In his article What’s new in Emacs
27.1? Mickey
Petersen wrote that the built-in project.el
1 is a library “not widely used”
and “about 20 years too late”, concluding that it is “a missed opportunity”.
From what I can tell project.el
has been around since 2015. As everything else
in our Emacs world, it’s an effort from volunteers offered back to the
community. I see no reason to avoid it because it has been lacking the attention
of other well-known alternatives such as Projectile. On the contrary, I believe
that the more users try it and report what is missing back to the developers or
perhaps contribute with lines of code, the more chances this tiny library has to
grow and to get better.
Instead of replacing helm-ls-git
with project.el
, I decided to leave Helm
aside for a moment and try my luck with Icomplete. I trust Protesilaos
Stavrou’s opinion on it, anyway, so that’s another
good point to give it a shot. If you want a detailed setup for Icomplete be sure
to follow his lead. I limited myself to installing
icomplete-vertical and
orderless to make my life easier.
The entry point in project.el
is the prefix C-x p
. You can hit C-h
after that to
see the available key bindings. If you press C-x p p
a list of known projects
will appear. You will see that an option to select a new project is always
available, so it’s trivial to add new elements here.
Once you land on your candidate hit RET to be presented with a customizable list of commands to act on the selected project. The keys to activate the commands are highlighted so, for instance, you can press f to start exploring your project files.
The defaults key bindings provided by project.el
suit me well enough, but I did
apply some changes to tune its behaviour to my needs.
First, I don’t want to rely on find
for project--files-in-directory
when the
faster fd is around the corner.
(el-patch-defun project--files-in-directory (dir ignores &optional files)
(el-patch-remove
(require 'find-dired)
(require 'xref)
(defvar find-name-arg))
(let* ((default-directory dir)
;; Make sure ~/ etc. in local directory name is
;; expanded and not left for the shell command
;; to interpret.
(localdir (file-local-name (expand-file-name dir)))
(command (el-patch-swap
(format "%s %s %s -type f %s -print0"
find-program
localdir
(xref--find-ignores-arguments ignores localdir)
(if files
(concat (shell-quote-argument "(")
" " find-name-arg " "
(mapconcat
#'shell-quote-argument
(split-string files)
(concat " -o " find-name-arg " "))
" "
(shell-quote-argument ")"))
""))
(format "fd -t f -0 . %s" localdir))))
(project--remote-file-names
(sort (split-string (shell-command-to-string command) "\0" t)
#'string<))))
Then I had to tweak project-kill-buffer-conditions
for buffers in
cider-repl-mode
to ensure project-kill-buffers
catches them.
(add-to-list 'project-kill-buffer-conditions '(major-mode . cider-repl-mode) t)
The last customization was adding quick keys for magit-status
, project-shell
,
and ripgrep
to project-switch-commands
. You don’t need my Elisp for that.
As little and work-in-progress as it is, project.el
already covers everything
I usually need to handle my projects. It’s good to know that right within our
beloved text editor comes a tool like this. And no, Pat Benatar, this time is
not too little too late.