vim modelines in git config

I’m working on different Open Source projects and most of them have different coding style guidelines. Mostly spaces or tabs or different tabwidth. The easiest thing would be to store these information in the git config of the project. So here is a easy and secure way to have modelines in the git config.

So first I set the modelines (here for the Samba project):
git config --add vim.modeline "tabstop=8 shiftwidth=8 noexpandtab cindent"

or for a specific language:
git config --add vim.modeline-python "tabstop=4 shiftwidth=4 expandtab"

Then copy this plugin into ~/.vim/plugin folder.

The modeline you defined in your git config will be appended to the :setlocal command of vim. It only allows a limited set of setlocal commands to be used. It will not execute any arbitrary code and you probably are the only person modifying the git config. You can change the allowed commands by adding the following to your ~/.vimrc file

    let g:git_modelines_allowed_items = [
                \ "textwidth",   "tw",
                \ "softtabstop", "sts",
                \ "tabstop",     "ts",
                \ "shiftwidth",  "sw",
                \ "expandtab",   "et",   "noexpandtab", "noet",
                \ "filetype",    "ft",
                \ "foldmethod",  "fdm",
                \ "readonly",    "ro",   "noreadonly", "noro",
                \ "rightleft",   "rl",   "norightleft", "norl",
                \ "cindent",     "cin",  "nocindent", "nocin",
                \ "smartindent", "si",   "nosmartindent", "nosi",
                \ "autoindent",  "ai",   "noautoindent", "noai",
                \ "spell",
                \ "spelllang"
                \ ]

* New script which only allows a specified list
* Use sandbox command for set
* Added git repository
* Set only locally when reading the buffer

You may also like...

10 Responses

  1. Stefan says:

    Or you could use the DetectIndent plugin.

  2. Leif says:

    I wrote something similar to scratch an itch. Instead of storing the vim options in your git config it stores them in the .vimrc at the base of your git project.

  3. @Leif Looks like you introduce a security hole into your system. Someone could trick you to checkout a git repository which already has a .vimrc file in it. If you then open a file in that git project you would execute whatever arbitrary code the .vimrc file includes.

    My approach is more secure here, cause a) you’re the only one who controls the git config file and b) it is limited to the :set command of vim 🙂

  4. Martian says:

    Very dangeruous! You should at least consider using exe “:sandbox set “…

    Attack: I will just put .git in a subdirectory of a project and your extension will execute anything on yourt machine with modeline like ‘ ts=4 | !ls -l ~/.ssh/id_rsa’

    — Martian

  5. Martian says:

    Correcting myself: `:sandbox exe “set …”`! Not `:exe “sandbox set …”` which still works!

  6. Marian, I’ve created a plugin which checks the set commands against a list of allowed commands.

  7. Martian says:

    Looks better! 🙂

    2 more things you might consider and get lot of fame on github 😉

    It may be better to hook it as autocommand when file is loaded. You should use :setlocal instead of :set in such case. The plugin work only when opening vim inside git tree and for example I am sometimes wandering in single session among two-three related projects.
    Also if you have any plugin setting options on a per filetype basis, it will override those set in vim.modeline.

    It would be nice to define modeline on per filetype basis: many projects are a mix of different languages and e.g. python “standard” (PEP8) says 4 spaces (sw=4 et) while some other files use different settings (for example Makefile: sw=8 noet)

    Getting complicated…

  8. @Martian I’ve implemented the first suggestion. The second is nice but bit too complex for me and my little vim scripting knowledge.

    Hoewever as it is a git repo now, patches are welcome.

  9. Wladimir says:

    Thanks, this is what I was looking for, and in my opinion the best way to set code style settings per project. I did make the following change:

    let git_path = shellescape(expand("%:p:h"))
    let git_config_modeline = system("cd " . git_path . "&& git config --get vim.modeline." . &ft)
    let git_config_modeline = system("cd " . git_path . "&& git config --get vim.modeline")

    This executes git in the path of the buffer instead of the current directory of vim, which can be useful when having files from multiple projects open in one vim session.

  10. Could you update your git repo and send a git patch? 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *