1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
|
= 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.
== Project indexing method
Projectile has three 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 two (`hybrid` and
`alien`) rely on external commands like `find`, `git`, etc to
obtain the list of files in a project.
The `alien` indexing method maximizes the speed of the `hybrid` indexing method.
This means that Projectile will not do any processing or sorting of the files
returned by the external commands and you're going to get the maximum
performance possible. This behaviour makes a lot of sense for most people, as
they'd typically be putting ignores in their VCS config (e.g. `.gitignore`) and
won't care about any additional ignores/unignores/sorting that Projectile might
also provide.
NOTE: By default the `alien` method is used on all operating systems except Windows.
Prior to Projectile 2.0 `hybrid` used to be the default (but to make things
confusing `hybrid` used to be known as `alien` back then).
To force the
use of native indexing in all operating systems:
[source,elisp]
----
(setq projectile-indexing-method 'native)
----
To force the use of hybrid indexing in all operating systems:
[source,elisp]
----
(setq projectile-indexing-method 'hybrid)
----
To force the use of alien indexing in all operating systems:
[source,elisp]
----
(setq projectile-indexing-method 'alien)
----
This can speed up Projectile in Windows significantly (especially on
big projects). The disadvantage of this method is that it's not well
supported on Windows systems, as it requires setting up some Unix
utilities there. If there's a problem, you can always use `native`
indexing mode.
=== Alien indexing
The alien indexing works in a pretty simple manner - it simply shells
out to a command that returns the list of files within a project.
For version-controlled projects by default Projectile will use the
VCS itself to obtain the list of files. As an example, here is the
command that Projectile uses for Git projects:
----
git ls-files -zco --exclude-standard
----
For every supported VCS there's a matching Projectile defcustom holding the command
to invoke for it (e.g. `projectile-git-command`, `projectile-hg-command`, etc).
WARNING: If you ever decide to tweak those keep in mind that the command should always be returning
the list of files **relative** to the project root and the resulting file list should be 0-delimited
(as opposed to newline delimited).
For non-VCS projects Projectile will invoke whatever is in `projectile-generic-command`. By default that's:
----
find . -type f -print0
----
TIP: It's a great idea to install https://github.com/sharkdp/fd[fd] which is much faster than `find`.
If `fd` is found, projectile will use it as a replacement for `find`.
== Sorting
You can choose how Projectile sorts files by customizing `projectile-sort-order`.
NOTE: If Alien indexing is set, files are not sorted by Projectile at all.
The default is to not sort files:
[source,elisp]
----
(setq projectile-sort-order 'default)
----
To sort files by recently opened:
[source,elisp]
----
(setq projectile-sort-order 'recentf)
----
To sort files by recently active buffers and then recently opened files:
[source,elisp]
----
(setq projectile-sort-order 'recently-active)
----
// These URLs below are in HTML so that the parentheses in the URL fragments are properly recognised.
To sort files by https://en.wikipedia.org/wiki/MAC_times#Modification_time_(mtime)[modification time] (mtime):
[source,elisp]
----
(setq projectile-sort-order 'modification-time)
----
To sort files by https://en.wikipedia.org/wiki/MAC_times#Access_time_(atime)[access time] (atime):
[source,elisp]
----
(setq projectile-sort-order 'access-time)
----
== 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:
[source,elisp]
----
(setq projectile-enable-caching t)
----
At this point you can try out a Projectile command such as kbd:[s-p f] (kbd:[M-x] `projectile-find-file` kbd:[RET]).
Running kbd:[C-u s-p f] will invalidate the cache prior to
prompting you for a file to jump to.
Pressing kbd:[s-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.
Normally the cache lasts for the duration of your Emacs session.
If you want to cache to persist between Emacs sessions you
should set this option to `'persistent`.
[source,elisp]
----
(setq projectile-enable-caching 'persistent)
----
Now the project cache is persistent and will be preserved during Emacs restarts.
Each project gets its own cache file, that will be placed in the root folder of the
project. The name of the cache file is `.projectile-cache.eld` by default, but you can tweak it
if you want to:
[source,elisp]
----
(setq projectile-cache-file "foo.eld")
----
The cache file will be loaded automatically in memory the first time you trigger
a "find file" operation for the project it belongs to.
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`.
NOTE: Prior to Projectile 2.9 the cache for all projects was serialized to the same file.
In Projectile 2.9 this was changed and now each project has its own cache file relative to
the project's root directory.
When `projectile-mode` is enabled Projectile will auto-update the project cache when files
within are added or deleted from within Emacs. (this is achieved by file hooks) This behavior
can be disabled like this:
[source,elisp]
----
(setq projectile-auto-update-cache nil)
----
One last thing - the project cache will be auto-invalidated if you're using
`.projectile` and it's last modification time is more recent than the time at
which the cache file was last updated.
=== File exists cache
Projectile does many file existence checks since that is how it identifies a
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:
[source,elisp]
----
(setq projectile-file-exists-remote-cache-expire nil)
----
To change the remote file exists cache expire to 10 minutes use this snippet
of code:
[source,elisp]
----
(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:
[source,elisp]
----
(setq projectile-file-exists-local-cache-expire (* 5 60))
----
== Using Projectile Commands Outside of Projects 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 Commander, 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.
=== `projectile-commander`
NOTE: This is the recommended option for people who find themselves often needing
to invoke a different action on project switch.
With this setting, after selecting a project to switch to, you'll be prompted to specify the action to take with a 1-character mnemonic.
|===
| Keybinding | Description
| kbd:[?]
| Commander help buffer.
| kbd:[D]
| Open project root in dired.
| kbd:[R]
| Regenerate the project's etags/gtags.
| kbd:[T]
| Find test file in project.
| kbd:[V]
| Browse dirty projects
| kbd:[a]
| Run ag on project.
| kbd:[b]
| Switch to project buffer.
| kbd:[d]
| Find directory in project.
| kbd:[e]
| Find recently visited file in project.
| kbd:[f]
| Find file in project.
| kbd:[g]
| Run grep on project.
| kbd:[j]
| Find tag in project.
| kbd:[k]
| Kill all project buffers.
| kbd:[o]
| Run multi-occur on project buffers.
| kbd:[r]
| Replace a string in the project (running with kbd:[C-u] will allow users to select file name patterns and extensions).
| kbd:[s]
| Switch project.
| kbd:[v]
| Open project root in vc-dir or magit.
|===
=== `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.
== Completion Options
Projectile supports all major minibuffer completion packages that
exist today. Normally it will just detect what you're using (e.g. `ivy`),
but you can force a particular completion system via the variable
`projectile-completion-system`.
NOTE: Historically `projectile-completion-system` defaulted to `ido`,
but this was changed in version 2.3. You may need to enable `ido-mode`
in your Emacs configuration if updating from an older version of Projectile.
=== Auto (default)
By default Projectile detects the completion system in use, based
on the mode variables `ido-mode`, `ivy-mode` and `helm-mode`.
If none of those is activated, the `default` completion system is used.
Unless for some reason you want to use a different completion system for
Projectile than for the rest of Emacs (e.g. you normally use `icomplete-mode`,
but want to use `ido-mode` with Projectile), you'll probably don't want to
select a particular completion system manually.
=== Basic (Emacs's default)
Select this option if you want to use Emacs's standard completion (based on `completing-read`):
[source,elisp]
----
(setq projectile-completion-system 'default)
----
TIP: You might want to combine default completion with `icomplete-mode` for optimum results.
Emacs 27 added `fido-mode` to `icomplete`.
If you are using `fido-mode`, Projectile will
use the `default` completion system. The same holds for `vertico` which also rely
on the `default` completion system.
=== Ido
The `ido` completion system is extremely popular and it is built into Emacs.
[source,elisp]
----
(setq projectile-completion-system 'ido)
----
As noted above, Projectile will auto-detect `ido-mode` if enabled, so the
above configuration is not needed most of the time.
TIP: As already noted above if you're going to use the `ido` completion it's
**extremely highly** recommended that you install the optional
https://github.com/lewang/flx[flx-ido package], which provides a much
more powerful alternative to ``ido``'s built-in `flex` matching.
=== Ivy (recommended)
Another completion option is https://github.com/abo-abo/swiper[ivy]:
[source,elisp]
----
(setq projectile-completion-system 'ivy)
----
As noted above, Projectile will auto-detect `ivy-mode` if enabled, so the
above configuration is not needed most of the time.
=== Custom Completion Function
You can also set `projectile-completion-system` to a function:
[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 show
the file name (not including path) and if the file selected is not
unique, another completion with names relative to project root
appears.
== 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.
== 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-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.
== Regenerate tags
To be able to regenerate a project's tags via `projectile-tags-command`, you
should install and add to the PATH
http://ctags.sourceforge.net/[Exuberant Ctags] instead of a plain ctags, which
ships with Emacs distribution.
== 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`:
[source,elisp]
----
(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: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`.
== 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.
|