Vim Tips Wiki
Register
Advertisement
Tip 1231 Printable Monobook Previous Next

created 2006 · complexity intermediate · author Davide Alberani · version 6.0


You may need to maintain source files that use different indentation styles. For example, some files may use four spaces for each indent, while others use three spaces, or use tabs, or use a mixture of tabs and spaces.

This tip presents alternative procedures to automatically detect and set the indent options so Vim adapts to the style of the program you are working on. The procedures are oriented towards working on Python programs but may be useful for other languages.

IndentConsistencyCop[]

The IndentConsistencyCop plugin warns if inconsistent indentation is used in a buffer and also offers to correct the buffer's indent settings (shiftwidth, softtabstop, etc) if they do not match the indent type used in the buffer. This plugin is not limited to Python files. Checks can be triggered manually or (with the IndentConsistencyCopAutoCmds add-on plugin) automatically for certain filetypes.

Indent Finder[]

The Indent Finder plugin sets the correct indentation for each file that you edit. It uses a Python script that determines what indent style was used, then adjusts your settings so that new modifications use the same style.

Vindect[]

Vindect is a Python script to detect the indent options required for editing a Python program. In Vim, output from the :version command should include "+python".

The following options are set based upon usage in the current file, and your preferences: shiftwidth, tabstop, softtabstop, smarttab, expandtab.

Rename the downloaded file to vindect.py. The file includes setup instructions using the deprecated mysyntaxfile variable. Following is a better procedure that should be used instead.

The following commands need to be executed once per Vim session (done below):

" First need to set the Python path so vindect.py is found.
:py import vindect
:py vindect.setDefaults(...)  " optional to set different defaults

This command detects and sets the indent options when a new file is opened (done below):

:py vindect.detect(preferred='space')

The following setup performs all the required steps whenever a Python file is opened.

  • Place vindent.py in your .vim (Unix based systems) or vimfiles (Windows) directory.
  • Create an after/ftplugin/python.vim file with the following contents. On Windows systems, change .vim to vimfiles.
if !exists('s:configured_vindect')
  if has('python')
    py import sys,os; sys.path.append(os.path.expanduser('~/.vim/'))
    try
      py import vindect
      let s:configured_vindect = 1
    catch
      let s:configured_vindect = 0
    endtry
    " to set different defaults: py vindect.setDefaults(...)
  else
    let s:configured_vindect = 0
  endif
endif
if s:configured_vindect
  py vindect.detect(preferred='space')
endif

DetectIndent[]

The DetectIndent plugin is another alternative.

Vim script[]

The following script can only choose between two sets of fixed options. One set is used if tabs are detected; otherwise another set is used (for space indents).

You could put the following in your vimrc and use a mapping to call PyIndentAutoCfg() when wanted, or define an auto command to call that function when a Python file is opened.

" Set options if using spaces for indents (default).
function PySpacesCfg()
  set expandtab
  set tabstop=8
  set softtabstop=4
  set shiftwidth=4
endfunction

" Set options if using tabs for indents.
function PyTabsCfg()
  set noexpandtab
  set tabstop=4
  set softtabstop=4
  set shiftwidth=4
endfunction

" Return 1 if using tabs for indents, or 0 otherwise.
function PyIsTabIndent()
  let lnum = 1
  let got_cols = 0  " 1 if previous lines ended with columns
  while lnum <= 100
    let line = getline(lnum)
    let lnum = lnum + 1
    if got_cols == 1
      if line =~ "^\t\t"  " two tabs to prevent false positives
        return 1
      endif
    endif
    if line =~ ":\s*$"
      let got_cols = 1
    else
      let got_cols = 0
    endif
  endwhile
  return 0
endfunction

" Check current buffer and configure for tab or space indents.
function PyIndentAutoCfg()
  if PyIsTabIndent()
    call PyTabsCfg()
  else
    call PySpacesCfg()
  endif
endfunction

Comments[]

Re configuration of vindent: It may be possible to avoid a hard coded path to vindect.py by using :exec with expand('<sfile>') and filenamemodify().


Re the Vim script: The following version of PyIsTabIndent() handles more languages:

function! PyIsTabIndent()
  let lnum = 1
  while lnum <= 100
    let line = getline(lnum)
    let lnum = lnum + 1
    if line =~ '^\t\t\(if\|while\|do\|for\|public\|private\|char\|int\|float\|double\|call\)\>'
      return 1
    endif
  endwhile
  return 0
endfunction

Advertisement