vi/vim - custom formatting depending on presence of special file or tag inside code

586 Views Asked by At

Question

Is there a simple/reliable way to have VIM, on a project/directory specific base, either detect a special file (ie: custom .vimrc with a couple settings), or to change run-time settings based on the presence of a special tag/string/hash in a comment at the beginning of a source (.c) or header (.h) file? The string/hash must map to a function/setting in the .vimrc file, and must not contain the actual settings themselves.


Background

I have a mutli-developer project where we all have a common set of code style settings for our various editors ( and , primarily), and we all adhere strictly to these settings, such as newline style (CR versus CR+LF), indentation (length, hard-tabs versus expanded-as-spaces), and so on.


Problem

I'm creating a few new projects that, for reasons beyond our control (ie: static code analysis tool we have to use), will require different style settings than ours. There are ways to bypass this in the static code analysis tool, but there's a non-technical/legal requirement that we avoid disabling "features" of this tool.

For each of these new projects, I would like to somehow make / aware of some special flag, either by the presence of a special file in the root of the project's directory structure, or by a special keyword/tag/hash/etc I could put inside a /* C-style block comment */. When / is aware of the presence of this "trigger", I would want it to invoke a function to override the style settings for newlines, indentation, etc. If this is possible, is it also possible to have several, mutually exclusive such "triggers" so that everyone has a common .vimrc and the project determines which style to utilize?


Question - redux

Is there a straightforward way to accomplish this?

4

There are 4 best solutions below

5
On BEST ANSWER

... to change run-time settings based on the presence of a special tag/string/hash in a comment at the beginning of a c source (.c) or header (.h) file?

Yes, they're called modelines. http://vim.wikia.com/wiki/Modeline_magic

They can appear at the start or end of files.

An example from some C sources of mine:

/* vim:ft=c:expandtab:sw=4:ts=4:sts=4:
 */

See :help modeline in vim for more info.

0
On

One solution: modelines (:help modeline) for Vim and file variables for Emacs.

Those are special comments you put in your files that are interpreted by your editor. You can use them to set indent style, file encoding, etc.

In my opinion, modelines are ugly noise.

One solution for Vim: .exrc (:help 'exrc').

You can put your project-specific settings in a .exrc file at the root of your project. The manual claims this solution is insecure but I fail to see how normal functioning adult could be beaten by it. YMMV.

One solution for Vim: directory-specific autocommands.

That's the safer alternative mentioned at the end of :help 'exrc' but it requires each contributor to add stuff to his own vimrc so… not that useful I guess.

The definitive solution: editorconfig.

You put your settings in a .editorconfig at the root of your project and let each contributor's IDE/editor deal with it.

0
On

Central configuration

If it's okay to configure the specific commands / local exceptions centrally, you can put such autocmds into your ~/.vimrc:

:autocmd BufRead,BufNewFile /path/to/dir/* setlocal ts=4 sw=4

It is important to use :setlocal instead of :set, and likewise :map <buffer> ... and :command! -buffer ....

On the other hand, if you want the specific configuration stored with the project (and don't want to embed this in all files via modelines), you have the following two options:

Local config with built-in functionality

If you always start Vim from the project root directory, the built-in

:set exrc

enables the reading of a .vimrc file from the current directory. You can place the :set ts=4 sw=4 commands in there.

Local config through plugin

Otherwise, you need the help of a plugin; there are several on vim.org; I can recommend the localrc plugin (especially with my own enhancements), which even allows local filetype-specific configuration.

Note that reading configuration from the file system has security implications; you may want to :set secure.

0
On

I've covered the main alternatives in this answer : https://stackoverflow.com/a/456889/15934 (Yes, your question is almost a duplicate: different formulation, but same solutions).

  • Modelines are really limited: you have to use a plugin to set things that are not vim options.

  • .exrc doesn't look behind the current directory

  • editorconfig is restricted to very specific options: don't expect to forward plugin specifications like where compilation directories are (this is how I support multiple compilation modes with CMake -- others prefer playing with ccache and tuning the CMakeCache, but this doesn't work well when using g++ and clang++ one after the other), how the linter shall be called, your naming conventions...

  • autocommand don't scale and cannot be ported easily from one directory to the other.

  • In the end, the best solutions are plugin based IMO: There a plenty plugin solutions see the non exhaustive list at the end of my local_vimrc plugin's README

  • Note also that since my previous answer, I've initiated another experiment to simplify project management. For instance, I introduce p:variables which are variables shared among all buffers belonging to a project.