Changelog
August 25, 2026 · View on GitHub
master (unreleased)
New features
- #2160: Add
projectile-find-file-in-sibling-projects(s-p n f) andprojectile-search-in-sibling-projects(s-p n s), which work across the family of related projects rather than just the one you're in.- Both are built on
projectile-find-file-in-projectsandprojectile-search-in-projects, which take any list of projects, so a command for a group of your own is a two-line wrapper. - A group search puts every match in one
*projectile-search*buffer, named relative to the directory containing the group, so each one is labelled with the project it came from.
- Both are built on
- #2165: A subproject now has its own project type, so the
s-p c mlifecycle commands build a monorepo member with the member's own toolchain - a Rust crate or Go module under a JavaScript repository runscargo testorgo testrather than the repository'snpm test. Newprojectile-subproject-type.- A member identified by the same manifest as the repository keeps the repository's type: a pnpm or yarn workspace member holds only a
package.jsonand would otherwise fall back to plainnpm.
- A member identified by the same manifest as the repository keeps the repository's type: a pnpm or yarn workspace member holds only a
- #2166: Subprojects now come from the workspace's own member list when the repository declares one - pnpm, npm/yarn/bun, Cargo and
go.work- instead of from scanning for manifests, so test fixtures and excluded crates stop showing up as subprojects. Babel's repository goes from 205 to its declared 162. Newprojectile-subproject-functions.- Build tools that compute their members rather than declaring them (Gradle, Bazel) keep using the scan, which is why it remains the fallback.
- #2163: Add
projectile-switch-to-buffer-in-sibling-projects(s-p n b),projectile-multi-occur-in-sibling-projects(s-p n o) andprojectile-todos-in-sibling-projects(s-p n t), so buffers and annotations follow the same family as files and searches.projectile-switch-to-buffer-in-projectsjoins the two existing generic commands, andprojectile-todosnow shares one implementation with its group form.
Changes
- #2160:
projectile-switch-sibling-projectmoved froms-p ntos-p n p.s-p nis now the prefix for every command that works across related projects, with each key mirroring the project-wide one a level down, the wayc mdoes for subprojects. - #2168: Search results are redrawn at most every
projectile-search-render-intervalwhile streaming, instead of on every chunk. The buffer is redrawn from scratch, so drawing per chunk cost roughly chunks times matches - two thirds of a sibling-group search went on redrawing. A search across 18 projects drops from 0.32s to 0.18s, and across 122 from 4.8s to 2.8s. - #2164: A search across several projects now uses ripgrep, one run per project, instead of falling back to the Emacs Lisp scanner. The candidate file list is also only computed when something is going to scan it, so the ripgrep path no longer pays for a directory walk it never reads.
Bugs fixed
- #2172: Fix subproject detection in a Go workspace. A
go.worknames its modules as./api, and the leading./survived into the subproject name, which then matched none of the project's file paths - soprojectile-find-file-in-subprojectoffered nothing at all in a Go monorepo. Members are now spelled relative to the project root whatever the manifest wrote. - #2171: The commands that list the known projects now load the persisted list first. They read the
projectile-known-projectsvariable, which stays nil until the same-named accessor loads it from disk and which nothing loads at startup - so whichever of them you reached for first in a session offered nothing.projectile-find-file-in-known-projectscompleted over an empty list;projectile-vc,projectile-remove-known-projectand the "Switch to project" prompt ofprojectile-require-project-rootwere affected too. - #2170: Navigating a search results buffer while the scan is still running is no longer undone by the next chunk. Each redraw ended by going to the top of the buffer, so point jumped back on every batch of matches; it now stays where you left it.
- #2167: The Emacs Lisp search scanner no longer decompresses or decrypts the files it reads. It went through
file-name-handler-alist, so every archive in the candidate set was run through gzip and every.gpghanded to EPA - work discarded a moment later as binary, and on an encrypted file a passphrase prompt in the middle of a project search.- Matches inside compressed files are no longer reported by that scanner, which is what the ripgrep path already did.
- #2162: Listing another project's files now applies that project's own ignore rules instead of the rules of whichever project you happen to be visiting.
projectile-find-file-in-known-projectsand the sibling commands used to filter every other project by the current one's dirconfig, and with caching on they stored that wrong list under the other project's key - so an ordinaryprojectile-find-filethere kept offering ignored files, and with persistent caching it survived a restart. - #2161: Customizing
projectile-mode-line-prefixnow reaches buffers whose lighter is never recomputed - every buffer whenprojectile-dynamic-mode-lineis off, which is the case its docstring describes, and remote ones always. The prefix used to be frozen at whatever it was when Projectile loaded. - #2157:
projectile-use-comint-modenow covers the named tasks run byprojectile-run-task, which were always given a read-only compilation buffer however it was set - so a task that needs to ask for a sudo password had nowhere to type one (#2156). Nametaskin the list, or set the option tot.
3.4.0 (2026-08-10)
New features
- #2148: Add
projectile-switch-sibling-project(s-p n), which offers only the projects related to the one you're in, rather than every project on the machine.- Relatedness comes from
projectile-project-groupsif you've configured it, then from the owner of the upstream remote, then from the leading word of the directory name - seeprojectile-sibling-project-functions. - The remote's owner is what relates projects whose names have nothing in common; an inferred group covering more than
projectile-sibling-max-group-shareof your projects is dropped, since "we're all under the same account" relates nothing.
- Relatedness comes from
- #2151:
projectile-switch-worktreealso offers Jujutsu workspaces, and a jj repository is now identified through its git backing store, so a workspace and the colocated git checkout agree on being the same thing and jj projects get siblings like any other. - #2147: Add
projectile-switch-worktree(s-p W), which offers the other checkouts of the current project's repository, each annotated with whatever tells it apart - the branch for git and Mercurial, the workspace name for Jujutsu.- Git worktrees and separate clones of the same upstream both count as checkouts, since they're the same workflow with and without the plumbing;
projectile-worktree-functionsis where other ways of finding them plug in.
- Git worktrees and separate clones of the same upstream both count as checkouts, since they're the same workflow with and without the plumbing;
- #2138: Better support for OCaml, Erlang and F#.
projectile-run-test-at-pointlearnserlang-ts-mode(EUnit's_test/_test_functions, run asrebar3 eunit --test=module:name) andfsharp-ts-mode(bindings attributed[<Fact>],[<Theory>],[<Test>],[<TestCase>]or[<Property>], run throughdotnet test --filter).- The
ocaml-duneandrebarproject types gained their run, install, package and source/test directory attributes, and a newerlang-mktype covers the other common Erlang build tool. - OCaml deliberately gets no test-at-point rule: its tests are ordinary values registered with Alcotest or OUnit rather than anything the syntax marks out, so there is nothing to recognize.
- #2137: Ship
:file-kindstables for Phoenix, Laravel and Next.js, soprojectile-find-file-of-kind(s-p j) andprojectile-toggle-related-file(s-p J) work in those out of the box - Rails and Django were the only frameworks covered before.- Phoenix keys a resource's modules on the name they share (
user_controller.ex,user_html.ex,user_live.ex), Laravel on the model's class name, Next.js on the app router's directory. - Adds a
nextjsproject type (next.config.jsand friends) to hang the last of those on.
- Phoenix keys a resource's modules on the name they share (
- #2136:
projectile-run-test-at-pointnow knows Ruby (RSpec and Minitest), Rust, Elixir and Java, on top of the Python, Go and JS/TS rules it shipped with.- Ruby is written the same way whichever framework you use, so the project type picks the runner; Java's picks between Maven and Gradle, and takes the class name from the file.
- ExUnit can't select a test by name from the command line, so Elixir tests are addressed as
FILE:LINE.
- #2135: Add
projectile-ignored-project-patterns, the regexp-matching sibling ofprojectile-ignored-projects(exact paths) andprojectile-ignored-project-function(a predicate), so keeping whole areas of a machine out of the known projects doesn't need a lambda. - #2134: Add
projectile-find-changed-file(s-p C), which completes over the files git reports as staged, unstaged or untracked - or, with a prefix argument, over everything that differs from a revision you pick. - #2133:
projectile-doctorfindings you can act on now carry a button that does it -[enable]for a disabledprojectile-mode,[enable caching]on a large uncached project,[open dirconfig]for a.projectilewith prefix-less lines,[edit .dir-locals.el]for an undetected project type. Pressing one regenerates the report, so the finding answers for itself; findings Projectile can't act on stay plain advice. - #2132: The dashboard gained a "Notable files" section linking the project's README, changelog, license, its type's own manifest and its
.projectile(seeprojectile-dashboard-link-files), plus a count of its open buffers and a summary of the ignore rules in effect.- A project with nothing cached now offers an
[index now]button instead of only reporting that it isn't indexed. - Both report buffers set up
outline-minor-modeover their sections, so a long report folds with the usual outline keys, and their footers derive the keys they advertise withsubstitute-command-keysrather than hardcoding them.
- A project with nothing cached now offers an
- #2131: The
projectile-doctorandprojectile-dashboardbuffers are no longer plain text: section headers, field labels, the project's identity and the doctor's findings are faced by meaning, with the findings colored by severity and sorted so anything wanting action comes first.- All the new faces only inherit from standard ones, so themes style them without knowing about Projectile and a terminal without colors degrades to what you got before.
projectile-report-copy(win either buffer) copies the buffer as plain text, without the faces and buttons - a doctor report usually ends up in an issue.
- #2130:
projectile-run-tasknow also discovers rake tasks, read out of the project'sRakefileand its.rakefiles (inrakelib,tasksandlib/tasks) rather than by runningrake -T, which would load the whole application. Tasks are qualified with theirnamespace(rake:db:migrate) and run throughbundle execwhen the project has aGemfile.
Changes
- #2152: The per-command-type histories now belong to the repository rather than the directory, so pressing
M-pat a compile or test prompt in a fresh git worktree - or in a second clone of the same upstream - offers the commands the project is actually built with instead of nothing (#1786).- What a prompt is pre-filled with, and what
projectile-repeat-last-commandreplays, stay local to the checkout you're in: both act without asking, and a remembered command can carry absolute paths back into the checkout it was typed in. - Existing histories are adopted rather than dropped, and
projectile-command-history-scopeset toprojectrestores a history per directory.
- What a prompt is pre-filled with, and what
- #2146: The six
projectile-<cmd>-use-comint-modeoptions fold into oneprojectile-use-comint-mode, takingtor a list of the phases to make interactive. - #2146:
projectile-per-project-compilation-bufferandprojectile-per-command-compilation-bufferfold intoprojectile-compilation-buffer-scope, a list ofprojectand/orcommand- which is what setting both booleans already meant. - #2146: Rename the options that broke their own naming schemes:
projectile-global-ignore-file-patternstoprojectile-globally-ignored-file-regexps,projectile-cmd-hist-ignoredupstoprojectile-command-history-ignore-duplicates,projectile-related-files-fn-functiontoprojectile-related-files-function,projectile-auto-discovertoprojectile-auto-discover-projects, and the three reviewable-search options named after replace (projectile-replace-max-matches,-asyncand-scan-chunk-size) to theprojectile-search-prefix their siblings already used. - #2146:
projectile-tags-file-nameandprojectile-go-project-test-functionare obsolete; both were only ever read as Projectile loaded, so setting them from your init file afterwards did nothing. List the tags file inprojectile-globally-ignored-files, and re-register thegoproject type to change how it's detected. - #2146: Every renamed or folded option is still honored under its old name, so existing configuration keeps working.
- #2146: Make the options' Customize metadata uniform - seven options that document
nilas meaningful had a:typethat rejected it, so Customize refused to edit them, and the:safepredicates now cover all the ignore lists rather than four of the nine.
Bugs fixed
- #2145: The known projects file, the frecency store and the session directory are resolved with
locate-user-emacs-filerather than expanded againstuser-emacs-directoryby hand, so they land beside the rest of your Emacs state when your configuration lives in~/.config/emacsinstead of~/.emacs.d. Nothing moves for a configuration in the usual place. - #2144: Internal: the two shapes a project type marker can take are decoded in one place now, rather than by each of the four consumers separately.
- #2142: Project types can declare
:src-extensionand:test-extension, for the languages whose tests don't carry the same extension as their sources. The bundledelixirtype sets them, so toggling fromlib/foo.exnow offers to createtest/foo_test.exs- a script ExUnit will actually run - rather thantest/foo_test.ex. - #2141: The messages Projectile emits without being asked are now prefixed with
[Projectile], so it's clear where they came from; the ones that answer a command you just invoked stay unprefixed. Five different conventions across the file (aProjectile:prefix, a bareProjectileone, the project name in brackets, plain passthrough, and no prefix at all) become one rule.- The indexing notice follows the manual's
Operating.../Operating...doneidiom, so a long index no longer leaves the echo area claiming to still be working. projectile-project-inforeadsProject: /path/ (npm, git)rather than separating its three fields with##.
- The indexing notice follows the manual's
- #2140:
projectile-verbosenow covers five more messages Projectile emitted without being asked: caching a file thefind-filehook picked up, a search path entry that doesn't exist, an indexing command that exited non-zero but produced usable output (both the sync and async runners), and a session file from an older format version. Commands you invoke still report what they did whatever the option is set to, and the two that are also commands (projectile-cache-current-file,projectile-discover-projects-in-directory) still speak when invoked directly. - #2139: The file-notification cache updates now honor the VCS's ignore rules too, so a watched project no longer gains files a re-index would never have listed - the last place
.gitignorewas going unread, after #2126 fixed it for files opened by hand. Onegit check-ignorecovers a whole batch of events, since a batch can be an entire directory moved into the project. - #2146: The default
projectile-globally-ignored-buffersentries are matched as regexps, so*scratch*only matched by accident and*scratchhh*matched too; the asterisks are now escaped. - #2146:
projectile-svn-commandfiltered directories out ofsvn list -Rwithgrep -v '$/', where the$is a literal rather than an anchor, so it never dropped anything and svn projects listed their directories among their files.
3.3.0 (2026-07-27)
New features
- #1867: Add
projectile-per-command-compilation-buffer, so compiling, testing and running a project no longer overwrite each other's output (*compilation*<test>). - #2121: Recognize the subprojects of a monorepo:
projectile-find-file-in-subproject(s-p c m f) scopes file completion to one part of the repository,projectile-project-subprojectslists them, and the subproject lifecycle commands now work in any project rather than only where the module's manifest matches the project's own type (projectile-subproject-markers). - #2120:
projectile-run-tasknow also offers the tasks a project's own tooling defines - npm scripts, Deno tasks, Composer scripts, just recipes, go-task tasks and Make targets - named after the tool that defines them (npm:build) and switched off withprojectile-discover-tasks. - #2119: Add 34 project types that used to come out as generic projects:
node(apackage.jsonwith no lock file),bun,deno,nx,turborepo,python-uv,python-pdm,php-composer,php-laravel,xcode,flutter,terraform,pulumi,helm,ansible,docker-compose,just,mise,buck2,pants,gleam,babashka,scala-cli,dub,fpm,alire,foundry,godot,platformio,hugo,jekyll,zola,mkdocsandquarto. - #2119: A project type marker can now be an
(:any "file1" "file2")clause, so a build file with several spellings no longer needs a predicate function. - #2115: Add
projectile-replace-undo(s-p u), which reverts the last replace applied from the reviewable replace buffer, leaving alone any file whose replaced text has changed since. - #2114: Add project-scoped bookmarks -
projectile-bookmark-set(s-p B s),projectile-bookmark-jump(s-p B j) andprojectile-bookmark-delete(s-p B d) - which are plain Emacs bookmarks with the completion scoped to the current project (seeprojectile-bookmark-scope). - #2113: Add
projectile-todos(s-p s t), which collects the project'sTODO/FIXME-style annotations (projectile-todo-keywords) into the reviewable search buffer. - #2112: Add
projectile-dashboard(s-p P), a buffer summarising the current project - name, root, type, file count, branch and working tree status, most-visited files, tasks and lifecycle commands, each of them a button - which also works as aprojectile-switch-project-action. - #2111: Add
projectile-doctor(s-p H), which reports how Projectile sees the current project - root, type, indexing method and command, available tools, cache state and effective ignore rules - and ends with a list of concrete suggestions. - #2104: Alien indexing now honors Projectile's ignore rules, which it previously skipped entirely, by pushing them into the external tool.
- Alien projects will list fewer files than before; set
projectile-alien-honors-ignoresto nil for the old behavior. - Tools that can't express exclusions (svn, fossil, bzr, darcs, pijul, plain
find) are filtered in Emacs Lisp instead, and dirconfig+keep entries stayhybrid/nativeonly.
- Alien projects will list fewer files than before; set
- #2096: Add an optional Embark/Marginalia integration, wired via
with-eval-after-loadso neither package becomes a dependency.
Changes
- #2123: Every lifecycle command now has a subproject variant -
projectile-configure-subproject,-install-and-package-join compile, test and run (s-p c m o,s-p c m i,s-p c m p) - and they all say which subproject they'll run in at the prompt. - #2123: Fix the subproject commands discarding the project type's compilation directory, which had a Meson monorepo building in
sub/instead ofsub/build/;projectile-compilation-dirnow takes the subproject as an optional base directory. - #2122:
projectile-globally-ignored-directoriesnow also covers the dependency and build output directories of the common ecosystems -node_modules,target,_build,__pycache__,.venv,.next,.terraformand a couple of dozen more.- Names that projects do sometimes commit (
vendor,dist,public,build) are deliberately left out, andprojectile-globally-unignored-directoriestakes any of the others back.
- Names that projects do sometimes commit (
- #2121:
go.modis now the Go type's project file, so it can anchor the root of a Go project outside version control and mark a module inside a larger repository. - #2119: Bring the stale build tool markers up to date: Bazel now matches on
MODULE.bazel, Gradle on the Kotlin DSL and on a settings file alone, Zig onbuild.zig, and go-task on all fourTaskfilespellings. - #2119: Modernize the lifecycle commands that no longer work: Symfony's console moved to
bin/and its server out of the framework, the Dart CLI subsumedpub,setup.py buildis deprecated by the PyPA, and poetry projects run pytest. - #2119: Rails and Django had their development server wired to the compile command, leaving the run command empty; the server is now the run command.
- #2119: The PHP types are now registered after the JavaScript ones, so a PHP application isn't detected as a Node project because of the
package.jsonits asset pipeline ships. - #2119: The supported project types table in the manual is now generated from the registry, which had drifted well behind it.
- #2114: In
projectile-dispatch, "display buffer" moved fromBtoC-o(mirroring itss-p 4 C-obinding), soBcould become the bookmark prefix. - #2110: The grep/ag search integration and the ignore predicates now derive their exclusions from the same gitignore patterns indexing uses, so they answer exactly what indexing would.
projectile-ignored-file-pandprojectile-ignored-directory-ptake an optional project root instead of a pre-computed list of ignored paths.- Removed
projectile-ignored-files,projectile-ignored-directories, their-relvariants,projectile-project-ignored,projectile-project-ignored-files,projectile-project-ignored-directories,projectile-paths-to-ignoreandprojectile-patterns-to-ignore, which existed only to build those absolute path lists.
- #2109:
alienindexing now honors dirconfig+keep entries, which it previously ignored without saying so. - #2109: Fix indexing failing outright when a dirconfig had
+keep entries and the indexing command was a shell pipeline (the plainfindfallback, svn, fossil, pijul). - #2107: Projectile's ignore configuration now speaks gitignore patterns everywhere, matched the same way by every indexing method: a slashless pattern matches at any depth, a pattern with a slash is anchored at the project root, a trailing
/means directory-only, and*,**,?and[...]are wildcards.- The
*prefix inprojectile-globally-ignored-directoriesis no longer a marker meaning "at any depth" (that's now the default) - it's a plain wildcard, so*node_modulesshould becomenode_modules. - A bare entry is no longer top-level-only under
hybrid; write/tmpif you meant only the project root. - Dirconfig
!ensure entries now apply underalientoo, andprojectile-global-ignore-file-patternsstays Emacs regexps and thereforenative-only.
- The
- #2104: Ignore matching is now case-sensitive under every indexing method, where
nativeandhybridpreviously folded case (so.elcalso hidBUILD.ELC). - #2104: Drop
.ensime_cacheand.eunitfrom the defaultprojectile-globally-ignored-directories, as ENSIME was archived in 2018 and.eunitis a rebar2 artifact. - #2104: Remove
projectile-warn-when-dirconfig-is-ignored, which existed only to warn thatalienbypassed the dirconfig. - #2099: Drop the standalone package headers (
Version,Package-Requires) fromprojectile-consult.el, since the phantomPackage-Requiresmade build tooling treat an in-package module as its own package.
Bugs fixed
- #1927: A known projects file Projectile can't read is now moved aside with a
.corruptsuffix and reported, instead of being read as an empty list - which made it look like another Emacs had removed every project, so the merge dropped the session's projects too and overwrote the file. Projectile also strips text properties when saving, since a propertized string whose properties don't read back is how the file gets corrupted in the first place. - #2118: Fix
projectile-find-fileshowing "Projectile is indexing" forever withprojectile-async-indexingenabled: Projectile waited for the indexing process's sentinel, which Emacs doesn't guarantee to run while a command sits waiting on the process, and now collects the finished command's output itself instead (projectile-async-index-sentinel-timeout). - #2097: Fix
projectile-compile-projectandprojectile-test-projectforgetting a command you edited at the prompt in a CMake project, where a command the project type registers as a function was never cached - the function's own answer still isn't, so a preset picker keeps prompting. - #1075: Opening a file the VCS ignores no longer adds it to the file cache under
alien/hybridindexing, so a compiled artifact you happen to visit stops turning up inprojectile-find-file. - #2119: Fix the
angularproject type never matching anything: its two markers were ANDed, but a project has eitherangular.json(Angular 6+) or.angular-cli.json, never both. - #2119: Fix the Python project types shadowing each other -
pyproject.tomlwas checked beforedjango,python-poetry,python-pipenvandpython-tox, and since nearly every Python project has one, those four never matched. - #2119: Fix
php-symfonynot matching a modern Symfony project: it required anappdirectory, gone since Symfony 3, and avendordirectory, which only exists after someone has run composer.
3.2.1 (2026-07-13)
Bugs fixed
- #2116: Fix alien/hybrid indexing being broken on Windows: the asynchronous indexer no longer hardcodes
/bin/sh(whichmake-processcan't spawn on Windows), locatingshviaexec-paththere and falling back to the synchronous runner when no POSIX shell is available. - #2094: Fix a
wrong-type-argument stringpcrash when runningprojectile-search(a 3.2.0 regression): the search-prompt tool tag now accepts the backend name symbol, not just a string.
3.2.0 (2026-07-12)
New features
- #2072: Add reviewable read-only search commands, a search-only sibling of the reviewable replace UI.
projectile-search-review(s R) searches for a literal string;projectile-search-regexp-review(s X) searches for an Emacs regexp, honoring full Emacs regexp syntax.- Matches are gathered into a read-only
*projectile-search*buffer, grouped by file, oneLINE:COL: CONTEXTline per match with the matched span highlighted; there is no preview, no per-match toggle and no apply. - The buffer reuses the replace reviewer's navigation, case/regexp toggles (
c/x), line and file filters (k/d/K/D), re-search (g) and grep-mode export (e). rbridges the current search to the replace reviewer, carrying over the term, literal-ness and case setting and prompting only for the replacement.- A literal
projectile-search-reviewaccelerates its scan with ripgrep whenrgis installed, streaming matches in near-instantly on large projects.- Controlled by
projectile-search-use-ripgrep(default on); set it to nil to always use the pure-elisp scan. - The ripgrep fast-path follows ripgrep's ignore rules plus Projectile's ignore globs, which can differ slightly from the elisp path's file set (e.g. hidden files, symlinks); regexp search and the whole replace reviewer always use the portable elisp scan.
- Controlled by
- The commands are available from
projectile-dispatchand the Projectile menu.
- #1924: Add reviewable project-wide replace commands that let you preview matches and choose which to apply, instead of the blocking, file-by-file
query-replacewalk ofprojectile-replace.projectile-replace-review(R) does a literal replace;projectile-replace-regexp-reviewdoes an Emacs-regexp replace whose replacement can reference capture groups.- Matches are gathered in Emacs Lisp, so the regexp command honors full Emacs regexp syntax and the preview reflects exactly what will be edited, including unsaved changes in open buffers.
- The
*projectile-replace*results buffer shows a per-file, per-match preview where each match can be toggled on or off;!(orC-c C-c) applies just the enabled ones, in any order. - Applying edits each file from the bottom up, edits open buffers in place under a single undo step, writes closed files back preserving their coding system, and skips buffers modified since the search rather than corrupting them.
- The results buffer can reshape the search in place, each action re-scanning and re-rendering the previews:
ctoggles case sensitivity (seeded fromcase-fold-search).xtoggles between literal and Emacs-regexp matching, refusing an invalid regexp rather than erroring.k/dkeep or flush the matches whose line matches a regexp;K/Ddo the same by file name; re-searching withgrestores anything filtered away.
- A status line at the top shows the term, replacement, match and file counts, the mode flags, and a note when the list has been filtered.
eexports the shown matches to agrep-modebuffer so wgrep or Emacs 31'sgrep-edit-modecan turn them editable and write back; wgrep stays an optional integration and!remains the no-dependency apply path.- Both reviewers scan the project asynchronously, so a large search no longer freezes Emacs.
- The results buffer opens right away, matches stream in as they're found (the header shows a "Searching..." progress note), and the scan is cancelable with
q,C-g, or by killing the buffer. - While a scan is still running,
!(apply),e(export) and the filter keys (k/d/K/D) refuse until it finishes, so the write-back never runs against a partial match set and a filter can't be outrun by a later chunk; starting a new scan (g/c/x) cancels any in-flight one. - Set
projectile-replace-asyncto nil to force the old synchronous single-pass scan; batch runs always scan synchronously.
- The results buffer opens right away, matches stream in as they're found (the header shows a "Searching..." progress note), and the scan is cancelable with
- The commands are available from
projectile-dispatchand the Projectile menu, and the match cap is customizable viaprojectile-replace-max-matches.
- #2065: Add
projectile-session-mode, a global minor mode that gives each project its owntab-bartab.- Switching to a project selects its existing tab (restoring that project's window layout) when one is open, or otherwise opens a fresh tab named after the project and populated via
projectile-session-default-action. - Same-named checkouts get distinct tab names (e.g.
work/fooandhome/foo); customize the scheme withprojectile-session-tab-name-function. projectile-session-switch-to-buffercompletes over just the current tab's project buffers.- Sessions persist across Emacs restarts:
projectile-session-save,projectile-session-restoreandprojectile-session-forgetwrite a project's window layout and buffers to a file underprojectile-session-directoryand read it back;projectile-session-save-allsaves every open project at once. - Switching to a project with a saved session restores it (gated by
projectile-session-restore-on-switch);projectile-session-autosavesaves sessions on switch-away and on exit. projectile-session-restore-allreopens every saved project's session, each into its own tab (skipping projects already open and dropping stale sessions whose files are gone); setprojectile-session-restore-on-startupto run it automatically at Emacs startup.- Which buffers are recorded, and how, is extensible via
projectile-session-buffer-serializers; file-visiting anddired-modebuffers work out of the box. - The session commands are bound under the
wsub-prefix of the command map (s-p w s,s-p w S,s-p w r,s-p w R,s-p w f,s-p w b), and are also available fromprojectile-dispatchand the Projectile menu.
- Switching to a project selects its existing tab (restoring that project's window layout) when one is open, or otherwise opens a fresh tab named after the project and populated via
Changes
- #2082: Add
projectile-frecency-max-projects(default 100), which caps how many projects' frecency history is kept so the store can't grow without bound. - #2082:
projectile-replace-scan-chunk-sizeis now a user-facingdefcustom(was an internal variable). - #2093: Advertise the right completion metadata category per command so marginalia and embark annotate and act on candidates correctly: buffer switching now uses the
buffercategory (so marginalia shows its rich buffer annotations), project switching usesfile, and file commands keepproject-file- previously every completion was hardcoded toproject-file.projectile-completing-readgained a:categorykeyword for this. - #2092: Add whole-word matching to the reviewable search/replace: toggle it with
win the results buffer, default it withprojectile-search-whole-word, or seed it for one run with theprojectile-dispatch--wordswitch. The elisp scan fences the pattern with word boundaries and the ripgrep fast-path passes--word-regexp, so both engines agree. - #2091: Wire the reviewable search/replace into the
projectile-dispatchModifiers: the two literal/regexp search entries are folded into onesRdriven by--regexp(matching how--regexpalready drives the ag/ripgrep search), and a new--case-sensitiveswitch seeds the reviewable search/replace case-sensitive. Both can still be flipped withx/cin the results buffer. - #2090: Highlight the search tool and the default value in the search prompts, and give them one consistent
Search [tool] for (default: X)format acrossprojectile-search,projectile-grep/-ag/-ripgrepand the reviewable search. The tool that will run (grep/ag/ripgrep, orripgrep/elispfor the reviewable search's literal fast-path) is faced withprojectile-search-prompt-tooland the symbol-at-point default withprojectile-search-prompt-default. The reviewable search now also shows its default up front and which engine it will use.
Bugs fixed
- #1549, #1676: Re-invoke a function-valued lifecycle command (e.g. a CMake preset picker or a project type's
:run/:testfunction) on every run instead of freezing its first result in the command cache, so it can prompt again.
3.1.0 (2026-07-04)
New features
- #2064: Add declarative "file kinds", letting a project type describe categories of files (e.g. Rails models, controllers and views) via the new
:file-kindskeyword ofprojectile-register-project-type.projectile-find-file-of-kind(j) prompts for a kind and completes over just the project files of that kind.projectile-toggle-related-file(J) generalizesprojectile-toggle-between-implementation-and-test: it jumps to related files of other kinds, jumping straight when there's one, prompting when there are several, and cycling through them on repeated presses.- The
rails-test,rails-rspecanddjangoproject types ship with ready-made:file-kindstables. Related files are keyed by their namespaced path, so a top-levelUsersControllerrelates to the top-levelUsermodel rather than anAdmin::User.
- #2059:
projectile-find-fileandprojectile-find-file-dwimnow rank the files you work with first, ordering completion candidates by how often and how recently you've visited them (with decay).- The ranking is applied through completion metadata, so it works with any completion UI and under every indexing method, including
alien(whichprojectile-sort-ordernever reached). - Controlled by
projectile-enable-frecency(default on); the per-project history is persisted inprojectile-frecency-fileand capped byprojectile-frecency-max-files.
- The ranking is applied through completion metadata, so it works with any completion UI and under every indexing method, including
- #1992, #1587, #1553, #1794: Add named project tasks - shell commands (or functions returning them) that you can run by name.
projectile-tasksmaps task names to commands and can be set globally, per project type via the new:taskskeyword ofprojectile-register-project-type, or per project via.dir-locals.el.projectile-run-task(c x) picks a task with completion and runs it like the lifecycle commands, in a per-task compilation buffer; a prefix argument lets you edit the command first (e.g. to pass ad-hoc arguments).projectile-repeat-last-task(c X) re-runs the project's last task.
- #978: Add
projectile-project-changed-functions, run whenever the current project changes - including implicitly via visiting a file or directory of another project - with the new and previous project root as arguments. - #1442:
projectile-sort-ordercan now be set to a function that receives the list of project files and returns them in the desired order. - #1984: The VCS markers are now customizable via
projectile-vcs-markers, whose order breaks ties between markers in the same directory - so colocatedjj+gitrepositories can be detected asjjby moving.jjfirst. - #1890: Recognize osc (openSUSE Build Service) checkouts:
.oscis now a VCS marker, a top-down-recurring root marker, and globally ignored; file listing uses the generic indexing command. - #1694: Add
projectile-invalidate-cache-all, which invalidates the caches of all known projects at once (handy when commands likeprojectile-find-file-in-known-projectsserve stale results). - #1075: Add experimental opt-in automatic cache updates via filesystem notifications, so files created, deleted or renamed outside Emacs update the cache without a manual
projectile-invalidate-cache.- Enable it with
projectile-auto-update-cache-with-watches; only local, cached projects are watched. - Each project uses one
file-notifywatch per directory, bounded byprojectile-watch-directory-limit.
- Enable it with
- #2063: Add
projectile-other-window-command(s-p 4 4) andprojectile-other-frame-command(s-p 5 5), modeled after Emacs'sother-window-prefix/other-frame-prefix(C-x 4 4/C-x 5 5): they display the buffer of the next command in another window or frame, keeping the Projectile keymap active for the next key.- This works with any command, including ones without a dedicated
-other-window/-other-framevariant, e.g.s-p 4 4 x sstarts a project shell in another window.
- This works with any command, including ones without a dedicated
- #2060: Add
projectile-run-test-at-point(bound toc .), which runs just the test around point, located via the buffer's tree-sitter parse tree (requires Emacs 29+ with tree-sitter).- Rules for pytest (
python-ts-mode),go test(go-ts-mode) and jest (js-ts-mode/typescript-ts-mode/tsx-ts-mode) are built in; other languages can be added viaprojectile-test-at-point-rules.
- Rules for pytest (
Changes
- #2010: Project root detection and project-type detection now probe marker files with a single directory listing per directory level instead of one file stat per marker, collapsing dozens of sequential round-trips over TRAMP into one.
- Marker matching is exact-case as a result, even on case-insensitive filesystems. This corrected the
gnumaketype's marker to GNU make's actualGNUmakefilespelling, and themaketype now recognizes a lowercasemakefiletoo.
- Marker matching is exact-case as a result, even on case-insensitive filesystems. This corrected the
projectile-auto-discovernow defaults tot, so settingprojectile-project-search-pathis enough to have those projects discovered (no change for anyone without a search path).- The scan now runs once per session on the first project switch, rather than on every switch, and remote (TRAMP) search-path entries are skipped.
- #1771, #740: Hybrid indexing now applies the dirconfig glob patterns (
-/!entries without a leading slash); previously they were silently ignored underhybridand only/-prefixed path entries took effect. - #1941: Dirconfig glob patterns now follow
.gitignore-like rules, identical undernativeandhybridindexing (previouslynativeused loose string suffixes, so-buildalso ignoredmybuild, and expanded globs per directory level, so matching differed from level to level):- a slashless pattern matches the file name or any directory segment at any depth;
- a pattern containing a slash is anchored at the project root (prefix with
**/to match anywhere); - a trailing slash matches directories only, and a matched directory covers its subtree;
*stops at/while**crosses it.
- Remove
projectile-check-pattern-pandprojectile-ignored-rel-p, the old pattern matchers superseded by the compiled dirconfig matcher (nothing referenced them anymore). projectile-verify-filenow goes throughprojectile-file-exists-p, so cold project-type detection benefits from the remote file-exists cache instead of issuing a TRAMP round-trip for every marker file probed.- The mode-line updater is only added to
window-configuration-change-hookwhenprojectile-dynamic-mode-lineis enabled; change the option via Customize orsetoptfor it to apply immediately. - The
recentfandrecently-activesort orders no longer rescan the full project file list once per recent file, making them usable on very large projects. - #1953: Cache the git submodule listing instead of shelling out to
git submodule foreachon every alien/hybrid file listing; the cache invalidates automatically when.gitmoduleschanges and is also cleared byprojectile-invalidate-cache. - User-facing conditions (no project found, missing optional package, nothing to toggle to, etc.) now signal
user-errorinstead oferror, so they no longer trigger the debugger underdebug-on-error.
Bugs fixed
- #1115:
projectile-replaceno longer skips replacements (or reports "All files processed" without replacing anything) when the project root is in abbreviated~/...form, or when a match's case differs from a lower-case input. - #1677:
projectile-replaceandprojectile-replace-regexpnow scan buffers that already visit a project file from the beginning, so matches before point in those buffers are no longer missed. - #1849:
projectile-skel-dir-localsnow exits its variable-entry loop on an empty variable name, keeping the entries made so far, instead of trapping the user in the prompt and discarding input onC-g. - CMake preset files referenced via
includeare now resolved relative to the file that includes them; previously the top-levelCMakePresets.json's includes resolved againstdefault-directory, silently dropping the included presets when the current buffer was outside the project root. - #1600: The default git submodule listing no longer depends on a Unix shell (single quotes,
tr), fixing alien/hybrid indexing of projects with submodules on Windows. - Invalidating a project's cache now cancels its pending deferred cache flush; previously a flush scheduled before the invalidation could fire afterwards and recreate the just-deleted cache file with empty contents.
- Frecency tracking now works for projects reached through a symlinked root; the visited file is resolved the same way as the project root, so its visits are no longer silently dropped.
projectile-find-other-fileno longer treats the dot before a file's extension as a wildcard when matching, sofoo.elwon't match an unrelatedfooXel-style name.
3.0.0 (2026-07-01)
Changes
- #2055: Remove the dedicated
ido/ivy/helmcompletion systems (and theautomode that detectedido-mode/ivy-mode/helm-mode).projectile-completing-readnow uses Emacs'scompleting-read(the formerdefault), which works with Vertico, Consult, Fido,ido-completing-read+, etc., and still tags candidates with theproject-filecategory.projectile-completion-systemnow takesdefaultor a custom function; the removed values degrade todefault, so nothing breaks.helm-projectileandcounsel-projectileare unaffected (they don't go through this path). - #2045:
projectile-find-referencesnow honours Projectile's ignore configuration (.projectileand the globally-ignored files/directories) and is scoped via the project's file set, likeprojectile-grep/-ag/-ripgrep. It previously went through the semantic-symref API, which searched the whole tree and ignored that configuration. It also now defaults the prompt from the active region (not just the symbol at point) and no longer carries a dead pre-27 display fallback. The search remains a backend-agnostic textual one; for semantic references use the built-inxref-find-references(which is also scoped to the Projectile project). - #2041: Remove the built-in tags support:
projectile-find-tag,projectile-regenerate-tags,projectile-visit-project-tags-table, and theprojectile-tags-command/projectile-tags-backendoptions (along with the ggtags/etags-select special casing). ctags/etags navigation has been largely superseded byxrefand LSP (eglotis built in since Emacs 29). Usexref-find-definitionsdirectly, orprojectile-find-referencesfor project-wide references.projectile-tags-file-nameis kept, since it's still used to exclude a generated tags file from indexing. - #2040: Remove
projectile-browse-dirty-projectsandprojectile-vcs-dirty-state. The implementation spun upvc-dirand busy-waited (sleep-for) up to 30 seconds per project across every known project, scraping status strings - slow, blocking, and niche. Use Magit,vc-dir, or a dedicated tool to find projects with uncommitted changes. - #2039: Remove the idle timer (
projectile-enable-idle-timer,projectile-idle-timer-seconds,projectile-idle-timer-hook). It existed mainly to re-runprojectile-regenerate-tagson an idle timer, which makes little sense in an LSP/xref world, and it was off by default. Use a plainrun-with-idle-timerif you really want this behavior. - #2036: Remove
projectile-commander(anddef-projectile-commander-method), the single-key command dispatcher. It's superseded byprojectile-dispatch, thetransientmenu added in this cycle. Thes-p mbinding and theC-u s-p pproject-switch prefix now invokeprojectile-dispatchinstead (the prefix falls back toprojectile-switch-project-actionwhentransientisn't installed). - #2032: A cold
projectile-find-file(and any command that lists project files) no longer freezes Emacs while the project is indexed under thealien/hybridmethods. The indexing command runs asynchronously and is awaited in a way that keeps Emacs responsive to redisplay andC-g(which aborts the indexing), instead of blocking until it finishes. The resulting file list is identical; only the responsiveness during indexing differs. Controlled by the newprojectile-async-indexing(default on); it has no effect undernativeindexing, in batch mode, or while a keyboard macro runs, all of which index synchronously as before. - #2030: Speed up native indexing further:
projectile-index-directorynow reads each directory withdirectory-files-and-attributes, so an entry's type comes from the listing call instead of afile-directory-pstat per file. That stat was a separate filesystem round-trip each, which dominated the walk on large and remote (TRAMP) trees - it's now one round-trip per directory instead of one per file. Symlinks pointing at directories are still followed, matching the previous behaviour. Roughly 40% faster on a local 12k-file tree; the win is far larger over TRAMP. - #2035: Speed up native indexing's post-walk step:
projectile-dir-files-nativestrips the project-root prefix with a singlesubstringper file instead offile-relative-name, which paid for anexpand-file-name/abbreviate-file-nameper file.projectile-project-filesalso skips re-relativising the listing when the only directory walked is the project root itself (the common single-directory case). Together that removes roughly two seconds of overhead per 90k files indexed. - #1872: Clarify in the
projectile-register-project-typedocstring and the manual that a list ofmarker-filesmust all be present for a type to match (logical AND), and that a predicate function should be used to match when any one of several files is present. - #1935: The
emacs-easkproject type now has atestcommand (eask test), soprojectile-test-projectworks out of the box for Eask projects. Eask auto-detects the test framework (buttercup, ERT, ...), so no framework-specific type is needed. - #1638: Document in
projectile-svn-commandthat it runs non-interactively and therefore needs SVN credentials to be cached up front for authenticated remotes. - #2016: Keep a separate command history per lifecycle command type (configure, compile, test, install, package, run), so the prompt's
M-phistory no longer mixes, say, test commands with compile commands.projectile-repeat-last-commandstill uses the combined per-project history and is unaffected. - Remove the unused private
projectile--init-known-projectsalias (a leftover compatibility shim for the old known-projects API; nothing in the codebase referenced it). - #2000:
projectile-get-immediate-sub-projectsskips thegit submodule foreachshell-out for git projects with no.gitmodulesfile anywhere up the parent chain. Hot path for monorepos that index the project root often. - #2000:
projectile-discover-projects-in-directorynow usesdirectory-files-no-dot-files-regexpto skip.and..at the C level instead of doing the post-filter in Elisp - matches the indexing walker. - #2000: Document the anchored vs
*-prefixed semantics ofprojectile-globally-ignored-directories, thefindfallback's lack of common directory exclusions whenfdisn't available, and howfd/git ls-fileshandle deleted-but-unstaged files differently. - #1999: Speed up native indexing on large trees:
projectile-index-directorynow hashes the ignored-files / ignored-directories / globally-ignored-directory-names lists once per indexing call (the per-filememberscans were O(N*M)), expands dirconfig glob patterns once per directory level instead of once per (file, pattern) pair, and accumulates results into a shared cell so we no longer pay for anapply appendat each recursion level. - #1999:
projectile-remove-ignored(hybrid post-processing) now hashes the ignored-files basenames and pre-splits ignored-dirs into prefix-match and any-segment groups, so the per-file inner loops drop from O(M)seq-somewalks to O(1) hash lookups (or O(segments) for*-prefixed entries). - #1998: Hybrid indexing now batches the external command into a single invocation when the project's
.projectiledeclares multiple+keep entries, instead of shelling out once per kept subdirectory. The kept paths are passed to the indexing tool (e.g.git ls-files,fd,find) as positional pathspecs and submodule files outside those subdirectories are filtered out. Resolves the long-standing TODO inprojectile-project-files. - #1998:
projectile-files-via-ext-commandnow accepts an optionalpathspecsargument; entries are shell-quoted before being appended to the command.projectile-dir-files-aliensimilarly accepts an optionalsubdirsargument that threads through. - #1997: Document the
hybridindexing method in the manual and add a feature matrix showing which Projectile knobs (dirconfig, global ignores/unignores, sort order, default caching) apply undernative/hybrid/alien. - #1997:
projectile-dir-files-aliennow accepts an optionalvcsargument so the dispatcher can thread through the already-resolved VCS instead of recomputing it. Existing single-argument callers are unaffected. - #1997:
projectile-index-directory(native indexing) now relies ondirectory-files-no-dot-files-regexpto filter out.and..at the C level instead of walking past them in Elisp. - #1996:
projectile-project-root-cachenow keys entries on cons cells ((FUNC . DIR)for per-function results,('none . DIR)for the overall failure marker) instead of formatted strings. This is internal state, but third-party code that reaches into the cache directly will need to update. - #1994:
projectile-parse-dirconfig-filenow returns aprojectile-dirconfigstruct (withkeep,ignore,ensure, andprefixless-ignoreslots) instead of a positional 3-tuple. External callers should use the accessors (projectile-dirconfig-keepetc.) rather thancar/cadr/caddr. - #1994: Soft-deprecate prefix-less ignore entries in
.projectile. Lines without a+/-/!prefix are still treated as ignore patterns for backward compatibility, but a one-time warning is now shown for each project that uses them. Setprojectile-warn-on-prefixless-dirconfig-linesto nil to silence. - #2056: [Breaking] Remove the legacy single-letter lifecycle keybindings
C/K/L/P/u(configure/package/install/test/run project). Use thecprefix instead (c o,c p,c i,c t,c r). - #2056: Remove two long-obsolete aliases:
projectile-global-mode(useprojectile-mode) andprojectile-project-root-files-functions(useprojectile-project-root-functions). - #1986: Pre-compute file timestamps in
projectile-sort-by-modification-timeandprojectile-sort-by-access-timeto reduce stat calls from O(n log n) to O(n). - #1986: Cache
projectile-parse-dirconfig-fileresults per project root (invalidated by file modification time), avoiding redundant file reads during indexing. - #1986: Cache
file-truenameresults inprojectile-project-buffer-pwhen checking multiple buffers, reducing redundant symlink resolution. - #1987: Use a hash set for deleted file removal in
projectile-dir-files-alien, improving performance from O(n*m) to O(n+m) when filtering deleted-but-unstaged files. - #1987: Avoid redundant
projectile-project-rootcall inprojectile-detect-project-typeby passing through the already-resolved root. - #1988: Share
file-truenamecache across buffers inprojectile-open-projects, matching the optimization already inprojectile-project-buffers. - #1988: Remove unnecessary temp buffer creation in
projectile--cache-project-commands-p(was creating a buffer and re-reading.dir-locals.elon every compile/test/run invocation). - #2056: [Breaking] Bump the minimum required Emacs version to 28.1 (from 26.1). This removes ~30 lines of compatibility code (fileloop fallback,
time-convertfallback,projectile-flattenshim), makestransient(and thereforeprojectile-dispatch) an unconditional dependency, and fixes thetags-query-replaceFIXME inprojectile-replace-regexp. - Add
compatas a dependency, enabling the use of modern Emacs APIs (e.g.string-replace) on older Emacs versions. - Replace most
cl-libsequence functions withseq.elequivalents (seq-filter,seq-remove,seq-some,seq-find,seq-sort,seq-every-p,seq-difference) and convertcl-casetopcase. - #1971: Support
slnxfiles for dotnet project types. - #1958: Exclude
.projectile-cache.eldfrom search results (ripgrep/ag/grep) by default. - #1947:
projectile-project-nameshould be marked as safe. - Set
projectile-auto-discovertonilby default (to avoid startup slowdowns in some situations). - #1943: Consider
projectile-indexing-methodto be safe as a dir-local variable if it is one of the preset values. - #1936: Do not require selecting a project when using
M-x projectile-invalidate-cache, since there is a global cache that is also cleared by that command, even when not operating on any specific project. - Add
build.millas an alternative project marker for the Mill project type, matching Mill's current recommended file extension. - Replace obsolete
when-letandcl-gensymwithwhen-let*andgensymfor compatibility with Emacs 31+.
New features
- #1697: Add
projectile-add-and-switch-project, which prompts for a directory, adds it to the known projects, and immediately switches to it. - #1698: Support
%pin project command strings (configure/compile/test/run/install/package); it is replaced with the project name when the command runs, so e.g.:run "docker run %p"works for both registered project types and interactively entered commands. - #2053: Add
projectile-run(s-p x r), a single command that opens a shell, REPL or terminal in the project root over a pluggable backend (the same registry that powersprojectile-search). Projectile shipsshell,eshell,ielm,term,vterm,eatandghostelbackends;projectile-shell-backendselects which is used (defaulteshell). Register your own terminal withprojectile-register-shell-backend. The dedicated commands (projectile-run-eshell,projectile-run-vterm, ..., and the-other-windowvariants) are kept as thin wrappers that force a backend. - #2052: Add
projectile-search(s-p s s), a single search command that runs over a pluggable backend. Projectile shipsgrep,ripgrepandagbackends;projectile-search-backendselects which is used (autoby default, favouring ripgrep then grep). Register your own tool (deadgrep, consult-ripgrep, ...) withprojectile-register-search-backend.projectile-grep,projectile-ripgrepandprojectile-agare kept as thin wrappers that force a specific backend. Note the keymap change:s-p s sis nowprojectile-search(it used to beprojectile-ag), andprojectile-agmoves tos-p s a. The generic registry behind this (projectile-register-backend) is designed to be reused for other command families later. - #2051:
projectile-dispatchnow exposes command modifiers astransientswitches. A Modifiers group offers--invalidate-cache(-i, rebuild the file cache first, for the find file/dir commands),--regexp(-r, forag/ripgrep),--new-process(-n, for the shells/REPLs), and--display(-d, cycle the display target through this window / other window / other frame, for the file/buffer/project commands). The--displayswitch replaces the old dedicated "Other window" and "Other frame" menu columns. (Theprojectile-command-map4 <key>/5 <key>bindings are unchanged.) - #2034: Add
projectile-consult.el, an optional Consult integration distributed alongside Projectile (with a soft dependency onconsult, so it's only loaded if yourequireit).projectile-consult-find-filedrives a streaming Consult finder from Projectile's own indexing command (viaprojectile-project-files-producer), so candidates appear in the minibuffer as the project is indexed instead of blocking until it's done, while still honouring the project's VCS and indexing configuration. The module is self-contained so it can be split into its own package later; it requires Emacs 29.1+ (Consult's floor). - #2031: Add
projectile-index-project-async, which indexes the current project in the background (viamake-process) and populates the files cache without freezing Emacs, so a laterprojectile-find-filefinds the cache already warm. Works with thealien/hybridindexing methods (thenativeElisp walk can't run off the main thread) and requires caching to be enabled. The underlying building blocks -projectile-files-via-ext-command-asyncandprojectile-dir-files-alien-async- are public, so a streaming finder (e.g. one built onconsult) can drive Projectile's indexing command asynchronously. Remote projects are handled via TRAMP. The result is identical to the synchronous indexing path. - #2033: Add
projectile-project-files-producer, which returns a plist (:directory,:vcs,:command,:separator) describing how to list a project's files with its external indexing command. It gives an external asynchronous/streaming file finder (e.g. one built onconsultoraffe) a single, stable entry point for driving Projectile's own indexing command instead of stitching together the root, VCS and command builders by hand. - #1956: Add
projectile-switch-project-other-windowandprojectile-switch-project-other-frame(bound to4 pand5 p), which switch to a project and display it in another window/frame. The action they run is configurable viaprojectile-switch-project-other-window-action/projectile-switch-project-other-frame-action(find-file in the other window/frame by default). - #1809: Track the project switched away from in
projectile-most-recent-projectand addprojectile-switch-to-most-recent-projectto jump back to it (repeated calls toggle between the two). Only switches made through Projectile's switch-project commands are tracked. - #1861: Add
projectile-discard-command-cacheto drop the cached configure/compile/test/install/package/run commands for the current project, so a freshly edited.dir-locals.el(or project-type default) is picked up on the next run. Can be called manually or added toafter-save-hook. - #2011: Add
projectile-uniquify-dirname-transform, a project-aware value foruniquify-dirname-transformthat disambiguates same-named buffers using the project name. Mirrorsproject.el'sproject-uniquify-dirname-transform. - #2012: Add
projectile-dispatch, atransientmenu mirroringprojectile-command-mapfor more discoverable command access.transientis an optional dependency (it requires Emacs 28+); the menu is only available when it's installed and is not bound to a key by default. - #2008: Add
projectile-remove-project-typeto unregister a project type. This is the supported way to stop Projectile auto-detecting a type; clearing itsmarker-filesdoes not work (see the related bug fix below). - #1936: Add
projectile-discard-root-cachecommand to clearprojectile-project-root-cachewithout touching other Projectile caches. Useful after creating or removing a project marker, since the existingprojectile-invalidate-cacheeither also drops the file list cache or prompts for a project depending on context. - #1993: Warn once per session when
projectile-indexing-methodisalienbut the project has a non-empty.projectilefile, so users notice their dirconfig rules are being bypassed. Controlled by the newprojectile-warn-when-dirconfig-is-ignoredoption. - #1993: Warn when a
+keep entry in.projectilecontains glob metacharacters. The+prefix is for subdirectory paths only and globs are silently coerced into a non-matching directory name; the warning surfaces the misuse rather than letting it fail silently. - #1964: Implement
project-nameandproject-buffersmethods for theproject.elintegration, so that code usingproject.elAPIs returns correct results for Projectile-managed projects. - #2013: Implement the
project-ignoresmethod for theproject.elintegration, translating Projectile's global ignores, ignored file suffixes, and dirconfig (.projectile) ignore entries into the glob formatproject.elexpects. This makes Projectile a more completeproject.elbackend for tools that rely on the protocol (e.g.project-find-regexp). - #2014: Add
projectile-forget-projects-underto drop all known projects located under a directory (with a prefix argument it recurses into nested projects). Mirrorsproject.el'sproject-forget-projects-under. - #2014: Add
projectile-forget-zombie-projectsas an alias forprojectile-cleanup-known-projects, for discoverability and parity withproject.el'sproject-forget-zombie-projects. - #2015:
projectile-kill-buffers-filternow also accepts a composable list of conditions (buffer-name regexps, predicates, andmajor-mode/derived-mode/not/and/orforms), modeled onproject.el'sproject-kill-buffer-conditions. The existingkill-all,kill-only-files, and predicate-function values keep working unchanged. - #1837: Add
eatproject terminal commands with keybindingsx xandx 4 x. - #2022: Add
ghostelproject terminal commands with keybindingsx Gandx 4 G. - #1937: Add keybinding
A(in the projectile command map) and a menu entry forprojectile-add-known-project. - #1653: Add
projectile-compile-subprojectandprojectile-test-subprojectcommands for building/testing individual modules in multi-module projects (e.g. Maven, Gradle). Bound toc m candc m t.
Bugs fixed
- #2005: Fix hybrid indexing with
fdwhen the.projectilefile has+keep entries. The kept directories were appended to thefdcommand as bare positional arguments, butfd's grammar is[pattern] [path...](so the first path was misread as the search pattern) andfd9+ additionally rejects--strip-cwd-prefixalongside explicit paths (error: ... '--strip-cwd-prefix' cannot be used with '[path]...'). Projectile now passes the directories tofdvia--search-pathand drops--strip-cwd-prefixin that case. Other tools (git ls-files,find, etc.) still get plain trailing paths. - #2042: Asynchronous indexing now runs its command under
/bin/shrather than the user's interactiveshell-file-name. The async runner wraps the command as{ ...; } 2>file, which is POSIX-sh syntax and broke for users whose shell iscsh/tcsh/fish(it produced bogus{-related output instead of a file list). The indexing command itself is a plain POSIX command, so a POSIX shell is the correct interpreter regardless of the login shell. - #2046: Commands chosen from the
projectile-dispatchmenu now run in the project that was just selected, instead of the current buffer's project. The menu is atransient, so its suffix commands run after the project switch has unwound; the switched-to project is now kept current for the lifetime of the menu and restored when it exits. This applies whether the menu is reached viaC-u s-p por by settingprojectile-switch-project-actiontoprojectile-dispatch(or any other transient). - #2037:
projectile-consult.elnow byte-compiles cleanly whenconsultisn't installed. Because the module ships inside the Projectile MELPA package, build systems (package.el, nixpkgs) try to compile it withoutconsultpresent, which previously errored on its top-level(require 'consult).consultis now loaded softly at the top (and hard-required inside the command, where it's actually needed), with the used functions forward-declared. - #2042: A non-zero exit from the indexing command (
fd,git ls-files,find, ...) no longer abortsprojectile-find-filewhen the command still produced a file listing. External listers likefdroutinely exit non-zero on benign conditions (e.g. an unreadable directory hit mid-traversal); that output is now used. Auser-erroris still raised when a non-zero exit produced no output at all, so a genuinely broken/missing command is still surfaced rather than mistaken for an empty project. - #1663: Projects matched by
projectile-ignored-projects(orprojectile-ignored-project-function) are now excluded fromprojectile-relevant-known-projects, so they no longer show up inprojectile-switch-projecteven when they were added to the known projects before being ignored. Previously the ignore list was only consulted when adding a project. - #1909: A project type registered with a predicate
marker-filesfunction now receives the project root as its argument when detecting the current project's type. Previously it was passednil, so such a function could never match the current project. - #1829:
projectile-project-rootno longer errors with(wrong-type-argument stringp nil)whendefault-directoryis nil (which can happen in some non-file buffers); it returns nil instead. - #1946:
projectile-ripgrepnow builds its ignore exclusions as--glob=!PATTERNinstead of--glob '!PATTERN'. The surrounding single quotes were only stripped by POSIX shells, so on Windowscmdthey became part of the pattern and the exclusions silently failed. - #2008: A project type with an empty
marker-fileslist no longer matches every project.projectile-verify-filesis vacuously true for an empty list, so a type whose markers were cleared (e.g. viaprojectile-update-project-type ... :marker-files nil) would be detected everywhere instead of nowhere.projectile-detect-project-typenow treats an empty marker set as a non-match. projectile-discard-root-cacheandprojectile-invalidate-cachenow also clearprojectile-file-exists-cache. Without this, after creating a new project marker (.projectile,.git, etc.) over TRAMP, the negative entries cached during earlier root-walks would keep reporting "not found" for up toprojectile-file-exists-remote-cache-expireseconds even after the user explicitly invalidated the root cache.projectile-find-file-hook-functionno longer disables all of Projectile for remote buffers - the cheap operations (file caching, known-projects tracking, project buffer-count cap) now run regardless of remoteness, and only the genuinely slow ones (mode-line update, tags-table visit) stay gated. Previously the entire hook was a single(unless (file-remote-p ...)), which meant remote projects never showed up in known-projects auto-tracking and never had their files cached on visit.- Stop stat'ing remote known projects in
projectile-keep-project-p. The "remote and connected" branch usedfile-readable-p, which is a remote round-trip per project; withprojectile-auto-cleanup-known-projectsenabled, that turned every project switch into a serial network walk over all remote known projects. Remote projects are now always kept; users can drop dead ones withprojectile-remove-known-project. - Skip
file-truenamefor remote paths inprojectile-ignored-project-pandprojectile-ignored-projects. The known-projects tracker callsprojectile-ignored-project-pfrom the find-file hook for every visit, and the previous behavior round-tripped to the remote on each call (and once per ignored entry) just to canonicalize symlinks. projectile-project-buffer-pnow skips thefile-truenamecall for buffers visiting remote (TRAMP) files. Each truename was a remote round-trip andprojectile-project-buffersiterates the fullbuffer-list, so projects with N remote buffers in distinct directories were paying N round-trips on every call. Resolving symlinks across a TRAMP boundary is rarely meaningful in any case.- Replace the 10 sequential
file-exists-pprobes inprojectile-project-vcswith a singledirectory-fileslisting, and cache the per-project result inprojectile-project-vcs-cache. Also collapse the up-the-tree dominator walk so each ancestor directory is listed at most once instead of up to 10 times. Over TRAMP this turns "1 round-trip per VCS marker per probed directory" into "1 round-trip per probed directory", and the cache means follow-up callers (the indexing path,projectile-project-info, the project-cleanup loop) hit memory. - Cut down
projectile-project-rootround-trips on TRAMP. The cache-validity check used rawfile-exists-pon the cached project root, which is a fresh remote stat on every call; switched toprojectile-file-exists-pso the per-host TTL applies. Also memoize(file-truename dir)across theprojectile-project-root-functionsloop so cache-miss calls compute the truename once instead of once per probe (4-5 remote stats with the default function list). - #1501, #1275: Detect
fd/fdfindon the remote host for TRAMP projects instead of reusing the locally-detectedprojectile-fd-executable. The locally-resolved value is meaningless on the remote, so whenfdwas installed on the local box but not on the remote (or vice-versa), git indexing would silently fall back to an empty file list. The newprojectile-fd-executable-forreturns the per-directory executable, with a per-host cache so the remoteexecutable-findlookup runs at most once per host per session. - #1898, #1932: Surface non-zero exit codes from the indexing command in
projectile-files-via-ext-commandinstead of silently returning an empty file list. The most common cause isfd/gitbeing installed locally but not on the remote host of a TRAMP project — previously this manifested as an unexplained empty completion list (orstringp, nilcrashes downstream); it now signals auser-errorpointing at the*projectile-files-errors*buffer for the captured stderr. - #1211: Fix file-local
projectile-project-rootoverrides being ignored after the first buffer in a directory was visited. The cache used(default-directory)as part of the key butprojectile-root-localreads a buffer-local variable, so two buffers in the same directory with different overrides got the first buffer's answer. Results fromprojectile-root-localare no longer cached. - #1836: Memoize per-function
nilresults in the project root cache. Previously, when an early entry inprojectile-project-root-functionsreturned nil, the nil was indistinguishable from a missing cache entry, so the function was re-run on everyprojectile-project-rootcall. With many entries this could cost several full directory walks per call. A'nonesentinel is now stored for unsuccessful entries. - #1508: Fix dirconfig parser silently treating lines as ignore patterns when the
+/-/!prefix or the comment character is preceded by whitespace; leading spaces and tabs are now skipped before prefix dispatch. - #1989: Fix
projectile-files-via-ext-commandexecuting empty string as shell command for non-git VCS sub-projects. - #1989: Fix
projectile-select-filescrashing on filenames with regexp metacharacters by usingstring-searchinstead ofstring-match. - #1989: Fix
projectile-find-referencesusing internalxref--show-xrefsAPI whose signature changed across Emacs versions. - #1989: Fix
projectile-determine-find-tag-fnfalling back tofind-tagwhich was removed in Emacs 29; now falls back toxref-find-definitions. - #1989: Fix
projectile-files-to-ensureexpanding wildcards relative to the current buffer instead of the project root. - #1989: Fix
projectile-ignored-project-pfailing to match abbreviated paths against truename-resolved ignored projects list. - #1989: Fix
projectile-edit-dir-localssaving partial.dir-locals.elcontent when the user aborts skeleton insertion withC-g. - #1989: Fix
projectile--other-extension-filessort comparator ignoring its second argument, producing undefined ordering; replaced with a stable partition. - #1989: Fix
projectile-toggle-project-read-onlyoperating on the wrong buffer afteradd-dir-local-variableby wrapping insave-selected-window. - #1988: Fix
projectile-cache-current-filecallingprojectile-project-roottwice instead of reusing the already-resolved value. - Fix
projectile-cache-current-filequeueing one idle timer per opened file, each capturing a stale snapshot of the file list. With persistent caching, opening many files in a session would result in N redundant disk writes after Emacs went idle. A pending flush is now coalesced per project and reads the latest in-memory cache at fire time. - Fix
projectile-load-project-cachenot recording a cache time, which combined withprojectile-files-cache-expiremade the TTL check immediately re-evict freshly loaded data — every call ended up re-reading the cache file from disk and the data was never reindexed. The cache file's mtime is now used to seedprojectile-projects-cache-time. - #1988: Fix
projectile-load-project-cachestoring nil in cache on corrupt/empty cache files, preventing future reload attempts. - Fix
projectile-purge-dir-from-cacheonly updating the in-memory cache; with persistent caching the purged directory's files would reappear on the next session. The on-disk cache is now updated as well, matching the behavior ofprojectile-purge-file-from-cache. projectile-invalidate-cachenow deletes the persistent cache file instead of overwriting it with a serializednil.- #1988: Fix
projectile--cmake-command-presetsusingmapcarinstead ofmapcan, producing nested lists for included presets. - #1988: Fix
projectile--eatignoring thenew-processargument when generating buffer names. - #1988: Fix
projectile-check-vcs-statushanging indefinitely by adding a 30-second timeout to its busy-wait loop. - #1988: Fix
projectile-sort-by-modification-timeandprojectile-sort-by-access-timecrashing on deleted files (nilfile-attributes). - #1988: Fix
projectile-recentf-filesfailing to match files when the project root contains symlinks. - #1988: Fix
projectile--run-project-cmdpassing nil tocompilewhen no command is configured andcompilation-read-commandis nil — now signals a clearuser-error. - #1988: Fix
projectile--merge-related-files-fnsusing destructivenconcwhich could corrupt shared data and silently drop values when the existing list was nil. - #1988: Fix
projectile-configure-commandformat call passing an unusedcompile-dirargument. - #1987: Fix
projectile-update-project-typeresetting the project type cache with wrong hash table:test(used defaulteqlinstead ofequalfor string keys). - #1987: Fix
projectile-find-file-hook-functionrunningprojectile-maybe-limit-project-file-bufferson TRAMP buffers, causing potential hangs on slow connections. - #1987: Use
expand-file-nameinstead offile-truenameinprojectile-compilation-dirto avoid unnecessary symlink resolution (and TRAMP network round-trips). - #1987: Use non-destructive
appendinstead ofnconcinprojectile-get-all-sub-projectsto avoid mutating caller data. - #1987: Add
safe-local-variablepredicates for project settings variables (projectile-project-test-suffix,projectile-project-compilation-cmd, etc.) so they can be set in.dir-locals.elwithout prompting. - #1962: Fix
projectile-get-other-filescrashing when a candidate other-file lives in the project root directory. - #1816: Fix
projectile-expand-file-name-wildcardfailing when a parent directory is not readable (e.g. iCloud Drive, Termux). - #1841: Preserve user's
compilation-buffer-name-functionwhenprojectile-per-project-compilation-bufferis nil. - #1823: Update the mode-line via
window-configuration-change-hookso non-file buffers (e.g. Magit) display the correct project info. - #1886: Fix
(wrong-type-argument stringp nil)error when running project commands in a newly created project by usingprojectile-acquire-rootinstead ofprojectile-project-rootinprojectile--run-project-cmd. - #1456: Fix
projectile-replace-regexpstopping when encountering a missing file by filtering nonexistent files from the replacement file list. - #1687: Fix
projectile-grep-finished-hooknot running on subsequent grep calls due to buffer rename collision. - #1939: Handle corrupted
projectile-known-projects-filegracefully instead of crashing with(wrong-type-argument listp ...). - #1748: Fix
projectile-replacefalling back to the legacy Emacs 25/26 code path on Emacs 27+ becausefileloopwas not loaded. - #1741: Fix
projectile-replacetreating the search string as a regexp instead of a literal string on Emacs 27+. - #1729: Fix
projectile-root-top-downto actually return the topmost matching project root instead of the bottommost. - #1596:
projectile-find-dirnow includes intermediate directories that contain only subdirectories (e.g.src/when it only hassrc/ComponentA/,src/ComponentB/). - #1551: Don't add nonexistent files to the project cache (e.g. when visiting a new file with
find-fileand then abandoning the buffer). - #1554: Fix
projectile-files-with-stringfailing on special characters when usinggreporgit-grepby adding the-F(fixed-string) flag. - #1897: Filter deleted-but-unstaged files from
git ls-filesoutput in alien/hybrid indexing (whenfdis not used). - #1873: Skip unreadable directories during native indexing instead of aborting with a permission error.
- #1961: Prevent directories from matching file-type project root markers (e.g., a
workspacedirectory no longer matches theWORKSPACEBazel marker on case-insensitive filesystems). - #1749: Strip
./prefix fromfdoutput inprojectile-files-via-ext-command, fixing compatibility with olderfdversions that don't support--strip-cwd-prefix. - #1942: Fix
projectile-ripgrepfailing on zsh when ignored file patterns contain glob characters, by quoting--globarguments. - #1952: Fix CMake version parsing failing when
cmake --versionoutput contains extra text after the version number. - #1944: Fix Jujutsu file listing to use template syntax for null-byte-separated output, making it robust against user customization of
jjoutput format. - #1986: Fix
projectile-purge-file-from-cacheserializing the stale file list to disk instead of the updated one. - #1986: Fix misplaced paren in
projectile-project-buffers-other-buffercausingswitch-to-bufferarguments to be ignored. - #1986: Fix
projectile-default-generic-commandsilently dropping lambda/closure commands (only symbol commands worked). - #1986: Fix
dired-before-readin-hookbeing added as buffer-local instead of global inprojectile-mode, so it now correctly fires in all dired buffers. - #1986: Fix
projectile-find-dir-hooknot being cleaned up when disablingprojectile-mode. - #1986: Use
display-warninginstead ofmessagewhen cache serialization fails, making the failure visible in the*Warnings*buffer.
2.9.1 (2025-02-13)
Bugs Fixed
- #1929: Don't create cache files when
projectile-use-cachingis not set topersistent.
2.9.0 (2025-02-12)
New features
- #1870: Add package command for CMake projects.
- #1875: Add support for Sapling VCS.
- #1876: Add support for Jujutsu VCS.
- #1877: Add custom variable
projectile-cmd-hist-ignoredups. - Add support for Eask projects.
- #1892: Add category metadata to
completing-read. (it's used by packages likemarginaliaandembark) - #1899: Add support for xmake build utility.
- #1918: Add Zig project discovery.
- Add support for Swift project discovery.
- Introduce
projectile-global-ignore-file-patternsconfig that allows to ignore files and directories with regexp patterns. - Introduce
projectile-auto-cleanup-known-projectsoption that allows you to auto-cleanup missing projects.
Bugs fixed
- #1881: Fix
projectile-recentfwhen called outside any project. - #1915: Fix dotnet-sln project-type recognition. (check
*.slnfiles instead ofsrc/) - #1850: Ensure the presence of a project in
projectile-compilation-dir. - #1811: Revert a change to
projectile-ignored-directoriesthat had converted them into regular expressions. - #1893: Fix
projectile-discover-projects-in-directorywhen called interactively.
Changes
-
#1874: Changes
compilation-find-file-projectile-find-compilation-bufferto navigate directly to the file if already present on disk to help improve performance in scenarios where there are a large number of project directories. -
Drop support for Emacs 25.
-
Rework the caching logic. The main changes from before are:
-
Each project has its own cache file
-
Cache files are consulted only when you request the files of some project
This makes caching both more robust and faster, as before the cache file for all projects was loaded when projectile-mode was enabled.
-
-
Make the cache transient by default. (meaning it lives only in memory and is not persisted to a file)
- To enable persistent caching you need to set
projectile-enable-cachingto'persistent.
- To enable persistent caching you need to set
-
Speed-up load time by moving known projects initialization outside of
projectile-mode's init.- As a side effect the known projects will be initialized properly even if you're not using
projectile-mode. - The projects are read from disk the first time you invoke
projectile-switch-projector a similar command.
- As a side effect the known projects will be initialized properly even if you're not using
-
Introduce a common prefix for project lifecycle command keybindings:
c o->projectile-configure-projectc c->projectile-compile-projectc p->projectile-package-projectc i->projectile-install-projectc t->projectile-test-projectc r->projectile-run-project- The old keybindings will be removed in a future version of Projectile.
2.8.0 (2023-10-13)
New features
- #1862: Add project types "yarn" and "pnpm" separate from "npm".
- #1851: Add ripgrep to
projectile-commanderwith binding?p. - #1833: Add Julia project discovery.
- #1828: Add Nimble-based Nim project discovery.
- Add elm project type.
- #1821: Add
pyproject.tomldiscovery for python projects. - #1830: Add command
projectile-run-vterm-other-windowand bind it tox 4 v.
Changes
- #1839: Ensure
projectile-toggle-between-implementation-and-testalso obeysprojectile-project-test-dirandprojectile-project-src-dir. - #1285: By default, use fd in Git repositories instead of
git ls-fileswhen it is installed, in order to solve the problem where deleted files were still shown inprojectile-find-fileuntil their deletions were staged. The user-facing behavior should be the same, although potentially with different performance characteristics in large Git repositories. The old behavior can be reclaimed by settingprojectile-git-use-fdto nil. - #1831: Enable the project.el integration only when
projectile-modeis active. - #1847: Use literal directory name casing when toggling between impl and test.
Bugs fixed
- Fix
fdinserting color control sequences when used over tramp. - #1835: Reopening existing vterm buffer in other window
- #1865:
projectile-generic-commandshould useprojectile-fd-executableto find the path for fd.
2.7.0 (2022-11-22)
New features
- #1591: Add
project.elintegration that will make Projectile the default provider for project lookup. - Add new command
projectile-find-references(bound toC-c C-p ?andC-c C-p s x). - #1737: Add helpers for
dir-local-variablesfor 3rd party use. Functionsprojectile-add-dir-local-variableandprojectile-delete-dir-local-variablewrap their built-in counterparts. They always use.dir-locals.elfrom the root of the current Projectile project. - Add a new defcustom (
projectile-dirconfig-file) controlling the name of the file used as Projectile’s root marker and configuration file. - #1813: Allow project-files to contain wildcards and allow multiple project-files per project type registration. Add a new project-type for .NET solutions.
Changes
- #1812: Add a
projectile-root-markedfunction for finding roots marked by.projectile. Prioritize.projectileabove other bottom-up root files.
Bugs fixed
- #1796: Fix
projectile-root-bottom-updoesn't always find bottom-most file. - #1799: Fix
projectile-open-projectslists projects for which all buffers are closed. - #1806: Fix
projectile-project-typeto return the correct project type even when we pass it the DIR arg. As a result of the fix,projectile-expand-root,projectile-detect-project-type,projectile-verify-files,projectile-verify-fileprojectile-verify-file-wildcard,projectile-cabal-project-p,projectile-dotnet-project-p,projectile-go-project-pand the newly factored outprojectile-eldev-project-pnow also takes an &optional DIR arg to specify the directory it is acting on.
2.6.0 (2022-10-25)
New features
- #1790: Add
src-dirandtest-dirproperties for the mill project type. - #1778: Allow
projectile-replaceto select file extensions when using prefix arg (C-u). - #1757: Add support for the Pijul VCS.
- #1745: Allow
projectile-update-project-typeto change project type precedence and remove project options. - #1699:
projectile-ripgrepnow supports rg.el. - #1712: Make it possible to hide Projectile's menu. See
projectile-show-menu. - #1718: Add a project type definition for
GNUMakefile. - #1747: Add support for preset-based install-commands for CMake projects.
- #1768: Add support for disabling command caching on a per-project basis.
- #1797: Make all project type attributes locally overridable.
- #1803: Add support go-task/task.
Bugs fixed
- #1781: Fix
rails-rspecandrails-testto useappinstead oflibassrc-dir. - #1762: Fix
projectile-globally-ignored-directoriesunescaped regex. - #1713: Fix
projectile-discover-projects-in-directoryreordering known projects. - #1514: Fix
projectile-agglobal ignores not in effect. - #1714: Fix
projectile-discover-projects-in-directorynot interactive. - #1734: Make
projectile--find-matching-testusesrc-dir/test-dirproperties. - #1750: Fix source and test directories for Maven projects.
- #1765: Fix
src-dir/test-dirnot defaulting to"src/"and"test/"withprojectile-toggle-between-implementation-and-test. - Fix version extraction logic.
- 1654 Fix consecutive duplicates appearing in command history.
- #1755 Cache failure to find project root.
Changes
- #1785: Give the project type "go" higher precedence than universal types, namely "make".
- #1447: Restructure the menu.
- #1692: Enable minibuffer completions when reading shell-commands.
- Change the Grails project marker to
application.yml. - #1789: Progress reporter for recursive progress discovery.
- #1708:
projectile-ripgrepnow consistently searches hidden files.
2.5.0 (2021-08-10)
New features
- #1680: Add support for recursive project discovery.
- #1671/#1679: Allow the
:test-dirand:src-diroptions of a project to be set to functions for more flexible test switching. - #1672: Add
projectile-<cmd>-use-comint-modevariables (where<cmd>isconfigure,compile,test,install,package, orrun). These enable interactive compilation buffers. - #1705: Add project detection for Nix flakes.
Bugs fixed
- #1550: Make
projectile-regenerate-tagstramp-aware. - #1673: Fix CMake system-preset filename.
- #1691: Fix
compilation-find-fileadvice handling of directory.
Changes
- Remove
pkg-infodependency.
2.4.0 (2021-05-27)
New features
- Add
projectile-update-project-typefunction for updating the properties of existing project types. - #1658: New command
projectile-reset-known-projects. - #1656: Add support for CMake configure, build and test presets. Enabled by setting
projectile-cmake-presetsto non-nil, disabled by default. - Add optional parameters to
projectile-run-shell-command-in-rootandprojectile-run-async-shell-command-in-root
Changes
- Add
projectparam toprojectile-generate-process-name. - #1608: Use rebar3 build system by default for Erlang projects.
- Rename
projectile-project-root-files-functionstoprojectile-project-root-functions. - #1647: Use "-B" in the mvn commands to avoid ANSI coloring clutter in the compile buffer
- #1657: Add project detection for Debian packaging directories.
- #1656: CMake compilation-dir removed to accommodate preset support, commands adjusted to run from project-root, with "build" still being the default build-directory. The non-preset test-command now uses "cmake" with "--target test" instead of "ctest".
Bugs fixed
- #1639: Do not ask twice for project running ielm, term and vterm.
- #1250: Fix
projectile-globally-ignored-directoriesnot working with native indexing. - #1438: Make sure
projectile-files-via-ext-commandreturns files, not errors. - #1450: Call
switch-project-actionwithin project's temp buffer. - #1340: Fix remote projects being removed if TRAMP can't connect.
- #1655: Fix
projectile-replace-regexpsearching the wrong files when called with prefix arg. - #1659: Fix
projectile-project-vcsto work outside a project. - #1637: Integrate with savehist-mode.
2.3.0 (2020-11-27)
New features
- #1517: Add project-specific compilation buffers and only ask to save files in the project when compiling.
- New functions
projectile-acquire-rootandprojectile-process-current-project-buffers-current - New project commands
projectile-package-project,projectile-install-project. - #1539: New defcustom
projectile-auto-discovercontrolling whether to automatically discover projects in the search path whenprojectile-modeactivates. - Add emacs-eldev project type.
- Add Dart project type.
- #1555: Add search with ripgrep.
- Add Python-poetry project type.
- #1576: Add OCaml Dune project type.
- Add Mill project type.
- Auto-detect completion system, supporting
ido,ivy,helmand the default completion system.
Changes
- #1540: Add default
test-suffixto Angular projects. - Add a
:project-fileparam toprojectile-register-project-type. - #1588: Improve performance of
projectile-ibufferwith many buffers not in project. - #1601: Implement separate compilation command history for each project.
Bugs fixed
- #1377: Fix
projectile-regenerate-tagsdirectory.
2.2.0 (2020-06-10)
New features
- #1523: Add a new defcustom (
projectile-max-file-buffer-count) controlling how many opened file buffers should Projectile maintain per project. - Optional support for comments in .projectile dirconfig files using
projectile-dirconfig-comment-prefix. - #1497: New command
projectile-run-gdb(x g inprojectile-command-map). - Add Bazel project type.
Bugs fixed
- #1503: Leave archive before searching for the project root.
Changes
- #1528: Improve massively the performance of native indexing (it's around 10x faster now).
2.1.0 (2020-02-04)
New features
- #1486 Allow
projectile-run-shell/eshell/term/vterm/ielmto start extra processes if invoked with the prefix argument. - New command
projectile-run-vterm(x v inprojectile-command-map). - Add
related-files-fnoption to use custom function to find test/impl/other files. - #1019: Jump to a test named the same way but in a different directory.
- #982: Add heuristic for projectile-find-matching-test.
- Support a list of functions for
related-files-fnoptions and helper functions. - #1405: Add Bloop Scala build server project detection.
- #1418: The presence of a
go.modfile implies a go project. - #1419: When possible, use fd instead
of
findto list the files of a non-VCS project. This should be much faster.
Bugs fixed
- #675: Performance improvement for native project indexing strategy.
- #97: Respect
.projectileignores which are paths to files and patterns when usingprojectile-grep. - #1391: A
.cabalsub-directory is no longer considered project indicator. - #1385: Update
projectile-replacefor Emacs 27. - #1432: Support .NET project.
- #1270: Fix running commands that don't have a default value.
- #1475: Fix directories being ignored with hybrid mode despite being explicitly unignored.
- #1482: Run a separate grep buffer per project root.
- #1488: Fix
projectile-find-file-in-directorywhen in a subdir ofprojectile-project-root.
2.0.0 (2019-01-01)
New features
- #972: Add toggle for project read only mode:
projectile-toggle-project-read-only. - New interactive command
projectile-run-ielm. - Add crystal project type.
- #850: Make it possible to prompt for a project, when you're not in a project, instead of raising an error. (see
projectile-require-project-root). - #1147: Introduce a new indexing method called
hybridwhich behaves like the oldalien. - #896 Add commands
projectile-previous-project-bufferandprojectile-next-project-bufferto switch to other buffer in the project. - #1016: Add a new defcustom (
projectile-current-project-on-switch) controlling what to do with the current project on switch. - #1233: Add a new defcustom (
projectile-kill-buffers-filter) controlling which buffers are killed byprojectile-kill-buffers. - #1279: Add command
projectile-repeat-last-commandto re-execute the last external command in a project.
Changes
- (Breaking) #1147: Remove any post-processing from the
alienindexing method. - Specify project path for
projectile-regenerate-tags. - Handle files with special characters in
projectile-get-other-files. - #1260: ignored-*-p: Now they match against regular expressions.
- (Breaking) Remove the default prefix key (
C-c p) for Projectile. Users now have to pick one themselves. - Deprecate
projectile-keymap-prefix. - Avoid "No projects needed to be removed." messages in global mode.
- #1278: Add default
test-suffixtonpmproject. - #1285: Add default
test-suffixto Python projects. - #1285: Add support for Pipenv-managed Python projects.
- #1232: Stop evaluating code dynamically in the mode-line and switch to a simpler scheme where the mode-line is updated just once using
find-file-hook. - Make the mode line configurable via
projectile-dynamic-mode-lineandprojectile-mode-line-function. - #1205: Check that project directory exists when switching projects.
- Move Projectile's menu out of the "Tools" menu.
- [API] (Breaking) Stop raising errors from
projectile-project-rootif not invoked within a project. Now it will simply return nil. Use it together withprojectile-ensure-projectto emulate the old behavior.
Bugs fixed
- #1315: Give preference to the project types that were registered last.
- #1367: Fix the Makefile so that we can compile projectile - use
make.
1.0.0 (2018-07-21)
New Features
- #1255: Add support for function symbols as project default commands
- #1243: Add angular project support.
- #1228: Add support for a prefix argument to
projectile-vc. - #1221: Modify Ruby and Elixir project settings.
- #1175: Add a command
projectile-configure-commandfor running a configuration for build systems that need that. - #1168: Add CMake and Meson project support.
- #1159 Add nix project support.
- #1166: Add
-other-frameversions of commands that had-other-windowversions. - Consider Ensime configuration file as root marker,
.ensime. - #1057: Make it possible to disable automatic project tracking via
projectile-track-known-projects-automatically. - Added ability to specify test files suffix and prefix at the project registration.
- #1154 Use npm install instead of build.
- Added the ability to expire old files list caches via
projectile-projectile-files-cache-expire. - #1204:
projectile-register-project-typecan now be used to customize the source and test directory via:src-dirand:test-dirfor projects with custom needs (eg. maven). - #1240: Add some integration with ripgrep.
- Add
projectile-project-search-path, which is auto-searched for projects whenprojectile-modestarts. - Add
projectile-discover-projects-in-search-pathcommand which searches for projects inprojectile-project-search-path. - Auto-cleanup missing known-projects on
projectile-modestart.
Changes
- #1213: Cache project root in non-file-backed buffers.
- #1175:
projectile-register-project-typecan now set a default compilation directory for build systems that need to build out-of-tree (eg. meson). - #1175:
projectile-{test,run}-projectnow run inside(projectile-compilation-dir), just likeprojectile-compile-project. - #1175:
projectile-{test,run}-projectnow stores the default command per directory instead of per project, just likeprojectile-compile-project. - Cache the root of the current project to increase performance
- #1129: Fix TRAMP issues.
- Add R DESCRIPTION file to
projectile-project-root-files. - Ignore backup files in
projectile-get-other-files. - Ignore Ensime cache directory,
.ensime_cache. - #364:
projectile-add-known-projectcan now be used interactively. projectile-modeis now a global mode.projectile-find-tagnow defaults to xref on Emacs 25.1+.- Add relation between
.hand.ccfiles inprojectile-other-file-alist. - Cache the name of the current project for mode-line display of the project name.
- #1078: For projectile-grep/ag use default value like grep/rgrep/ag.
- Don't treat
package.jsonas a project marker. - #987: projectile-ag ignores ag-ignore-list when projectile-project-vcs is git
- #1119: File search ignores non-root dirs if prefixed with "*"
- Treat members of
projectile-globally-ignored-file-suffixesas file name suffixes (previously treated as file extensions). - Ensure project roots are added as directory names to avoid near-duplicate projects, e.g. "
/project/" and "/project". - Don't autoload defcustoms.
- (Breaking) Require Emacs 25.1.
- Remove the support for grizzl.
Bugs fixed
- #1222:
projectile-configure-projectfails for generic project type - #1162:
projectile-agcauses "Attempt to modify read-only object" error. - #1169:
projectile-compile-projectdoes not prompt for compilation command. - #1072: Create test files only within the project.
- #1063: Support Fossil checkouts on Windows.
- #1024: Do not cache ignored project files.
- #1022: Scan for Fossil's checkout DB, not its config DB.
- #1007: Make use of
projectile-go-function. - #1011: Save project files before running project tests.
- #1099: Fix the behaviour of
projectile-purge-dir-from-cache. - #1067: Don't mess up
default-directoryafter switching projects. - #1246: Don't blow away real project file during tests.
0.14.0 (2016-07-08)
New features
- Add elixir project type.
- Add emacs-cask project type.
- Add boot-clj project type.
- Add racket project type.
- Add support for projects using gradlew script.
- Prefer Haskell stack projects over cabal projects.
- Add ability to use elisp functions for test, compile and run commands.
- Consider
TAGSandGTAGSroot markers. - Add relation between the
.h,.cxx,.ixxand.hxxfiles inprojectile-other-file-alist. - Add relation between the
.hppand.ccfiles inprojectile-other-file-alist. - Add support to specify project name either via
.dir-locals.elor by providing a customizedprojectile-project-name-function. - Add a command to switch between open projects (
projectile-switch-open-project). - Add a command to edit the .dir-locals.el file of the project (
projectile-edit-dir-locals). - Add file local variable
projectile-project-root, which allows overriding the project root on a per-file basis. This allows navigating a different project from, say, an org file in a another git repository. - Add
projectile-grep-finished-hook. - Ignore file suffixes listed in
projectile-globally-ignored-file-suffixeswhen usingprojectile-grepandprojectile-ag. - Add
projectile-replace-regexp, which supports replacement by regexp within a project.projectile-replaceis now used solely for literal replacements. - New command
projectile-run-shell(C-c p x s). - New command
projectile-run-eshell(C-c p x e). - New command
projectile-run-term(C-c p x t). - #971: Let user unignore files in
.projectilewith the ! prefix. - Add a command to add all projects in a directory to the cache (
projectile-discover-projects-in-directory). - Add a command to list dirty version controlled projects (
projectile-browse-dirty-projects).
Changes
- Prefer ag's internal .gitignore parsing.
- Added variable to control use of external find-tag implementations.
- Specify
--with-keep.sourceargument when installing R projects
Bugs fixed
- #871: Stop advice for
compilation-find-fileto override other advices. - #557: stack overflow in
projectile-find-tag. - #955: Error while toggling between test and source file.
- #952: VCS submodules brought in even though not descendent of project root.
- #576:
projectile-replacestomps regular expressions. - #957: When opening a specified file from the terminal, do not error inside of
projectile-cache-current-file. - #984: Error when a project is a symlink that changes target.
- #1013:
projectile-project-buffer-pmay return incorrect result on Windows.
0.13.0 (2015-10-21)
New features
- Add
projectile-before-switch-project-hook. - Add the ability to specify the project type via
.dir-locals.el. - Add support for projects using Midje.
- Add the ability to create missing tests automatically (controlled via the
projectile-create-missing-test-filesdefcustom). - Add the ability to dynamically decide if a project should be added to
projectile-known-projects(via newprojectile-ignored-project-functiondefcustom). - Add the ability to register new project types dynamically with
projectile-register-project-type. - Add the ability to specify a project compilation and test commands via
.dir-locals.el. This is done via the variablesprojectile-project-compilation-cmdandprojectile-project-test-cmd. - #489: New interactive command
projectile-run-project. - Optionally run monky on Mercurial projects.
- Add the ability to specify a project compilation directory relative to the root directory via
.dir-locals.elwith the variableprojectile-project-compilation-dir. - When there is a selected region, projectile-ag, projectile-grep, projectile-replace and projectile-find-tag uses its content as a search term instead of symbol at point.
Changes
- Rename
projectile-switch-project-hooktoprojectile-after-switch-project-hook. projectile-compile-projectnow offers appropriate completion targets even when called from a subdirectory.- Add an argument specifying the regexp to search to
projectile-grep. - Use
helm-projectile-grepinstead ofhelm-find-filewhen selecting a project. - Omit current buffer from
projectile-switch-to-bufferandprojectile-switch-to-buffer-other-windowchoices.
Bugs fixed
- #721: Remove current buffer from
helm-projectile-switch-project. - #667 Use
file-truenamewhen caching filenames to prevent duplicate/symlinked filepaths from appearing when opening a project file. - #625: Ensure the directory has a trailing slash while searching for it.
- #763: Check for
projectile-use-git-grepinhelm-projectile-grep - Fix
projectile-parse-dirconfig-fileto parse non-ASCII characters properly.
0.12.0 (2015-03-29)
New features
- Replace Helm equivalent commands in
projectile-commanderwhen using Helm. - Add replacement commands projectile-grep, projectile-ack and projectile-ag with their Helm versions.
- Add virtual directory manager that allows to create/update (add or delete files) a Dired buffer based on Projectile files.
- Add a new Helm command:
helm-projectile-find-file-in-known-projectsthat opens all files in all known projects. - Add an action for
helm-projectile-switch-projectto delete multiple marked projects. - Add the ability to retrieve files in all sub-projects under a project root.
- Add
projectile-find-file-dwimandhelm-projectile-find-file-dwimcommands. - Provide actual Helm commands for common Projectile commands.
- Use existing Helm actions and map in
helm-find-filesthat allowshelm-source-projectile-files-listto behave likehelm-find-files, such as multifile selection and opening or delete on selected files. - Add compile action to
helm-projectile. - Allows using Eshell and Magit outside of a project in
helm-projectile. - Add Helm action for incremental grep in the selected projects.
- Add command projectile-find-other-file Switch between files with the same name but different extensions.
- Add Helm interface to switch project. For more details checkout the file README.md.
- Make the mode line format customizable with
projectile-mode-line - Add support for
cargo.tomlprojects - Try to use projectile to find files in compilation buffers
- Support
helmas a completion system - New command
projectile-project-infodisplays basic info about the current project. - New
defcustomprojectile-globally-ignored-buffersallows you to ignore buffers by name - New
defcustomprojectile-globally-ignored-file-suffixesallows you to globally ignore files with particular extensions
Changes
- get-other-files returns more accurate results for files with the same name placed under different directories
- Collect search tool (
grep,ag,ack) keybindings under a common keymap prefix (C-c p s) - Remove
defcustomprojectile-remember-window-configsin favor ofpersp-projectile.el. - Progress reporter for the native indexing method.
Bugs fixed
- Fix
projectile-regenerate-tagsto work in directories that include spaces. - Prevent
projectile-kill-buffersfrom trying to kill indirect buffers. - #412: Handle multiple possible targets in
projectile-toggle-between-implementation-or-test.
0.11.0 (2014-05-27)
New features
- Added support for default file glob pattern to
projectile-grep - added file existence cache with defcustoms
projectile-file-exists-remote-cache-expireandprojectile-file-exists-local-cache-expire. - added new defcustoms
projectile-project-root-files-top-down-recurring,projectile-project-root-files-bottom-upandprojectile-project-root-files-functions. - Added new command
projectile-save-project-buffers. - Added new command
projectile-cleanup-known-projects. - Added new commands
projectile-display-bufferandprojectile-find-dir-other-window. - Added new interactive function
projectile-project-buffers-other-bufferwhich runs newprojectile-project-buffers-non-visiblefunction, the former is bound toC-c p ESC. - New variable
projectile-enable-idle-timerturns on an idle timer which runs the hookprojectile-idle-timer-hookeveryprojectile-idle-timer-secondsseconds when non-nil. - New defcustom
projectile-remember-window-configswill makeprojectile-switch-projectrestore the most recent window configuration (if any) of the target project. - New command
projectile-run-command-in-root. - New command
projectile-run-shell-command-in-root. - New command
projectile-run-async-shell-command-in-root. - New defcustom
projectile-use-git-grepwill makeprojectile-grepusegit grepfor git projects. - Added new
projectile-commandermethods ?v and ?R which runprojectile-vcandprojectile-regenerate-tags, respectively. projectile-vcwill usemagit-statusif available.- New functions
projectile-find-implementation-or-testandprojectile-find-implementation-or-test-other-window, the latter is bound toC-c p 4 t. - New defcustoms
projectile-test-prefix-functionandprojectile-test-suffix-functionallow users to customize how projectile identifies test files by project type. projectile-grepwill ask for a file pattern if invoked with a prefix argument.- Subversion checkouts are now automatically detected.
- CVS checkouts are now automatically detected.
- added
projectile-persp-switch-projectcommand to make perspective mode work along with projectile. - Changed
projectile-mode-line-lighterto a defcustom variable to make mode line indicator prefix customizable. - New command
projectile-find-file-in-known-projects. - New defcustom
projectile-ignored-projectsallows you to specify projects that shouldn't be added to the known projects list. - New command
projectile-remove-current-project-from-known-projects. - New defcustom
projectile-buffers-filter-function. - New defcustom
projectile-sort-order. - New function
projectile-process-current-project-buffers. - New function
projectile-process-current-project-files.
Changes
- The presence of a
Makefileis no longer taken as an indicator of the project root by default, since recursive make is unfortunately a common occurrence (affectsprojectile-project-root-files). - Projectile is now able to find the project pertaining to a symlink pointing to a version-controlled file.
- Drop
projectile-ack-functiondefcustom. projectile-command-mapis now the keymap referenced by theprojectile-keymap-prefixinprojectile-mode-map. This allows modification of the inner map, and allows additional prefix keys to reference it.
Bugs fixed
- Modified
projectile-ackto append toack-and-a-half-argumentsinstead of overriding them. - [#229] Fix
projectile-find-file-in-directory's behavior for project directories projectile-toggle-between-implementation-or-testshows understandable error if current buffer is not visiting a file.- [#244] Correct folder picked up by
projectile-ackafter project-switch. - [#182] Invalidate project cache if .projectile is modified.
0.10.0 (2013-12-09)
New features
- Added new command
projectile-find-file-other-window. - Added new command
projectile-switch-to-buffer-other-window. - Added new command
projectile-find-file-in-directorythat allows you to jump to files in any directory. .projectileis now always taken into account.projectile-switch-project's behavior is now customizable viaprojectile-switch-project-action.- Added support for Gradle projects.
- Added support for
Ag. - Added new command
projectile-purge-file-from-cache. - Added new command
projectile-purge-dir-from-cache. - Added new command
projectile-find-tag. - Added new command
projectile-commander. It allows you to quickly run many Projectile commands with a single key. Very useful as a project-switching action. projectile-switch-projectnow supports a prefix argument. When it's present the switch action isprojectile-commander.
Changes
- Replaced variable
projectile-use-native-indexingwithprojectile-indexing-method. - Corrected grammar on error message for not being in a project.
Bug fixes
projectile-find-test-filenow properly displays only test files (#145).
0.9.2 (2013-07-16)
New features
projectile-invalidate-cachenow accepts a prefix argument. When present you'll be prompted for the project whose cache to invalidate.- New command
projectile-find-dirworks similar toprojectile-find-file- displays the project's dirs and opens them withdired. It's bound toC-c p d. - Added support for
grizzlas a completion system. - Added support for
fossilprojects. - Added support for
Symfony 2project. - New command
projectile-clear-known-projectsremoves all known projects. - New command
projectile-remove-known-projectprompts you for a known project to remove.
Bugs fixed
- Fixed
projectile-replace, which was broken from the use of relative paths - #103 -
projectile-switch-projectdoes not require a project to work - Don't show hidden buffers in projectile-project-buffers
Changes
- Rebound
projectile-compile-projectto C-c p c - Rebound
projectile-diredto C-c p D - Reworked
projectile-compile-projectandprojectile-test-projectto be smarter, more configurable and closer in behavior to the stockcompilecommand projectile-switch-project(C-c p s) now runsprojectile-find-fileinstead ofdired.
0.9.1 (2013-04-26)
New features
- Display recentf files in helm-projectile.
Bugs fixed
- #95 - handle properly missing project root
0.9.0 (2013-04-24)
New features
- Use fast external tools to find project files when possible. This is the default option on all Unices.
- Removed obsolete command
projectile-reindex-project. - Removed obsolete command
projectile-open. - Introduced support for finding tests and switching between code and tests.
- Implement basic project type detection.
- Add a simple version reporting command projectile-version.
- Display relative paths to project files instead of disambiguated filenames.
- Directories listed in .projectile file are excluded when tags are generated.
- Remembers visited projects and may switch between them with
projectile-switch-project. - Supports
lein {compile|test}in Clojure projects. - Support projects only for subdirs of the project root.
- Add the ability to manually cache files.
Bugs fixed
- #57 - properly set the current working dir, before invoking shell commands
- #71 - correct regenerate tags keybinding in the README
Misc
- Move menu entry under
Tools - Show indexing message only when doing native project indexing
- Massive performance improvements