3

I have a project consisting of files that Vim doesn't recognize by default, but has support for highlighting and indentation. I would like to have a vimrc file or a vimmodeline (or whatever similar) whose scope is similar to that of .gitignore to Git, such that it'll apply to all files under the directory it's in.

There are too many files to handle so it's not practical to append a mode line to each one.

3

There are a few options for you, depending on what exact settings you'd like to tweak, how you'd like to manage them and whether you're worried about untrusted settings.

Use "editorconfig"

If the kinds of settings you would like to set are related to indentation style, tab size, file format and charset, then you might want to look into "editorconfig", which is a cross-editor standard to specify this kind of settings in a specific project, and have all editors follow that configuration.

The "editorconfig" specification allows projects to request different settings depending on file extensions or names within the project. (So you can have Makefiles using TABs, your Python scripts using 4 spaces and your shell scripts using 2 spaces for indentation.)

You need a plug-in to use "editorconfig" in Vim. The official website provides one, but personally I'd recommend sgur/vim-editorconfig, which is written in pure Vimscript, so you don't need to worry about external dependencies too much.

Since "editorconfig" aims at cross-editor compatibility, it's quite limited in what it does, so if you want is consistent whitespace, file format (DOS vs. Unix) and encoding (Unicode utf-8, etc.), then "editorconfig" is for you. Otherwise, maybe not.

An autocmd in your .vimrc

Second choice is to manage project settings from your actual vimrc. If you have a single project, or at most a handful, that need this kind of setup, then that's possibly an option.

In order to do that, use :autocmd, looking for events BufRead and BufNewFile and use a pattern that matches files under your project tree.

(Always put your :autocmds inside an :augroup, since then they won't be duplicated whenever you :source your vimrc again.)

For example:

augroup myproject
  autocmd!
  autocmd BufRead,BufNewFile ~/myproject/* set ft=myproject
  autocmd BufRead,BufNewFile ~/myproject/*.py set ft=mypython
augroup END

This will set the filetype to mypython for all the files with the py extension in your project, and the myproject filetype for all other files under that project.

See :help file-pattern for more details in how you can specify the matching pattern for the BufRead and BufNewFile events. In particular, the * will match path separators (/), so this will work recursively in subdirectories of your project.

It's likely that you might have multiple autocmds fighting for the filetype of a specific type (for example, Vim default runtime will try to make the *.py files use the python filetype.) Which one will win will depend on a few factors, including ordering. Typically the rules in your vimrc will be the earliest ones, but that's no longer the case if you source your vimrc and recreate those rules.

You have three options to set the filetype:

  • set filetype=mypython: This will always set the filetype, at that point. It will only be lost if it's overwritten by another set filetype=... command. This is what you should typically use in your setup if you want to enforce your filetype.
  • setfiletype mypython: This will set the filetype, but only if it was unset at that point. This is typically what Vim's basic runtime and also plugins will use, so if you make your own setting, it will be stronger than these. (So, if all plugins are behaving correctly, you should be good!)
  • setfiletype FALLBACK mypython: This will set the filetype, only if it's still unset. But if there's another setfiletype the latter will override it. So this is a good way to set a fallback filetype, if the file doesn't get one in a different way.

You probably want either option 1 (if you want to control the final filetype), or option 3 (if you just want a fallback, for files that don't otherwise get a filetype.)

Finally, once you set filetypes, you can use the normal per-filetype configuration to set specific options and configure keybindings and commands for them. Just create the appropriate scripts under ftplugin/ in your ~/.vim/ directory, named after your filetype, and add your setlocal, nnoremap <buffer>, etc. commands there.

Using 'exrc' and 'secure'

You could enable the 'exrc' option in your vimrc. If you do so, make sure you also enable 'secure', which typically needs to be set at the end of the vimrc file.

set exrc
set secure

This will instruct Vim to read a vimrc file (.vimrc or _vimrc) from your current directory. So you could use this to set a per-project vimrc.

If you always cd to the top of the project, and refer to files in subdirectories by their full path, then a single .vimrc at the top of the project might be enough. If you typically cd into subdirectories, you might want to keep symlinks to the .vimrc at the top from subdirectories (which is not great, but possibly something you could automate.)

There are many drawbacks with this solution, such as still having to solve subdirectories, having to be inside the project tree when you start Vim and also security concerns about sourcing .vimrc files from the tree (you're setting 'exrc' globally, so Vim will try to open any .vimrc you happen to stumble upon.)

This is a terrible idea. Don't go with this one!

Roll your own

Finally, you could roll your own solution. That might take some Vimscript to do, but you can probably come up with something that fits your exact requirements.

You can probably get some inspiration from "editorconfig" in searching for the config file up the tree, and maybe its basic file format. (Perhaps just extend it for whatever else you might want to configure? Perhaps so that you can set a 'filetype'?)

This would take a bit of work, but I think the idea has potential.

Hopefully one of these options will be close enough to what you'd like.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.