Meta Redux: Projectile 3.1

Wait 5 sec.

Hot on the heels of Projectile 3.0comes Projectile 3.1!Three days apart, yes. There’s a story there. A big chunk of what’s in 3.1 wasoriginally meant for 3.0, but 3.0 was already turning into a monster of a releaseand I decided to cut it into two, so I’d actually be able to reason about each ofthem. So think of 3.1 less as “the next release” and more as “the second half of3.0 that I was too scared to ship all at once”.There was also a bit of calendar mischief involved. I really wanted a release onthe 1st of July - that’s July Morning, which is a bit of a thing here inBulgaria1 - and then another one on the 4th of July. Partly because it’s the250th US Independence Day, and partly because it happens to be my weddinganniversary. When else am I going to get a round number like that to line up? Sohere we are.Unlike 3.0, 3.1 has no breaking changes. Nothing was removed, no command oroption changed its name. What it does instead is knock out a pile oflong-standing ideas and feature requests, most of which pull in the samedirection: making Projectile leaner under the hood and a lot more extensible fromyour own config.Projectile learns what you actually work onprojectile-find-file now ranks the files you visit most often and most recentlyat the top of the completion list. It’s the kind of thing you don’t notice untilyou go back to a Projectile without it and suddenly your muscle memory is off.It works with any completion UI (Vertico, the default one, whatever) and underevery indexing method, and it’s on by default. If it’s not your thing, setprojectile-enable-frecency to nil.Named project tasksThe six lifecycle commands (compile, test, run, …) were never enough for realprojects, which tend to accumulate a dozen little “run this incantation”commands. So there’s projectile-tasks now - an arbitrary set of named commandsyou can attach to a project. The nice part is you can put them in.dir-locals.el and share them with your team through the repo:((nil . ((projectile-tasks . (("lint" . "make lint") ("deploy" . "make deploy STAGE=prod"))))))Then s-p c x (projectile-run-task) prompts you for a task and runs it, with aprefix argument if you want to tweak the command first. This one subsumes aboutfour separate feature requests I’d been staring at for years.Finding files by kindThis is my favourite one. Lots of frameworks organize files into well-knownkinds - Rails has models, controllers, views and helpers; Django has models,views and urls; and so on. Projectile can now describe those kindsdeclaratively, and it gives you two commands for free: s-p j to jump to a fileof a particular kind, and s-p J to hop between related files (from a model toits controller to its views and back).The best part is that it’s not hardcoded. Rails and Django ship out of the box,but the whole thing is driven by a :file-kinds entry on the project type, soyou can teach Projectile about your own framework’s layout in a few lines. Thisis the “more extensible” theme in a nutshell - I’d much rather ship a mechanismthan a hardcoded list.Running the test at pointIf you’re on Emacs 29+ with tree-sitter, s-p c . runs just the test your cursoris in, rather than the whole suite. It figures out the enclosing test from theparse tree and builds the right command. pytest, go test and jest are supportedout of the box, and - you guessed it - you can register rules for other testrunners yourself.Other-window and other-frame, the Emacs wayInstead of a small army of -other-window/-other-frame command variants, thereare now s-p 4 4 and s-p 5 5 prefixes, modeled exactly on Emacs’s ownC-x 4 4 / C-x 5 5. Press s-p 4 4 and the next Projectile command opens itsbuffer in another window - even commands that never had a dedicated variant. Theold commands still work, of course.More solid under the hoodA few things got quietly sturdier: File-notify cache updates. projectile-invalidate-cache has always beenProjectile’s most notorious footgun. If you opt intoprojectile-auto-update-cache-with-watches, Projectile watches your projectand keeps its file cache in sync as files come and go, so you rarely have tothink about invalidation at all. It’s off by default and deliberatelyconservative - when in doubt it just rebuilds. .projectile finally makes sense. The glob patterns in your dirconfig nowfollow .gitignore-style rules, and they behave identically under native andhybrid indexing. This kills a whole family of “why is this file showing up”bug reports that go back the better part of a decade. TRAMP got faster again. Project and project-type detection now probe markerfiles with a single directory listing instead of a stat per marker, which turnsdozens of sequential round-trips into one over TRAMP.Wrapping upThere are no breaking changes, but a handful of defaults and behaviors did shift(auto-discovery is on by default now, for one), so give theUpgrading to Projectile 3.1guide a quick read before you upgrade. The full list of changes lives in thechangelog, as always.With 3.1 out the door, Projectile is basically where I always wanted it to be.I’ve got a few ideas for follow-up releases, but the pressure is off - this isthe release where the big items I’d been carrying around for years finally gotdone. Another win for myburst-driven approachto maintaining my projects: nothing happens for a while, and then a whole lothappens at once.Keep hacking! July Morning is a Bulgarian tradition where people head to the Black Seacoast to greet the sunrise on the 1st of July. It started as a hippie /rock-and-roll thing in the 80s and stuck around. Highly recommended, if youever get the chance. ↩