Can I get the Vim Ctrlp plugin to ignore a specific folder in one project?

The Vim Ctrlp plugin has a way to globally ignore certain folder names. Eg:

let g:ctrlp_custom_ignore = '\v[\/]\.(git|hg|svn)$'

However, I have an ignore rule that's specific to one project. I would like something more like a .gitignore file.

Is there a way to ignore a specific folder in a specific project without modifying my global configuration?


Solution 1:

Use a custom listing command

Ctrlp lets you tell it what command to use to get a list of files in the folder. So if you wanted to exclude anything named beets.txt, you could do:

let g:ctrlp_user_command = 'find %s -type f | grep -v "beets.txt"'

That's global, but it starts to point toward the answer: supply your own shell command.

Even better, Ctrlp lets you supply multiple shell commands with markers, meaning "if you see this marker in the root directory, use this command."

I found this in :help ctrlp, and modified slightly based on the author's comment on an issue.

let g:ctrlp_user_command = {
  \ 'types': {
    \ 1: ['.git', 'cd %s && git ls-files --cached --exclude-standard --others'],
    \ 2: ['.hg', 'hg --cwd %s locate -I .'],
    \ },
  \ 'fallback': 'find %s -type f'
  \ }

This means: "If you see .git in the folder, use git ls-files.... Otherwise, if you see .hg, use hg --cwd..., otherwise use a regular find."

So, to ignore a specific folder in one project, devise a command that will ignore that folder, then place a unique marker in that project to let Ctrlp that you want to use your special command here.

(In my case, I actually wanted to ignore files that were in .gitignore, so the git ls-files command above works for me.)

Solution 2:

If you are using the Silver Searcher backend for CtrlP (which is far faster), just add an .agignore file to your project directory in the same format as a .gitignore:

.git/
.hg/
.svn/

Alternatively, keep a global ~/.agignore file.

Add the Silver Searcher as the backend with this in your .vimrc

let g:ctrlp_user_command = 'ag %s -l --nocolor --hidden -g ""'

Solution 3:

Specifies intentionally untracked files in a file

To solve this with a file like .gitignore (based in the Nathan grep solution), I created a file named .ctrlpignore and put the patterns that should be ignored, separated by lines:

node_modules/
\.log$
...

And my ctrlp configuration:

let g:ctrlp_user_command = 'find %s -type f | grep -v "`cat .ctrlpignore`"'

Maybe the .gitignore itself can be used to ignore the files in ctrlp, not needing to create a new file to do almost the same thing.

Solution 4:

As Wagner Andrade said, using a seperate .ctrlpignore would be a good idea.

A more robust and convenient vim setting is like this:

let g:ctrlp_user_command = 'cd %s;
  \ commonfilter="\.(jpg|bmp|png|jar|7z|zip|tar|gz|tgz|bz)$";
  \ if [ ! -r ".ctrlpignore" ]; then
  \   find . -type f | grep -Evi "$commonfilter";
  \ else
  \   find . -type f | grep -vF "$(cat .ctrlpignore)" | grep -Evi "$commonfilter";
  \ fi'

.ctrlpignore can be put in any dir that would be recognized as a root dir by ctrlp. Here is an example, every line is starting with ./

vim ~/.ctrlpignore

./Desktop
./R
./.vim
./.local/lib
.....

Note:

  1. grep -F will interpret pattern, ex. './.tmp', as a fixed string if you don't want your './ptmp' be filtered out. There are still some trivial bugs: './.tmp' will also filter out './.tmp2'. Forget it, I don't like \.

  2. g:ctrlp_custom_ignore will be ignored if g:ctrlp_user_command is set. Those could be done in a more complex g:ctrlp_user_command

  3. white-list instead of black-list is also possible. More convenient if implemented in a seperate script