Usage
Everything in this section assumes you’ve enabled projectile-mode.
|
Basic setup
In this section we’ll cover the bare minimum of setup you might want to do. Projectile works fine with no setup, but if you tweak the configuration a bit you’ll get more out of it.
Check out the "Configuration" section of the manual for a lot more information about configuring Projectile.
Basic Configuration
Here’s how a typical Projectile configuration would look:
;; Optional: ag is nice alternative to using grep with Projectile
(use-package ag
:ensure t)
;; Optional: Enable vertico as the selection framework to use with Projectile
(use-package vertico
:ensure t
:init
(vertico-mode +1))
;; Optional: which-key will show you options for partially completed keybindings
;; It's extremely useful for packages with many keybindings like Projectile.
(use-package which-key
:ensure t
:config
(which-key-mode +1))
(use-package projectile
:ensure t
:init
(setq projectile-project-search-path '("~/projects/" "~/work/" "~/playground"))
:config
;; I typically use this keymap prefix on macOS
(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
;; On Linux, however, I usually go with another one
(define-key projectile-mode-map (kbd "C-c C-p") 'projectile-command-map)
(global-set-key (kbd "C-c p") 'projectile-command-map)
(projectile-mode +1))
The example above builds upon the simpler setup demonstrated in the "Installation" section.
Automated Project Discovery
To add a project to Projectile’s list of known projects, open a file
in the project. If you have a projects directory, you can tell
Projectile about all of the projects in it with the command M-x
projectile-discover-projects-in-directory.
You can go one step further and set a list of folders which Projectile is automatically going to check for projects on startup.
Recursive discovery is configured by specifying the search depth in a cons cell:
(setq projectile-project-search-path '("~/projects/" "~/work/" ("~/github" . 1)))
You can manually trigger the project
discovery using M-x projectile-discover-projects-in-search-path or you can
use projectile-auto-discover to discover projects on the search path automatically:
(setq projectile-auto-discover t)
| Keep in mind the auto-discovery will be triggered every time you switch projects, so it’s probably not a good idea if you have many projects on your search path. |
Removal of missing projects
From time to time you’ll have projects in your list of known projects that are no longer
around. (e.g. they were removed or renamed) You can either trigger the command
projectile-cleanup-known-projects manually or set the variable
projectile-auto-cleanup-known-projects to t to remove such projects automatically.
(customize-set-variable 'projectile-auto-cleanup-known-projects t)
| If you’re a heavy TRAMP user it’s probably not a good idea to auto-discover and cleanup projects, as the file operations are slower there. |
projectile-cleanup-known-projects is also available under the alias
projectile-forget-zombie-projects, if you’re used to that name from project.el.
To drop a whole group of known projects at once (e.g. after deleting a directory
that held several checkouts) use projectile-forget-projects-under. It prompts
for a directory and removes the known projects that live directly under it; with
a prefix argument it also removes projects nested deeper in the tree.
Minibuffer Completion
Projectile reads through Emacs’s built-in completing-read, so it works with
whatever minibuffer UI you use. It works fine with the stock completion, but
you’re encouraged to pair it with a modern package like vertico (+ consult,
marginalia, orderless) or fido-mode/fido-vertical-mode. See the
Completion Options section for
details, including how to plug in a custom completion function.
Installing External Tools
Windows users can ignore this section unless they are using Emacs via WSL or cygwin.
|
Projectile will work without any external dependencies out of the box. However, if you have various tools installed, they will be automatically used when appropriate to improve performance.
Inside version control repositories, VC tools are used when installed to list files more efficiently. The supported tools include git, hg, fossil, bzr, darcs, pijul, svn, sapling and jujutsu.
Outside version control repositories, file search tools are used when installed for a faster search than pure Elisp. The supported tools include fd and GNU/BSD find.
By default, if fd is installed, it is also used inside Git
repositories as an alternative to git ls-files, because git
ls-files has the limitation that it also lists deleted files until
the deletions are staged, which can be confusing. You can eliminate
the use of fd in this circumstance by setting projectile-git-use-fd
to nil.
To benefit from the projectile-ag and projectile-ripgrep commands
to perform file search, it’s recommended to install
ag (the_silver_searcher) and/or
rg (ripgrep)
You should also install the Emacs packages ag, ripgrep or rg if you want to make use of Projectile’s commands projectile-ag and projectile-ripgrep.
|
Basic Usage
Just open some file in a version-controlled (e.g. git) or a project
(e.g. maven) directory that’s recognized by Projectile and you’re
ready for action. Projectile happens to recognize out of the box every common
VCS and many popular project types for various programming languages.
You can learn more about Projectile’s notion of a project here.
The extent of the support for every VCS differs and Git is the best supported
one. Projectile supports some advanced features like working with Git submodules
and using git-grep instead of GNU grep.
|
You need to know only a handful of Projectile commands to start benefiting from it.
-
Find file in current project (s-p f)
-
Switch project (s-p p) (you can also switch between open projects with s-p q, or jump back to the previously active project with
projectile-switch-to-most-recent-project) -
Grep (search for text/regexp) in project (s-p s g)
-
Replace in project (s-p r)
-
Find references in project (s-p ? or s-p s x)
-
Invoke any Projectile command via the Projectile dispatch menu (s-p m)
-
Toggle between implementation and test (s-p t)
-
Toggle between related files (e.g.
foo.h<→foo.candGemfile<→Gemfile.lock) (s-p a) -
Run a shell command in the root of the project (s-p ! for a sync command and s-p & for an async command)
-
Run various pre-defined project commands like:
-
build/compile project (s-p c c)
-
test project (s-p c t)
-
install project (s-p c i)
-
run project (s-p c r)
-
The next section lists many more commands, but the basics can get you pretty far.
Interactive Commands
Projectile doesn’t have a default key prefix for its commands, but all the examples
in the manual assume you’ve opted for s-p (super-p).
|
Here’s a list of the interactive Emacs Lisp functions, provided by Projectile:
| Keybinding | Description |
|---|---|
s-p f |
Display a list of all files in the project. With a prefix argument it will clear the cache first. |
s-p F |
Display a list of all files in all known projects. |
s-p g |
Display a list of all files at point in the project. With a prefix argument it will clear the cache first. |
s-p 4 f |
Jump to a project’s file using completion and show it in another window. |
s-p 4 g |
Jump to a project’s file based on context at point and show it in another window. |
s-p 5 f |
Jump to a project’s file using completion and show it in another frame. |
s-p 5 g |
Jump to a project’s file based on context at point and show it in another frame. |
s-p d |
Display a list of all directories in the project. With a prefix argument it will clear the cache first. |
s-p 4 d |
Switch to a project directory and show it in another window. |
s-p 5 d |
Switch to a project directory and show it in another frame. |
s-p T |
Display a list of all test files(specs, features, etc) in the project. |
s-p l |
Display a list of all files in a directory (that’s not necessarily a project) |
s-p s s |
Search the project with the configured backend ( |
s-p s g |
Run grep on the files in the project. |
M-- s-p s g |
Run grep on |
s-p s r |
Runs |
s-p s a |
Runs |
s-p s x |
Find references to the symbol at point within the project. Uses internally the |
s-p v |
Run |
s-p b |
Display a list of all project buffers currently open. |
s-p 4 b |
Switch to a project buffer and show it in another window. |
s-p 5 b |
Switch to a project buffer and show it in another frame. |
s-p 4 C-o |
Display a project buffer in another window without selecting it. |
s-p a |
Switch between files with the same name but different extensions. |
s-p 4 a |
Switch between files with the same name but different extensions in other window. |
s-p 5 a |
Switch between files with the same name but different extensions in other frame. |
s-p o |
Runs |
s-p r |
Runs interactive query-replace on all files in the projects. |
s-p i |
Invalidates the project cache (if existing). |
s-p k |
Kills all project buffers. |
s-p D |
Opens the root of the project in |
s-p 4 D |
Opens the root of the project in |
s-p 5 D |
Opens the root of the project in |
s-p e |
Shows a list of recently visited project files. |
s-p left |
Switch to the previous project buffer. |
s-p right |
Switch to the next project buffer. |
s-p E |
Opens the root |
s-p ! |
Runs |
s-p & |
Runs |
s-p c o |
Runs a standard configure command for your type of project. |
s-p c c |
Runs a standard compilation command for your type of project. |
s-p c t |
Runs a standard test command for your type of project. |
s-p c i |
Runs a standard install command for your type of project. |
s-p c r |
Runs a standard run command for your type of project. |
s-p t |
Toggle between an implementation file and its test file. |
s-p 4 t |
Jump to implementation or test file in other window. |
s-p 5 t |
Jump to implementation or test file in other frame. |
s-p z |
Adds the currently visited file to the cache. |
s-p p |
Display a list of known projects you can switch to. |
s-p 4 p |
Switch to a known project and show it in another window (runs |
s-p 5 p |
Switch to a known project and show it in another frame (runs |
s-p q |
Display a list of open projects you can switch to. |
s-p S |
Save all project buffers. |
s-p m |
Open the Projectile dispatch menu (a |
s-p x r |
Start or visit a shell/REPL/terminal for the project, using the configured backend ( |
s-p x e |
Start or visit an |
s-p x i |
Start or visit an |
s-p x t |
Start or visit an |
s-p x s |
Start or visit a |
s-p x g |
Start or visit a |
s-p x v |
Start or visit a |
s-p x x |
Start or visit an |
s-p x G |
Start or visit a |
s-p ESC |
Switch to the most recently selected Projectile buffer. |
If you ever forget any of Projectile’s keybindings just do a:
s-p C-h
Customizing Projectile’s Keybindings
It is possible to add additional commands to
projectile-command-map referenced by the prefix key in
projectile-mode-map. You can add multiple keymap prefixes for all
commands. Here’s an example that adds super-, as a command prefix:
(define-key projectile-mode-map (kbd "s-,") 'projectile-command-map)
You can also bind the projectile-command-map to any other map you’d
like (including the global keymap).
For some common commands you might want to take a little shortcut and
leverage the fairly unused Super key (by default Command on Mac
keyboards and Windows on Win keyboards).
|
Here’s something you can add to your Emacs config:
(define-key projectile-mode-map [?\s-d] 'projectile-find-dir)
(define-key projectile-mode-map [?\s-p] 'projectile-switch-project)
(define-key projectile-mode-map [?\s-f] 'projectile-find-file)
(define-key projectile-mode-map [?\s-g] 'projectile-grep)
The Super keybindings are not usable in Windows, as Windows
makes heavy use of such keybindings itself. Emacs Prelude already adds those
extra keybindings.
|
Dispatch Menu
Projectile ships projectile-dispatch, a transient menu that mirrors
projectile-command-map, for those of you who’d rather pick a command from a
menu than memorize a lot of keybindings. The menu keys match the command map
(e.g. f to find a file, c c to compile, s g to grep). Invoke
it with s-p m.
It’s also wired into project switching: press C-u s-p p and Projectile
opens the dispatch menu after you select a project, so you can run any command
in the project you just switched to. (The same happens if you set
projectile-switch-project-action to projectile-dispatch.)
You can bind the command to whatever you like as well:
(define-key projectile-mode-map (kbd "C-c P") #'projectile-dispatch)
Modifiers
The menu’s Modifiers group holds switches that tweak how the commands run. Toggle one (or more), then trigger a command:
-
-i invalidate cache - rebuild the file cache first (the find file/dir commands)
-
-r regexp search - treat the search term as a regexp (the
search,ripgrepandagcommands) -
-n new process - start a fresh process instead of reusing one (the shells / REPLs)
-
-d display in - cycle the display target through this window / other window / other frame (the file, buffer and project commands)
For example, toggle -d until it shows frame and then press f to
find a file and show it in a new frame; or press -i then f to
invalidate the cache and find a file. This replaces the old dedicated "other
window" and "other frame" menu columns.
projectile-dispatch is powered by transient, which is bundled with
Emacs 28.1+ (Projectile’s minimum), so the menu is always available. It’s bound
to s-p m, and C-u s-p p opens it when switching projects.
|
Using Projectile with project.el
Starting with version 2.7 Projectile bundles some integration with
project.el that makes project.el use Projectile’s
project lookup function (projectile-project-root) and project file
lookup function (projectile-project-files) whenever projectile-mode
is enabled. You can also enable the integration manually like this:
(add-hook 'project-find-functions #'project-projectile)
Beyond root and file lookup, Projectile implements several of project.el’s
backend methods (`project-root, project-files, project-name,
project-buffers, and project-ignores), so commands built on the protocol
(e.g. project-find-regexp) behave correctly for Projectile-managed projects.
| You can read more about the implementation details of the integration here. |
That’s useful as some packages (e.g. eglot) support natively only
project.el's API for project discovery. Fortunately, project.el
makes it easy to install additional project lookup functions and that’s
exactly what Projectile does.
The popular xref package also relies on project.el to infer the project for
helpful commands like xref-find-references (M-?), so it’s useful to teach
it about Projectile’s project discovery logic.
Projectile provides its own alternative to xref-find-references that’s named
projectile-find-references (s-p ? or s-p s-x). It’s a backend-agnostic
textual search: it greps the project for the symbol, scoped to the project root and
honouring Projectile’s ignore configuration (.projectile' and the globally-ignored
files/directories), just like `projectile-grep and friends. Use it when you don’t have
a language server or tags table set up; otherwise xref-find-references gives you
semantic results (and is scoped to the Projectile project too, thanks to the
`project.el' integration above).
|
You can disable the project.el integration like this:
(remove-hook 'project-find-functions #'project-projectile)