Vim Tips Wiki
Advertisement

While working with python files written by others with varying indentation levels (some using 3 spaces and others using 4 spaces, and some mixing tabs and spaces), it gets tiresome to determine the right settings and change them manually.

Solution using Vindect

There is a python script called vindect that is designed specifically for detecting indentation of Python files in Vim. The script is able to set the below settings appropriate to the current file based on the current usage of spaces and tabs:

  • shiftwidth
  • tabstop
  • softtabstop
  • smarttab
  • expandtab

The script requires a Python enabled Vim to run. It is invoked using the below command:

py vindect.detect(preferred='space')

The above command can be invoked manually at anytime on the ex command-line, but it is more convenient if it is invoked automatically, whenever a Python file is opened using a simple setup shown below.

The script comes with below instructions to setup, however look further for an Alternative Setup that should work better.

Setup

  • place this file in ~/.vim/
  • in .vimrc add:
    let mysyntaxfile = "~/.vim/mysyntax.vim"
    if has("python")
      py import sys,os; sys.path.append(os.path.expanduser("~/.vim/"))
      py import vindect
      "if you want different defaults: py vindect.setDefaults(...)
    endif
  • in ~/.vim/mysyntax.vim:
    if has("python")
      au Syntax python py vindect.detect() 
      au Syntax cpp py vindect.detect()
      au Syntax c py vindect.detect()
      au Syntax java py vindect.detect(preferred='space')
	  "...etc...
    endif

Alternative Setup

  • Place the python file in your .vim or vimfiles directory.
  • Rename it as vindect.py (remove the version number in the filename).
  • Create an after/ftplugin/python.vim file with the below contents (change vimfiles to .vim accordingly):
if !exists('s:configured_vindect')
  if has("python")
    py import sys,os; sys.path.append(os.path.expanduser("~/vimfiles/"))
    try
      py import vindect
      let s:configured_vindect = 1
    catch
      let s:configured_vindect = 0
    endtry
    "if you want different defaults: py vindect.setDefaults(...)
  else
    let s:configured_vindect = 0
  endif
endif
if s:configured_vindect
  py vindect.detect(preferred='space')
endif

Other Solutions

DetectIndent

There is a vim script called DetectIndent that is meant to do exactly this, but it didn't work well for some of the python files I tried (some being set to shiftwidth of 1). YMMV.

Comments

Thanks for the tip. I think we need to explain a little more what happens. While many of our old tips are full of mystery, we're trying to spell out what each new tip actually does. The lead paragraph does a good job, but there needs to be a section which lists the actual effect. Perhaps something like "for example, if you edit a Python file which uses two spaces for each indent, vindent.detect() will change the following Vim settings ...". What does happen if tabs and spaces are used? Also, can we spell out "change vimfiles to .vim accordingly". The DetectIndent info should probably be removed from the lead and added in a separate section (which will probably grow), perhaps "Other solutions".

JohnBeckett 01:04, 21 March 2009 (UTC)

I have now explained it a little more. Thanks for taking the time to make the above comment.

I think it is possible to avoid hardcoded path to vindect.py by using :exec command along with expand('<sfile>') and filenamemodify(), but I haven't tried it.

Haridsv 02:24, 21 March 2009 (UTC)

Advertisement