I have been using Projectile for years, and it served me well. While Projectile is really useful, it is a third party package made of more than 8000 lines of code. Since the built-in Project module has received lots of improvements since Emacs 28.1, I decided to give it a try and see if I could remove Projectile from my Emacs setup.
Key binding
The Project keymap is bound to C-x p
by default, but I am used to C-c p
.
This is easy to change, for example with use-package
:
(use-package project
:bind-keymap
(("C-c p" . project-prefix-map)))
Switching between projects
By default, the project switching command uses a prompt letting you select a command to run for the selected project. If you always use the same command, you can configure it, allowing to switch project without any prompt.
For example, to always display the project directory with Dired:
(setq project-switch-commands 'project-dired)
Search using Helm and AG
The Projectile feature I used the most is incremental project search using
helm-projectile
and helm-ag
.
Adding this feature to Project is not that hard. Let us write the search function:
(defun g-project-search ()
(interactive)
(let ((project (project-current t)))
(helm-do-ag (project-root project))))
And bind it to C-c p s
(replacing project-shell
, a command I do not use):
(use-package project
:bind
(:map project-prefix-map
(("s" . 'g-project-search))))
One thing to be aware of: helm-ag
does not take patterns returned by
project-ignores
into consideration when filtering results. It is not that
much of a problem to me, since ag
already supports .gitignore
files
But it would be an improvement to use project-ignores
and pass the pattern
list to ag
.
In the mean time, I can also remove the helm-projectile
dependency.
Starting Eshell
While both Projectile and Project can run Eshell in the current project, I want the ability to start it the same way whether I am in a project or not. Therefore I have a small function looking for a current project and running Eshell the right way. Migrating to Project is easy:
(defun g-eshell ()
"Start eshell at the root of the current project, or in the
current directory if the current buffer is not part of a
project."
(interactive)
(if (project-current)
(project-eshell)
(eshell)))
I bind it to C-x s
(“s” being for “shell”):
(global-set-key (kbd "C-x s") 'g-eshell)
Conclusion
The result is quite satisfying. It may not do everything Projectile supports, but the features I use are all implemented. As a result, my Emacs setup is simpler and lighter, relying on one less external dependency.