= Configuration

In the typical style of Emacs, Projectile is *extremely* configurable.
Pretty much every aspect of its behaviour can be tweaked or extended.

In this section we'll go over some of the most common things you might
want to fine-tune to make Projectile fit your workflow better.

TIP: A couple of larger configuration topics have their own pages:
xref:indexing.adoc[indexing, caching & performance] and
xref:sessions.adoc[per-project sessions].

== Using Projectile commands outside of project directories

Normally, you'd be using Projectile's commands from within some project directory.
If, however, you invoke a command outside of a project, by default you'll be prompted
for a project to switch to. That behavior is controlled by `projectile-require-project-root`.
You can make Projectile simply raise an error outside of Project folders like this:

[source,elisp]
----
(setq projectile-require-project-root t)
----

If you want Projectile to be usable in every directory (even without the presence of project file):

[source,elisp]
----
(setq projectile-require-project-root nil)
----

With this setting if you invoke Projectile outside of a project, the current directory will be
considered by Projectile the project root.

TIP: This might not be a great idea if you start Projectile in your home folder for instance. :-)

== Switching projects

By default, projectile does not include the current project in the list when
switching projects. If you want to include the current project, customize
variable `projectile-current-project-on-switch`.

When running `projectile-switch-project` (kbd:[s-p p]) and
`projectile-switch-open-project` (kbd:[s-p q]) Projectile invokes the
command specified in `projectile-switch-project-action` (by default it
is `projectile-find-file`).

TIP: Invoking the command with a prefix argument (kbd:[C-u s-p p] or kbd:[C-u s-p q]) will trigger
 the Projectile dispatch menu (`projectile-dispatch`), which gives you quick access to most
 common commands you might want to invoke on a project.

Depending on your personal workflow and habits, you
may prefer to alter the value of `projectile-switch-project-action`:

=== `projectile-find-file`

NOTE: This is the default.

With this setting, once you have selected your
project via Projectile's completion system (see below), you will
remain in the completion system to select a file to visit. `projectile-find-file`
is capable of retrieving files in all sub-projects under the project root,
such as Git submodules. Currently, only Git is supported. Support for other VCS
will be added in the future.

=== Dispatch menu on project switch

If you often need to invoke a different action right after switching to a
project, press kbd:[C-u s-p p] (a prefix argument to any switch-project
command). After you pick a project, Projectile opens the `projectile-dispatch`
menu so you can choose what to do in it.

NOTE: This requires the optional `transient` dependency. Without it the prefix
argument is ignored and the usual `projectile-switch-project-action` runs.

[[dashboard-switch-action]]
=== `projectile-dashboard`

[source,elisp]
----
(setq projectile-switch-project-action #'projectile-dashboard)
----

With this setting you land in a summary of the project you just switched to -
its type and file count, the branch and how dirty the working tree is, the
files you were last working on, and the tasks and lifecycle commands you can
run - all of it actionable with kbd:[RET]. It's the closest thing Projectile
has to `project.el`'s command menu, except it also tells you where you are.

The dashboard is built to be cheap enough for this: it never indexes the
project (a cold project simply reports "not indexed yet") and it skips the VCS
query on remote projects. See xref:usage.adoc#dashboard[Project dashboard].

=== `projectile-find-file-in-known-projects`

Similar to `projectile-find-file` but lists all files in all known projects. Since
the total number of files could be huge, it is beneficial to enable caching for subsequent
usages.

=== `projectile-find-file-dwim`

If point is on a filepath, Projectile first tries to search for that
file in project:

* If it finds just a file, it switches to that file instantly.  This
works even if the filename is incomplete, but there's only a single file
in the current project that matches the filename at point. For example,
if there's only a single file named "projectile/projectile.el" but the
current filename is "projectile/proj" (incomplete), projectile-find-file
still switches to "projectile/projectile.el" immediately because this
is the only filename that matches.
* If it finds a list of files, the list is displayed for selecting. A
list of files is displayed when a filename appears more than one in the
project or the filename at point is a prefix of more than two files in a
project. For example, if `projectile-find-file' is executed on a
filepath like "projectile/", it lists the content of that directory.
If it is executed on a partial filename like "projectile/a", a list of
files with character 'a' in that directory is presented.
* If it finds nothing, display a list of all files in project for
selecting.

=== `projectile-dired`

[source,elisp]
----
(setq projectile-switch-project-action #'projectile-dired)
----

With this setting, once you have selected your project, the top-level
directory of the project is immediately opened for you in a dired
buffer.

=== `projectile-find-dir`

[source,elisp]
----
(setq projectile-switch-project-action #'projectile-find-dir)
----

With this setting, once you have selected your project, you will
remain in Projectile's completion system to select a sub-directory of
your project, and then _that_ sub-directory is opened for you in a
dired buffer.  If you use this setting, then you will probably also
want to set

[source,elisp]
----
(setq projectile-find-dir-includes-top-level t)
----

in order to allow for the occasions where you want to select the
top-level directory.

== Known projects

Projectile stores the list of known projects in a file on disk.  You can
customize its location:

[source,elisp]
----
(setq projectile-known-projects-file "~/.emacs.d/projectile-bookmarks.eld")
----

=== Ignoring projects

You can prevent certain projects from being added to the known projects list:

[source,elisp]
----
;; A list of projects to ignore
(setq projectile-ignored-projects '("/tmp/" "~/.emacs.d/"))
----

For more flexible filtering, set `projectile-ignored-project-function` to a
predicate that receives a project root and returns non-nil if the project should
be ignored:

[source,elisp]
----
;; Ignore all remote (TRAMP) projects
(setq projectile-ignored-project-function #'file-remote-p)
----

=== Automatic tracking

By default, Projectile automatically adds projects to the known projects list
whenever you visit a file in a project.  You can disable this:

[source,elisp]
----
(setq projectile-track-known-projects-automatically nil)
----

== Completion options

Projectile reads with Emacs's built-in `completing-read`, so it works out of the
box with whatever minibuffer UI you use - Vertico, Consult + Marginalia,
`fido-mode`/`icomplete`, and so on. Its candidates are tagged with the
`project-file` completion category, which Marginalia and Embark use to enhance
how they're presented.

[source,elisp]
----
;; the default; nothing to configure for the common case
(setq projectile-completion-system 'default)
----

NOTE: Earlier versions had dedicated `ido`, `ivy` and `helm` completion systems;
these were removed in Projectile 3.0, and any of the old
`projectile-completion-system` values now simply behaves like `default`. Those
frameworks are used through `completing-read` these days, or through their own
integration packages,
https://github.com/bbatsov/helm-projectile[helm-projectile] and
https://github.com/ericdanan/counsel-projectile[counsel-projectile]. `ido` users
in particular should read the
xref:upgrading_to_projectile_3.adoc#ido-users[upgrade guide], which covers
`ido-completing-read+`.

[#recommended-completion-stack]
=== A recommended setup

Nothing below is required, but this is the combination that gets the most out of
Projectile's completion metadata, and it's what the screenshots in this manual
were taken with:

[source,elisp]
----
(use-package vertico      ; a vertical completion UI
  :ensure t
  :init (vertico-mode +1))

(use-package marginalia   ; annotations next to each candidate
  :ensure t
  :init (marginalia-mode +1))

(use-package orderless    ; space-separated, order-independent matching
  :ensure t
  :init (setq completion-styles '(orderless basic)))
----

https://github.com/minad/marginalia[Marginalia] is the one worth calling out,
because Projectile does real work to make it useful. Every Projectile prompt
tags its candidates with a completion category, and Marginalia keys off that
category to decide what to show: file size, permissions and modification time at
`projectile-find-file`, buffer sizes and major modes at
`projectile-switch-to-buffer`, and so on. The same prompt without Marginalia
(top) and with it (bottom):

image::projectile-marginalia.png[projectile-find-file without and with Marginalia annotations]

Picking a file by its size or by how recently you touched it, without leaving
the prompt, turns out to be a much bigger deal in day-to-day use than it sounds.

=== Embark actions

Projectile also ships a small integration layer for
https://github.com/oantolin/embark[Embark]. Like the Marginalia support, it's
wired with `with-eval-after-load`, so neither package becomes a dependency - if
you don't have them installed, nothing happens; if you do, it activates on its
own with no configuration.

Two things come out of it. First, `embark-act` on a file candidate targets the
right file. Projectile presents its file candidates relative to the project
root, so acting on one from a buffer whose `default-directory` is a
subdirectory would otherwise resolve against the wrong place. The integration
adds an Embark transformer that expands the candidate against the project root
- but only when the file really does live there, otherwise it defers to
whatever Embark was already doing, so `project-file` completions that aren't
Projectile's behave exactly as before.

Second, acting on a *project* candidate offers project operations rather than
generic file ones. Project prompts (`projectile-switch-project` and friends) use
a `projectile-project` completion category bound to
`projectile-embark-project-map`:

|===
| Key | Action

| kbd:[s] | switch to the project
| kbd:[v] | open the project's VC interface
| kbd:[d] | open the project root in Dired
| kbd:[D] | remove it from the known projects
|===

Acting on a project from the switch prompt, then opening it in Dired:

image::projectile-embark-project.gif[embark-act on a project candidate, showing the project action keymap]

The keymap inherits from `embark-general-map`, so Embark's generic actions
(collect, export, insert, and so on) are available too. Rebind or extend it like
any other keymap:

[source,elisp]
----
(with-eval-after-load 'embark
  (define-key projectile-embark-project-map (kbd "b") #'projectile-ibuffer))
----

Project candidates keep their Marginalia annotations under the new category -
they're directory paths, so Marginalia's file annotator handles them.

=== Custom completion function

You can also set `projectile-completion-system` to a function that accepts a
prompt and a list of choices:

[source,elisp]
----
(setq projectile-completion-system #'my-custom-completion-fn)
(setq projectile-completion-system
      (lambda (prompt choices)
        ;; ...
        ))
----

An example of a custom completion function is
https://gist.github.com/rejeep/5933343[this one], which only shows the file name
(not including path) and, if the selected file is not unique, follows up with a
completion over names relative to the project root.

== Project-specific compilation buffers

This affects all commands built on top of `projectile--run-project-cmd` like:

- `projectile-configure-project`
- `projectile-run-project`
- `projectile-test-project`
- `projectile-install-project`
- `projectile-package-project`

Normally, the buffers created by those commands would be shared (overwritten)
between projects, but it's also possible to make the compilation buffer names
project-specific. This requires that the user set:

[source,elisp]
----
(setq projectile-per-project-compilation-buffer t)
----

Both of these degrade properly when not inside a project.

Within one project those commands still share a buffer, since they all use
`compilation-mode` - so running the tests discards the build output. To keep
them apart, name the buffer after the command as well:

[source,elisp]
----
(setq projectile-per-command-compilation-buffer t)
----

That gives you `+*compilation*<test>+` and `+*compilation*<compile>+`, or
`+*compilation*<my-project:test>+` with both options enabled. Running the test
at point shares the test buffer. Named tasks already get a buffer each, named
after the task.

== Limit the number of project file buffers

Projectile can be configured to keep a maximum number of file buffers of a project
that are opened at one point. The custom variable `projectile-max-file-buffer-count`
can be set to an integer that will be the buffer count cap. If this limit is
reached, by opening a new file, Projectile will close the least recent buffer of
the current project. If the variable is `nil`, there will be no cap on the buffer
count.

[source,elisp]
----
(setq projectile-max-file-buffer-count 10)
----

Note that special project buffers (e.g. compilation, `dired`, etc) are not
affected by this setting.

== Mode line indicator

By default the minor mode indicator of Projectile appears in the form
" Projectile[ProjectName:ProjectType]". This is configurable via several custom variables:

* `projectile-mode-line-prefix` (by default " Projectile") controls the static part of the mode-line
* `projectile-dynamic-mode-line` (by default `t`) controls whether to display the project name & type part of the mode-line
* `projectile-mode-line-function` (by default `projectile-default-mode-line`) controls the actual function to be invoked to generate the mode-line. If you'd like to show different info you should supply a custom function to replace the default, for example `(setq projectile-mode-line-function '(lambda () (format " Proj[%s]" (projectile-project-name))))`

NOTE: The project name & type will not appear when editing remote files
 (via TRAMP), as recalculating the project name is a fairly slow operation there
 and would slow down a bit opening the files. They will also not appear for
 non-file buffers, as they get updated via `find-file-hook`.

== Searching

`projectile-search` (kbd:[s-p s s]) searches the project using a *pluggable
backend*.  Projectile ships three backends - `grep`, `ripgrep` and `ag` - and
you pick which one `projectile-search` uses via `projectile-search-backend`:

[source,elisp]
----
;; `auto' (the default) picks the first available backend, favouring ripgrep,
;; then grep (which is always available).  You can also name a specific backend
;; or use `prompt' to be asked each time.
(setq projectile-search-backend 'ripgrep)
----

The dedicated commands `projectile-grep` (kbd:[s-p s g]), `projectile-ripgrep`
(kbd:[s-p s r]) and `projectile-ag` (kbd:[s-p s a]) still exist; they're just
`projectile-search` with a forced backend.

For the `grep` backend, in Git projects you can use `vc-git-grep` instead of
`rgrep`, which tends to be faster as it respects `.gitignore`:

[source,elisp]
----
(setq projectile-use-git-grep t)
----

=== Adding your own search backend

Register a backend with `projectile-register-search-backend`.  It takes a name,
a `:description`, an optional `:available` predicate, and a `:search` function
called with the search term and a flag indicating whether it's a regexp.  For
example, to add https://github.com/Wilfred/deadgrep[deadgrep]:

[source,elisp]
----
(projectile-register-search-backend 'deadgrep
  :description "deadgrep"
  :available (lambda () (require 'deadgrep nil t))
  :search (lambda (term _regexp)
            (deadgrep term (projectile-acquire-root))))

(setq projectile-search-backend 'deadgrep)
----

== Shells, REPLs and terminals

`projectile-run` (kbd:[s-p x r]) opens a shell, REPL or terminal in the project
root using a *pluggable backend*, the same way `projectile-search` works.
Projectile ships `shell`, `eshell`, `ielm`, `term`, `vterm`, `eat` and
`ghostel` backends; `projectile-shell-backend` selects which one is used
(default `eshell`):

[source,elisp]
----
(setq projectile-shell-backend 'vterm)
----

The dedicated commands (`projectile-run-eshell`, `projectile-run-vterm`, ...,
plus the `-other-window` variants) are kept; they're just `projectile-run`
with a forced backend.

Register your own terminal with `projectile-register-shell-backend` - it takes
a name, a `:description`, an optional `:available` predicate, and a `:run`
function called with a new-process flag (the prefix argument) and an
other-window flag:

[source,elisp]
----
(projectile-register-shell-backend 'mistty
  :description "mistty"
  :available (lambda () (require 'mistty nil t))
  :run (lambda (_new-process _other-window)
         (let ((default-directory (projectile-acquire-root)))
           (mistty))))
----

The generic registry machinery behind both `projectile-search` and
`projectile-run` (`projectile-register-backend`) is intended to be reused for
other pluggable command families in the future.

== Project name

The project name displayed in the mode line and used in buffer names is
determined by `projectile-project-name-function`.  The default implementation
uses the project root directory name, but you can provide your own:

[source,elisp]
----
(setq projectile-project-name-function
      (lambda (project-root)
        (file-name-nondirectory
         (directory-file-name project-root))))
----

NOTE: If the variable `projectile-project-name` is set (e.g. via
`.dir-locals.el`), it takes precedence over the function.

== Hooks

Projectile provides several hooks for integrating with your workflow:

[source,elisp]
----
;; Run after a file is opened via projectile-find-file
(add-hook 'projectile-find-file-hook #'my-find-file-setup)

;; Run after a directory is opened via projectile-find-dir
(add-hook 'projectile-find-dir-hook #'my-find-dir-setup)

;; Run right before switching projects
(add-hook 'projectile-before-switch-project-hook #'my-before-switch-setup)
----

If you want to react to *any* change of the current project, not just
explicit invocations of `projectile-switch-project`, use
`projectile-project-changed-functions` (added in Projectile 3.1). Its
functions are also run when you enter another project implicitly, e.g. by
visiting one of its files or directories. Each function is called with the
new project root and the previous one (`nil` when there was none):

[source,elisp]
----
(add-to-list 'projectile-project-changed-functions
             (lambda (new previous)
               (message "Moved from project %s to %s" previous new)))
----

NOTE: Moving to a buffer outside any project doesn't count as a change; the
functions run again only when another project is entered.

== Miscellaneous

=== Verbose messages

By default Projectile echoes informational messages (not just errors).  To
suppress them:

[source,elisp]
----
(setq projectile-verbose nil)
----

=== Menu bar

Projectile adds a menu to the Emacs menu bar by default.  To disable it:

[source,elisp]
----
(setq projectile-show-menu nil)
----

== Project-type-specific configuration

=== CMake

Projectile supports https://cmake.org/cmake/help/git-stage/manual/cmake-presets.7.html[CMake presets]. Preset support is disabled by default, but can be enabled by setting `projectile-enable-cmake-presets` to non-nil. With preset-support enabled Projectile will parse the preset files and present the command-specific presets when executing a lifecycle command. In addition a `*no preset*` option is included for entering the command manually.

NOTE: Preset support requires a CMake version that supports preset and for `json-parse-buffer` to be available.
