/projectile

Project Interaction Library for Emacs

Primary LanguageEmacs Lisp

License GPL 3 Build Status Gittip

Synopsis

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 or gtags (requires gtags).
  • visit project in dired
  • run make in a project with a single key chord

Here's a glimpse of Projectile in action:

Projectile Screenshot

Installation

The recommended way to install Projectile is via package.el.

package.el

MELPA

You can install a snapshot version of Projectile from the MELPA repository. The version of Projectile there will always be up-to-date, but it might be unstable (albeit rarely).

MELPA Stable

You can install the last stable version of Projectile from the MELPA Stable repository.

el-get

Projectile is also available for installation from the el-get package manager.

Emacs Prelude

Projectile is naturally part of the Emacs Prelude. If you're a Prelude user - Projectile is already properly configured and ready for action.

Usage

Basic setup

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.

Indexing method

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, by default the second method is used on all operating systems except Windows. To force the use of native indexing:

(setq projectile-indexing-method 'native)

Caching

Project files

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.

You can purge an individual file from the cache with M-x projectile-purge-file-from-cache or an entire directory with M-x projectile-purge-dir-from-cache.

File exists cache

Projectile does many file existence checks since that is how it identifies an project root. Normally this is fine, however in some situations the file system speed is much slower than usual and can make emacs "freeze" for extended periods of time when opening files and browsing directories.

The most common example would be interfacing with remote systems using TRAMP/ssh. By default all remote file existence checks are cached

To disable remote file exists cache that use this snippet of code:

(setq projectile-file-exists-remote-cache-expire nil)

To change the remote file exists cache expire to 10 minutes use this snippet of code:

(setq projectile-file-exists-remote-cache-expire (* 10 60))

You can also enable the cache for local file systems, that is normally not needed but possible:

(setq projectile-file-exists-local-cache-expire (* 5 60))

Using Projectile everywhere

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. :-)

Switching projects

When running projectile-switch-project (C-c p s) Projectile invokes the command specified in projectile-switch-project-action (by default it is projectile-find-file).

When projectile-remember-window-configs is t (default is nil), the most recent window configuration of the target project is restored instead of calling projectile-switch-project-action. If the target project has no window configuration in the current editing session, projectile-switch-project-action is otherwise invoked as described above.

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

projectile-find-file

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-dired
(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
(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

(setq projectile-find-dir-includes-top-level t)

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

Completion Options

Ido

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.

Grizzl

Another completion option is grizzl:

(setq projectile-completion-system 'grizzl)

Projectile Screenshot

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).

Basic (Emacs's default)

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.

Custom Completion Function

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.

Regenerate tags

To be able to regenerate a project's tags via projectile-tags-command, you should install and add to the PATH Exuberant Ctags instead of a plain ctags, which ships with Emacs distribution.

Interactive Commands

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 F Display a list of all files in all known projects.
C-c p 4 f Jump to a project's file using completion and show it in another window.
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 4 d Switch to a project directory and show it in another window.
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 s g Run grep on the files in the project.
M-- C-c p s g Run grep on projectile-grep-default-files in the project.
C-c p v Run vc-dir on the root directory of the project.
C-c p b Display a list of all project buffers currently open.
C-c p 4 b Switch to a project buffer and show it in another window.
C-c p 4 C-o Display a project buffer in another window without selecting it.
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 j Find tag in project's 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 s a Runs ack on the project. Requires the presence of ack-and-a-half.
C-c p s s Runs ag on the project. Requires the presence of ag.el.
C-c p ! Runs shell-command in the root directory of the project.
C-c p & Runs async-shell-command in the root directory of the project.
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 t Toggle between an implementation file and its test file.
C-c p 4 t Jump to implementation or test file in other window.
C-c p z Adds the currently visited file to the cache.
C-c p p Display a list of known projects you can switch to.
C-c p S Save all project buffers.
C-c p m Run the commander (an interface to run commands with a single key).
C-c p ESC Switch to the most recently selected projectile buffer.

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"))

It is also possible to add additional commands to projectile-command-map referenced by the prefix key in projectile-mode-map. You can even add an alternative prefix for all commands. Here's an example that adds super-p as the extra prefix:

(define-key some-keymap (kbd "s-p") 'projectile-command-map)

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.

Ignoring files

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.

Customizing project root files

You can set the values of projectile-project-root-files, projectile-project-root-files-top-down-recurring, projectile-project-root-files-bottom-up and projectile-project-root-files-functions to customize how project roots are identified.

To customize project root files settings:

M-x customize-group RET projectile RET

Helm Integration

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 :-)

Helm-Projectile Screenshot

Work with Perspective Mode

Perspective is a minor mode that provides the ability to manage different workspaces. If you need to open many projects at the same time, prerspective can help you keep each project related buffers and windows setting separate from other projects, similar to multiple spaces on MacOS, which allows you to focus on the files of the current active project.

A picture says a thousand words. See below screenshot to get a concrete idea.

Only current project related files showing in minibuffer when I call ido-swith-buffer, and an indicator in mode line tells me which project that I'm in.

Persp-Projectile Screenshot 1

When I switch to a different project, I get a clean 'perspective'.

Persp-Projectile Screenshot 2

To integrate perspective with projectile, first of all, you need to install perspective. You can install it by:

M-x package-install

Then type perspective in the minibuffer, as below:

Install package: perspective

Secondly, make sure persp-projectile.el is in your Emacs load path. Then require it in your init file.

(persp-mode)
(require 'persp-projectile)

You're ready to go! Try the interactive command projectile-persp-switch-project, or you may also bind it to some handy keybinding.

(define-key projectile-mode-map (kbd "s-s") 'projectile-persp-switch-project)

Idle Timer

Projectile can be configured to run the hook projectile-idle-timer-hook every time Emacs is in a project and has been idle for projectile-idle-timer-seconds seconds (default is 30 seconds). To enable this feature, run:

M-x customize-group RET projectile RET

and set projectile-enable-idle-timer to non-nil. By default, projectile-idle-timer-hook runs projectile-regenerate-tags. Add additional functions to the hook using add-hook:

(add-hook 'projectile-idle-timer-hook 'my-projectile-idle-timer-function)

Mode line indicator

By default the minor mode indicator of Projectile appears in the form "Projectile[ProjectName]". The "Projectile" prefix is configurable using the variable projectile-mode-line-lighter.

Caveats

  • 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.

Would you like to know more?

Check out the Projectile's project page.

Known issues

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. :-)

Contributors

Here's a list of all the people who have contributed to the development of Projectile.

Contribution

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

I'm also accepting financial contributions via gittip.

Support via Gittip

Changelog

A fairly extensive changelog is available here.

Freenode

If you're into IRC you can visit the #projectile channel on Freenode.

Bugs & Improvements

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