Created
August 15, 2012 17:46
-
-
Save storborg/3361897 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" Python indent file | |
" Language: Python | |
" Maintainer: Eric Mc Sween <em@tomcom.de> | |
" Original Author: David Bustos <bustos@caltech.edu> | |
" Last Change: 2012 Aug 15 | |
" | |
" Updated 2012 Aug 15 by Scott Torborg <storborg@gmail.com> | |
" - Adds support for more esoteric PEP8 indentation conditions, particularly | |
" E125 and E127. | |
" Only load this indent file when no other was loaded. | |
if exists("b:did_indent") | |
finish | |
endif | |
let b:did_indent = 1 | |
setlocal expandtab | |
setlocal nolisp | |
setlocal autoindent | |
setlocal indentexpr=GetPythonIndent(v:lnum) | |
setlocal indentkeys=!^F,o,O,<:>,0),0],0},=elif,=except,0# | |
let s:maxoff = 50 | |
" Find backwards the closest open parenthesis/bracket/brace. | |
function! s:SearchParensPair() | |
let line = line('.') | |
let col = col('.') | |
" Skip strings and comments and don't look too far | |
let skip = "line('.') < " . (line - s:maxoff) . " ? dummy :" . | |
\ 'synIDattr(synID(line("."), col("."), 0), "name") =~? ' . | |
\ '"string\\|comment"' | |
" Search for parentheses | |
call cursor(line, col) | |
let parlnum = searchpair('(', '', ')', 'bW', skip) | |
let parcol = col('.') | |
" Search for brackets | |
call cursor(line, col) | |
let par2lnum = searchpair('\[', '', '\]', 'bW', skip) | |
let par2col = col('.') | |
" Search for braces | |
call cursor(line, col) | |
let par3lnum = searchpair('{', '', '}', 'bW', skip) | |
let par3col = col('.') | |
" Get the closest match | |
if par2lnum > parlnum || (par2lnum == parlnum && par2col > parcol) | |
let parlnum = par2lnum | |
let parcol = par2col | |
endif | |
if par3lnum > parlnum || (par3lnum == parlnum && par3col > parcol) | |
let parlnum = par3lnum | |
let parcol = par3col | |
endif | |
" Put the cursor on the match | |
if parlnum > 0 | |
call cursor(parlnum, parcol) | |
endif | |
return parlnum | |
endfunction | |
" Find the start of a multi-line statement | |
function! s:StatementStart(lnum) | |
let lnum = a:lnum | |
while 1 | |
if getline(lnum - 1) =~ '\\$' | |
let lnum = lnum - 1 | |
else | |
call cursor(lnum, 1) | |
let maybe_lnum = s:SearchParensPair() | |
if maybe_lnum < 1 | |
return lnum | |
else | |
let lnum = maybe_lnum | |
endif | |
endif | |
endwhile | |
endfunction | |
" Find the block starter that matches the current line | |
function! s:BlockStarter(lnum, block_start_re) | |
let lnum = a:lnum | |
let maxindent = 10000 " whatever | |
while lnum > 1 | |
let lnum = prevnonblank(lnum - 1) | |
if indent(lnum) < maxindent | |
if getline(lnum) =~ a:block_start_re | |
return lnum | |
else | |
let maxindent = indent(lnum) | |
" It's not worth going further if we reached the top level | |
if maxindent == 0 | |
return -1 | |
endif | |
endif | |
endif | |
endwhile | |
return -1 | |
endfunction | |
function! GetPythonIndent(lnum) | |
" First line has indent 0 | |
if a:lnum == 1 | |
return 0 | |
endif | |
" Examine this line | |
let thisline = getline(a:lnum) | |
let thisindent = indent(a:lnum) | |
" If we can find an open parenthesis/bracket/brace, line up with it. | |
call cursor(a:lnum, 1) | |
let parlnum = s:SearchParensPair() | |
if parlnum > 0 | |
" If this line ends in a :, we want it indented past the next logical | |
" statement as per E125, so go two tabs past the beginning of the | |
" statement. | |
if thisline =~ ':\s*$' | |
return indent(parlnum) + &sw * 2 | |
endif | |
let parcol = col('.') | |
let closing_paren = match(getline(a:lnum), '^\s*[])}]') != -1 | |
if match(getline(parlnum), '[([{]\s*$', parcol - 1) != -1 | |
if closing_paren | |
return indent(parlnum) | |
else | |
return indent(parlnum) + &shiftwidth | |
endif | |
else | |
if closing_paren | |
return parcol - 1 | |
else | |
return parcol | |
endif | |
endif | |
endif | |
" If the line starts with 'elif' or 'else', line up with 'if' or 'elif' | |
if thisline =~ '^\s*\(elif\|else\)\>' | |
let bslnum = s:BlockStarter(a:lnum, '^\s*\(if\|elif\)\>') | |
if bslnum > 0 | |
return indent(bslnum) | |
else | |
return -1 | |
endif | |
endif | |
" If the line starts with 'except' or 'finally', line up with 'try' | |
" or 'except' | |
if thisline =~ '^\s*\(except\|finally\)\>' | |
let bslnum = s:BlockStarter(a:lnum, '^\s*\(try\|except\)\>') | |
if bslnum > 0 | |
return indent(bslnum) | |
else | |
return -1 | |
endif | |
endif | |
" Examine previous line | |
let plnum = a:lnum - 1 | |
let pline = getline(plnum) | |
let sslnum = s:StatementStart(plnum) | |
" If the previous line is blank, keep the same indentation | |
if pline =~ '^\s*$' | |
return -1 | |
endif | |
" If this line is otherwise explicitly joined with a backslash... | |
if pline =~ '\\$' | |
"let compound_statement = '^\s*\(if\|while\|for\s.*\sin\|except\)\s*' | |
"let maybe_indent = matchend(getline(sslnum), compound_statement) | |
if thisline =~ ':\s*$' | |
" If the statement ends in an :, we don't want it to line up with th | |
" next logical line, so indent it by two, as per PEP8 E125. | |
return indent(sslnum) + &sw * 2 | |
else | |
" Otherwise indent by one as per PEP8 E127. | |
return indent(sslnum) + &sw | |
endif | |
endif | |
" If the previous line ended with a colon, indent relative to | |
" statement start. | |
if pline =~ ':\s*$' | |
return indent(sslnum) + &sw | |
endif | |
" If the previous line was a stop-execution statement or a pass | |
if getline(sslnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>' | |
" See if the user has already dedented | |
if indent(a:lnum) > indent(sslnum) - &sw | |
" If not, recommend one dedent | |
return indent(sslnum) - &sw | |
endif | |
" Otherwise, trust the user | |
return -1 | |
endif | |
" In all other cases, line up with the start of the previous statement. | |
return indent(sslnum) | |
endfunction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment