112

How do I specify Vim settings for all files under the current directory?

The ideal solution would be if Vim searched for and read a .vimrc in the current directory before searching for ~/.vimrc, and apply the settings there for the entire tree.

I've seen a plugin, but this means the applied settings aren't transparent since they require the plugin to be installed. In contrast, a modeline is transparent since regardless of a user's vimrc or specific vim invocation the modeline settings will be applied for that file.

Things I tried are

  • placing a .vimrc in the working directory
  • :so vimrc in the modeline.

I suppose both don't work for security reasons. I don't need the full power of a vimrc; being bound to settings acceptable by a modeline would suffice. My goal is to make it easier for vimmers to adopt coding standards in a project.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • 2
    Related: [How to make vimrc settings applicable for a directory tree only](http://vi.stackexchange.com/q/2094/467) at Vim SE – kenorb Feb 22 '15 at 13:09

11 Answers11

97

You can put something like this in $VIM/vimrc

autocmd BufNewFile,BufRead /path/to/files/* set nowrap tabstop=4 shiftwidth=4
sth
  • 222,467
  • 53
  • 283
  • 367
  • 1
    This is recursive, but only with the *. If you try to reduce it to /path/to/files/ or /path/to/files it won't work. – SystemParadox Feb 09 '12 at 22:42
  • 1
    This is great if your project has a tree of files written with "noexpandtab" and another tree with all files "expandtab" (e.g. CodeIgniter). You can set the proper action for files in each tree individually with one config file. – user9645 Jan 29 '14 at 15:03
  • 2
    Oddly, this didn't work when my path included a symlink; I had to put the full path with no symlinks before it would work. – Dolan Antenucci Sep 05 '14 at 20:03
  • See joseph07's answer about using a "trusted vim" as an alternative, inversion of this approach (distributed .vimrc vs centralized). – Nathan Schulte Jul 19 '19 at 16:58
  • 1
    We can also use a pattern like `/path/to/files/*.py` to give settings by path and file extension. The `*` in these patterns is "recursive" i.e. it matches the path separator so the autocmd will apply to all files having that extension under the given root dir. – Sam Watkins Nov 23 '21 at 10:59
51

I'd strongly suggest not using set exrc

Even with set secure, under *nix, vim will still run autocommands, shell, et al, if you own the file. So if you happend to edit a file in that tarball I sent you with a .vimrc containing:

autocmd BufEnter * :silent! !echo rm -rf ~/

you'll probably be less amused than I will.

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
phen
  • 511
  • 4
  • 2
43

I'm an advocate of the plugin way. For several reasons:

  • Modelines are particularly limited: we can't set variables (that tunes other (ft)plugins, like "should the braces of the for-snippet be on a newline ?"), or call function from them (I don't limit myself to coding standards, I also set the makefile to use depending on the current directory)
  • DRY: with modelines, a setting needs to be repeated in every file, if there are too many things to set or tunings to change, it will quickly become difficult to maintain, moreover, it will require the use of a template-expander plugin (which you should consider if you have several vimmers in your project).
  • Not every one uses vim to develop. I don't want to be bothered by other people editor settings, why should I parasite theirs?
  • It's easier to ask vimmers to install a same plugin, instead of asking them to copy-paste, and maintain, the same lines in their .vimrc
  • The settings can be saved with the other project files (cvs/svn/git/whatever)
  • It's really easy to have a configuration file per project -- with the plugin, I have a global configuration file for the coding standards of the overall project, and specific configuration files for each sub-project (which makefile to use, which executable to call, ...)

BTW, sth's solution can be used to source a single configuration file. This is very similar to the plugin approach except the .vimrc has to be parasited with non global options, and it does not support easily multiple/shared configuration files.

Community
  • 1
  • 1
Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83
  • I noticed you must save a new file in the path before it will correctly execute the plugin – cmcginty Nov 04 '10 at 00:43
  • Indeed. This family of plugins just defines a framework. You still have to write the project specific definitions in a file -- that the framework will automatically source. – Luc Hermitte Nov 04 '10 at 01:32
  • 1
    Please note, Luc links a plugin of his own. This seems to work much better than the one linked in the question. Thanks. – data Dec 01 '10 at 13:33
  • Well. I can't tell. As I've been using mine for years, I've never had a close look at the other implementations. From time to time I receive a bug report which I eventually take into account. BTW, my version is implemented to be triggered before mu-template in order to set project-specific variables before expanding templates (which is quite useful to fetch the current project root directory and trim it from the pathnames expanded) – Luc Hermitte Dec 01 '10 at 16:08
  • Just wanted to say that I tried out Luc's plugin and it worked perfectly. Thanks for the awesome work Luc! – Allen George Mar 22 '11 at 21:16
  • Is there a solution that will work recursively AND is secure even for untrusted sources? This is mostly just need for tabwidth configurations as some people use 2 spaces and others use 4 spaces. – Sophie McCarrell Mar 14 '18 at 15:22
  • 1
    @JasonMcCarrell My implementation of local_vimrc and Markus "embear" Braun's one have support for blacklist, whitelist... If you just need to specify how indentation is done, may be EditorConfig-vim plugin would be a better choice. – Luc Hermitte Mar 14 '18 at 15:30
33

This question is old, but it seems like a pretty natural and persistent concern.

My solution is pretty simple. I place a .vimrc file in the root directory of my projects. The first line of the .vimrc file usually sources ~/.vimrc, and then adds the particular configuration I want. I alias tvim='vim -u .vimrc', and use tvim in my personal project directories. "tvim" for "trusted vim," meaning that if I execute it in a directory with a .vimrc file and something goes wrong, I've got no one to blame but myself, since I explicitly said I trusted it. Also, I keep a group of these stored away so that I can sometimes just softlink the one I want for a particular kind of project.

andr
  • 15,970
  • 10
  • 45
  • 59
joseph07
  • 441
  • 4
  • 2
  • 1
    This approach is straightforward and perfectly matches my needs. – Jinxed Apr 05 '17 at 14:23
  • When I try this and `source $HOME/.vimrc` from my local `.vimrc`, Vim complains it cannot find my system-wide installed plugins (pathogen in this case; the `execute pathogen#infect()` command atop my `$HOME/.vimrc` fails with `Unknown function ...`). How can I fix this? – Nathan Schulte Jul 18 '19 at 19:55
21

Placing a .vimrc in the working directory actually is supported, only disabled by default. See :h 'exrc' and :h startup for details, setting 'exrc' will enable reading .vimrc from the current directory.

It's also recommended to :set secure when using this. This locks down :autocmd, shell and write commands for .vimrc in the current directory.

Another thing that might be worth looking at is setting up a session (:h session) with a standard view and settings for the project.

All that said, I would probably go with the plugin option detailed by Luc Hermitte myself.

gravious
  • 467
  • 2
  • 4
12

To minimize security risks with ANY "autorun" features for ANYTHING these days, may I advise you to utilize vim's existing features instead of plugins (portability baggage)?

Eg.

My local folder's vimrc file is named "_gvimrc" (on purpose). This reduces the hope for people like phen from amusing himself at our expense. :-)

In my $VIM/.vimrc file, I inserted:

if filereadable("_gvimrc")
    source _gvimrc
endif

at the end.

I use "filereadable()" over "fileexists()" as the later has some quirkiness when tortured with opening multiple (10+) files simultaneously, (not sure why).

Of course, you can give your own unique filename to obfuscate potential trouble-makers further. Such as "_mygvimrc", "_gobbledygook", etc. You just need to settle on one standardized name and source it accordingly in your $VIM/.vimrc. Relying on vi/vim internals for this rules out portability issues. BUT, DO NOT name it .vimrc (or _vimrc) to prevent recursive sourcing in case you're editing the $VIM/.vimrc file with vim later.

Been using this since Windoze 98SE, through Windork XP Pro, and now Windorkier 7 (5+ years already). I'll mark a list of .txt files in Explorer and then use "Edit with multiple Vim", resulting in multiple vim windows opening simultaneously. For my work, I do this several times a day, daily. All files got treated with what I set in my local _gvimrc.

XEQtor
  • 121
  • 1
  • 2
  • Here, the distrust for plugin portability has no ground as these local_vimrc plugins (at least mine) are portable (it used to be maintained on various different OS, and even windows 95). The issue about security risk is also exaggerated: if we follow this way, we will never install anything to ease our work. – Luc Hermitte Nov 02 '12 at 14:29
  • But, as far as I'm concerned, the first real issue is that, with your approach, you have to work from the exact directory that contains the _gvimrc file (which is a bad name as it's meant to contain gvim specific stuff). If your project is made of several directories, which may require a common configuration, and specific ones (in case of multiple modules), this will quickly show its limitations. – Luc Hermitte Nov 02 '12 at 14:33
  • The second issue is that you can only work on one project at the time -- if I want to work on OTB, openjpeg, and a project that ingrates both libraries, this solution won't let me have a specific setting for each of the three projects. – Luc Hermitte Nov 02 '12 at 14:34
  • This also works to daisy-chain loading a syntax file from a local directory. – Alcamtar May 11 '18 at 19:59
4

Use "editorconfig"

If the kinds of coding standards you would like to enforce 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.

filbranden
  • 8,522
  • 2
  • 16
  • 32
3

I agree with the plugin approach for security reasons.

There is a very good plugin which has not been mentioned yet. It lets you use a .lvimrc in your project directories.

Try "localvimrc" out:

http://www.vim.org/scripts/script.php?script_id=441

https://github.com/embear/vim-localvimrc

asgeo1
  • 9,028
  • 6
  • 63
  • 85
3

Assuming people aren't adding files every few days, you can probably add a modeline at the top of each file. In fact, if your version control system allows it, you could probably enforce a rule that says that each file must have a modeline when it's checked in.

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
1

Try vim-localrc

~/
|- .local.vimrc     (1)
`- project/
   |- .local.vimrc  (2)
   `- src/
      |- .local.vimrc   (3)
      `- main.c

https://github.com/thinca/vim-localrc/blob/master/doc/localrc.txt

Touv
  • 960
  • 8
  • 10
1

I looked at the plugins that existed and didn't really fancy any of them, so I wrote a simple function that piggy backs on vim-fugitive. The advantage of this is that it knows the root of the project is always the root of the repository, and additionally I can hash the file to keep a trust table. Just put the following in your .vimrc file.

function LoadRepoVimrc()
  let l:path = fugitive#repo().tree('.vimrc')
  if filereadable(l:path)
    let l:sha1 = fugitive#repo().git_chomp('hash-object',l:path)
    if !exists('g:SAFE_VIMRC') | let g:SAFE_VIMRC = {} | endif
    if has_key(g:SAFE_VIMRC,l:path) && g:SAFE_VIMRC[l:path] ==? l:sha1
      execute 'source '.fnameescape(l:path)
    elseif confirm("Trust ".l:path."?", "&Yes\n&No",2) == 1
      let g:SAFE_VIMRC[l:path] = l:sha1
      execute 'source '.fnameescape(l:path)
    else
      execute 'sandbox source '.fnameescape(l:path)
    endif
  endif
endfunction
autocmd User FugitiveBoot call LoadRepoVimrc()
set viminfo ^= !

If the ! option is set on the viminfo setting, then the SAFE_VIMRC dictionary will be preserved between runs (note the ^ to prepend the option so it doesn't mess up the n option).

Parakleta
  • 1,121
  • 10
  • 19