# Changelog

<!-- Entries are one line per item and section headings repeat for every release,
     so the line-length and duplicate-heading rules don't fit this file. -->
<!-- markdownlint-disable MD013 MD024 -->

## master (unreleased)

### New features

- [#2160](https://github.com/bbatsov/projectile/pull/2160): Add `projectile-find-file-in-sibling-projects` (`s-p n f`) and `projectile-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-projects` and `projectile-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.
- [#2165](https://github.com/bbatsov/projectile/pull/2165): A subproject now has its own project type, so the `s-p c m` lifecycle commands build a monorepo member with the member's own toolchain - a Rust crate or Go module under a JavaScript repository runs `cargo test` or `go test` rather than the repository's `npm test`. New `projectile-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.json` and would otherwise fall back to plain `npm`.
- [#2166](https://github.com/bbatsov/projectile/pull/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. New `projectile-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](https://github.com/bbatsov/projectile/pull/2163): Add `projectile-switch-to-buffer-in-sibling-projects` (`s-p n b`), `projectile-multi-occur-in-sibling-projects` (`s-p n o`) and `projectile-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-projects` joins the two existing generic commands, and `projectile-todos` now shares one implementation with its group form.

### Changes

- [#2160](https://github.com/bbatsov/projectile/pull/2160): `projectile-switch-sibling-project` moved from `s-p n` to `s-p n p`. `s-p n` is now the prefix for every command that works across related projects, with each key mirroring the project-wide one a level down, the way `c m` does for subprojects.
- [#2168](https://github.com/bbatsov/projectile/pull/2168): Search results are redrawn at most every `projectile-search-render-interval` while 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](https://github.com/bbatsov/projectile/pull/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](https://github.com/bbatsov/projectile/pull/2172): Fix subproject detection in a Go workspace. A `go.work` names its modules as `./api`, and the leading `./` survived into the subproject name, which then matched none of the project's file paths - so `projectile-find-file-in-subproject` offered nothing at all in a Go monorepo. Members are now spelled relative to the project root whatever the manifest wrote.
- [#2171](https://github.com/bbatsov/projectile/pull/2171): The commands that list the known projects now load the persisted list first. They read the `projectile-known-projects` variable, 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-projects` completed over an empty list; `projectile-vc`, `projectile-remove-known-project` and the "Switch to project" prompt of `projectile-require-project-root` were affected too.
...
...
