21

There is a programming project I work on where everyone else uses a tabsize of 4, so I find it most straightforward to set tabstop=4 in my ~/.vimrc. However, I'd rather not have this affect every file I edit - just those for this project - let's say every file in a certain directory (and its subdirectories).

Is there a way I can easily conditionally set variables based on the directory prefix of the file?

1

5 Answers 5

25

local / project-specific 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.

6
  • 1
    The third solution (the plugin) is excellent, and exactly the kind of thing I was looking for. I'm trying to avoid putting the config centrally, so you're right that the first is not ideal. Thanks for a comprehensive answer. May 23, 2013 at 11:05
  • Great! I also use the localrc plugin; it's truly useful. May 23, 2013 at 11:08
  • In case anyone else runs into an issue of the autocmd method not working, make sure you don't have any symlinks in your path -- I had to put the full path with no symlinks before it would work for me (on OS X 10.9) Sep 5, 2014 at 20:05
  • The solution of using set exrc and a .vimrc file is easy to implement and I find it very useful. I would like to understand why would someone use a plugin for this? Are there better solutions in 2023?
    – Unix
    Feb 15, 2023 at 13:11
  • 1
    @Unix To me the biggest downside of exrc is that you need to start Vim from the project directory. I share a single GVIM instance across projects, and for that a local vimrc plugin becomes indispensable. Feb 17, 2023 at 7:38
4

You can configure vim to read further commands using the source (so) command. Add this to your ~/.vimrc - it searches the current directory and if .vimrc_proj file not found there searches for .vimrc_proj in the parent directory.

if filereadable(".vimrc_proj")
    so .vimrc_proj
else
    if filereadable("../.vimrc_proj")
         so .vimrc_proj
    endif
endif

Then add any custom commands in .vimrc_proj config files to suit your projects.

2
  • I think that only works if I'm in the project's directory when I open the file, right? This doesn't handle where the current directory is something completely different. May 23, 2013 at 11:00
  • Correct, that is a limitation
    – suspectus
    May 23, 2013 at 11:01
1

You can use a plugin for Vim to solve the problem in a more general way by trying to detect the indention.

The plugin of choice for me is DetectIndent. It took some time for me to test all the forks of the plugin to find one that suits my needs. The original one was really close but not quite so I made my own fork.

For debugging it is very helpful to :set verbose=1 and run the plugin again with :DetectIndent

3
  • I think you may have put this answer on the wrong question? It doesn't seem relevant. May 25, 2013 at 20:49
  • @AndrewFerrier This answer is perfectly in place, it just presents different attitude to the problem. Instead of setting tab size for specific files you can use a plugin to detect correct tab size for each file.
    – gronostaj
    May 25, 2013 at 21:01
  • @gronostaj my question wasn't really about setting tab sizes, it was about per-directory-tree configuration - the tab size was just an example. But I see what you were getting at now, and it is a useful tip. Thanks. May 25, 2013 at 21:03
0

One possible solution which was not mentioned yet is to go one level above and implement project-specific shell scripts to fire up your vim environment.

This allows vim-specific settings to be passed using the -S command-line option. The advantage is that it also allows configuring other aspects of the environment, such as the terminal or cscope settings.

For example, let's say I have a C++ project called foo, for which I want to load vim settings of the file ~/.vim/projects/foo.vim. I also want to set up a cscope index and launch a terminal window if the command is invoked from some quick launch tool or desktop shortcut. To open up my environment, I have the following script, called vim-foo:

#!/bin/bash

# Script to setup the VIM development environment of my "foo" project
# Includes building ctags and cscope databases.

VIM_CONFIG=$HOME/.vim/projects/foo.vim
BASE_DIR=$HOME/work/foo

function setup_cscope()
{
    CSCOPE_FILES=$BASE_DIR/cscope.files

    created_files=false

    # check if global cscope.files exist
    if [ ! -f $CSCOPE_FILES ]; then
        echo "Creating cscope.files"
        find $BASE_DIR/src -name '*.cpp' -o -name '*.h' >> $CSCOPE_FILES
        created_files=true
    fi

    # create cscope database
    if [ $created_files ] || \ 
        [ ! -f $BASE_DIR/cscope.in.out ] || \
        [ ! -f $BASE_DIR/cscope.po.out ] || \
        [ ! -f $BASE_DIR/cscope.out ]; then
            echo "Creating cscope database"
            cscope -b -q -i $CSCOPE_FILES
            for f in in.out po.out out; do
                mv cscope.$f $BASE_DIR/
            done
    fi

    export CSCOPE_DB=$BASE_DIR/cscope.out
}

# setup everything and finally launch vim
setup_cscope
cd $BASE_DIR
if [[ $TERM == "rxvt-unicode" ]]; then
    vim -S $VIM_CONFIG
else
    urxvt -e vim -S $VIM_CONFIG
fi
0

Vim supports EditorConfig so you can put a .editorconfig file in that directory with something like:

# 4 space indentation for all .c files.
[*.c]
indent_style = tab
indent_size = 4

If you commit this to the project's version control then everybody can share it and it will work with their editors too.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .