Projectile is a project interaction library for Emacs. Its goal is to
provide a nice set of features operating on a project level without
introducing external dependencies(when feasible). For instance -
finding project files has a portable implementation written in pure
Emacs Lisp without the use of GNU find
(but for performance sake an
indexing mechanism backed by external commands exists as well).
Projectile tries to be practical - portability is great, but if some external tools could speed up some task substantially and the tools are available, Projectile will leverage them.
This library provides easy project management and navigation. The
concept of a project is pretty basic - just a folder containing
special file. Currently git
, mercurial
, darcs
and bazaar
repos
are considered projects by default. So are lein
, maven
, sbt
,
rebar
and bundler
projects. If you want to mark a folder manually
as a project just create an empty .projectile
file in it. Some of
Projectile's features:
- jump to a file in project
- jump to a directory in project
- jump to a file in a directory
- jump to a project buffer
- jump to a test in project
- toggle between code and its test
- jump to recently visited files in the project
- switch between projects you have worked on
- kill all project buffers
- replace in project
- multi-occur in project buffers
- grep in project
- regenerate project etags
- visit project in dired
- run make in a project with a single key chord
Here's a glimpse of Projectile in action:
The recommended way to install Projectile is via MELPA or Marmalade.
Just drop projectile.el
,
dash.el and
s.el somewhere in your
load-path
. I favour the folder ~/.emacs.d/vendor
:
(add-to-list 'load-path "~/emacs.d/vendor")
(require 'projectile)
If you're an Emacs 24 user or you have a recent version of package.el
you can install Projectile from the
Marmalade repository.
If you're an Emacs 24 user or you have a recent version of package.el
you can install Projectile from the
MELPA repository. The version of
Projectile there will always be up-to-date, but it might be unstable
(albeit rarely).
Projectile is naturally part of the Emacs Prelude. If you're a Prelude user - Projectile is already properly configured and ready for action.
You can enable Projectile globally like this:
(projectile-global-mode)
To enable Projectile only in select modes:
(add-hook 'ruby-mode-hook 'projectile-on)
If you're going to use the default ido
completion it's
extremely highly recommended that you install the optional
flx-ido package, which provides a much
more powerful alternative to ido
's built-in flex
matching.
Projectile has two modes of operation - one is portable and is
implemented in Emacs Lisp(therefore it's native to Emacs and is known
as the native indexing method
) and the other relies on external
commands like find
, git
, etc to obtain the list of files in a
project.
Since the native indexing mode is much slower, but default the second method is used on all operating systems except Windows. To force the use of native indexing:
(setq projectile-indexing-method 'native)
Since indexing a big project is not exactly quick (especially in Emacs Lisp), Projectile supports caching of the project's files. The caching is enabled by default whenever native indexing is enabled.
To enable caching unconditionally use this snippet of code:
(setq projectile-enable-caching t)
At this point you can try out a Projectile command such as C-c p f (M-x projectile-find-file RET).
Running C-u C-c p f will invalidate the cache prior to prompting you for a file to jump to.
Pressing C-c p z will add the currently visited file to the cache for current project. Generally files created outside Emacs will be added to the cache automatically the first time you open them.
The project cache is persistent and will be preserved during Emacs restarts.
If you want Projectile to be usable in every directory (even without the presence of project file):
(setq projectile-require-project-root nil)
This might not be a great idea if you start Projectile in your home folder for instance. :-)
When running projectile-switch-project
(C-c p s) Projectile invokes the command specified in
projectile-switch-project-action
(by default it's projectile-find-file
). If you want to use something else alter the value of
projectile-switch-project-action
:
(setq projectile-switch-project-action 'projectile-dired)
By default Projectile uses ido
as it completion system. ido
is
extremely popular and it is built into Emacs.
As already noted above if you're going to use the ido
completion it's
extremely highly recommended that you install the optional
flx-ido package, which provides a much
more powerful alternative to ido
's built-in flex
matching.
Another completion option is grizzl:
(setq projectile-completion-system 'grizzl)
grizzl
's advantage is that it provides good fuzzy completion
(compared to ido
's less than stellar built-in flex matching, but inferior to ido-flx
).
If you don't like ido
and grizzl
you can use regular completion:
(setq projectile-completion-system 'default)
You might want to combine default completion with icomplete-mode
for optimum results.
You can also set projectile-completion-system
to a function:
(setq projectile-completion-system 'my-custom-completion-fn)
(setq projectile-completion-system
(lambda (prompt choices)
;; ...
))
An example of a custom completion function is this one, which only show the file name (not including path) and if the file selected is not unique, another completion with names relative to project root appears.
Here's a list of the interactive Emacs Lisp functions, provided by projectile:
Keybinding | Description |
---|---|
C-c p f | Display a list of all files in the project. With a prefix argument it will clear the cache first. |
C-c p d | Display a list of all directories in the project. With a prefix argument it will clear the cache first. |
C-c p T | Display a list of all test files(specs, features, etc) in the project. |
C-c p l | Display a list of all files in a directory (that's not necessarily a project) |
C-c p g | Run grep on the files in the project. |
C-c p b | Display a list of all project buffers currently open. |
C-c p o | Runs multi-occur on all project buffers currently open. |
C-c p r | Runs interactive query-replace on all files in the projects. |
C-c p i | Invalidates the project cache (if existing). |
C-c p R | Regenerates the projects TAGS file. |
C-c p k | Kills all project buffers. |
C-c p D | Opens the root of the project in dired . |
C-c p e | Shows a list of recently visited project files. |
C-c p a | Runs ack on the project. Requires the presence of ack-and-a-half . |
C-c p c | Runs a standard compilation command for your type of project. |
C-c p p | Runs a standard test command for your type of project. |
C-c p z | Adds the currently visited to the cache. |
C-c p s | Display a list of known projects you can switch to. |
If you ever forget any of Projectile's keybindings just do a:
C-c p C-h
You can change the default keymap prefix C-c p
like this:
(setq projectile-keymap-prefix (kbd "C-c C-p"))
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)
Note that the Super
keybindings are not usable in Windows. Emacs
Prelude already adds those extra keybindings.
If you'd like to instruct Projectile to ignore certain files in a
project, when indexing it you can do so in the .projectile
file by
adding each path to ignore, where the paths all are relative to the
root directory and start with a slash. Everything ignored should be
preceded with a - sign. Alternatively, not having any prefix at all
also means to ignore the directory or file pattern that follows.
Here's an example for a typical Rails application:
-/log
-/tmp
-/vendor
-/public/uploads
This would ignore the folders only at the root of the project. Projectile also supports relative pathname ignores:
-tmp
-*.rb
-*.yml
-models
You can also ignore everything except certain subdirectories. This is useful when selecting the directories to keep is easier than selecting the directories to ignore, although you can do both. To select directories to keep, that means everything else will be ignored.
Example:
+/src/foo
+/tests/foo
Keep in mind that you can only include subdirectories, not file patterns.
If both directories to keep and ignore are specified, the directories to keep first apply, restricting what files are considered. The paths and patterns to ignore are then applied to that set.
Projectile can be integrated with
Helm via
helm-c-source-projectile
source (available in helm-projectile.el
). There is also an example function
for calling Helm with the Projectile file source. You can call it like
this:
M-x helm-projectile
or even better - bind it to a keybinding like this:
(global-set-key (kbd "C-c h") 'helm-projectile)
Obviously you need to have Helm installed for this to work :-)
- Traversing the project directory programmatically (instead of using something like GNU find) is not very fast. On the other hand - it's portable. Unlike find-file-in-project, projectile's jump-to-file will work on any OS.
- Some operations like search(grep) depend (presently) on external
utilities such as
find
.
Check out the Projectile's project page.
Check out the project's issue list a list of unresolved issues. By the way - feel free to fix any of them and sent me a pull request. :-)
Here's a list of all the people who have contributed to the development of Projectile.
All contributions are welcome, as long as they don't break anything :-) To make sure you didn't introduce any regressions it's a good idea to run the tests first.
Install cask if you haven't already, then:
$ cd /path/to/projectile
$ cask
Run all tests with:
$ make test
A fairly extensive changelog is available here.
Bug reports and suggestions for improvements are always welcome. GitHub pull requests are even better! :-)
Together we can create the ultimate project management tool for Emacs.
Cheers,
Bozhidar