" PEP8 compatible Python indent file
" Language: Python
-" Maintainer: Hynek Schlawack <hs@ox.cx>
+" Maintainer: Daniel Hahler <https://daniel.hahler.de/>
+" Prev Maintainer: Hynek Schlawack <hs@ox.cx>
" Prev Maintainer: Eric Mc Sween <em@tomcom.de> (address invalid)
" Original Author: David Bustos <bustos@caltech.edu> (address invalid)
" License: CC0
" Written in 2004 by David Bustos <bustos@caltech.edu>
" Maintained from 2004-2005 by Eric Mc Sween <em@tomcom.de>
" Maintained from 2013 by Hynek Schlawack <hs@ox.cx>
+" Maintained from 2017 by Daniel Hahler <https://daniel.hahler.de/>
"
" To the extent possible under law, the author(s) have dedicated all copyright
" and related and neighboring rights to this software to the public domain
" <http://creativecommons.org/publicdomain/zero/1.0/>.
" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
+if exists('b:did_indent')
finish
endif
let b:did_indent = 1
-setlocal expandtab
setlocal nolisp
setlocal autoindent
setlocal indentexpr=GetPythonPEPIndent(v:lnum)
setlocal indentkeys=!^F,o,O,<:>,0),0],0},=elif,=except
-setlocal tabstop=4
-setlocal softtabstop=4
-setlocal shiftwidth=4
if !exists('g:python_pep8_indent_multiline_string')
let g:python_pep8_indent_multiline_string = 0
\ '^\s*else\>': ['if', 'elif', 'for', 'try', 'except'],
\ }
let s:paren_pairs = ['()', '{}', '[]']
-if &ft == 'pyrex' || &ft == 'cython'
+if &filetype ==# 'pyrex' || &filetype ==# 'cython'
let b:control_statement = '\v^\s*(class|def|if|while|with|for|except|cdef|cpdef)>'
else
let b:control_statement = '\v^\s*(class|def|if|while|with|for|except)>'
endfunction
else
function! s:sw()
- return &sw
+ return &shiftwidth
endfunction
endif
function! s:find_start_of_multiline_statement(lnum)
let lnum = a:lnum
while lnum > 0
- if getline(lnum - 1) =~ '\\$'
+ if getline(lnum - 1) =~# '\\$'
let lnum = prevnonblank(lnum - 1)
else
let [paren_lnum, _] = s:find_opening_paren(lnum)
let r = 1
for i in range(a:start, end)
call cursor(a:lnum, i)
- if !(eval(a:expr) || text[i-1] =~ '\s')
+ if !(eval(a:expr) || text[i-1] =~# '\s')
let r = 0
break
endif
let nothing_after_opening_paren = s:match_expr_on_line(
\ s:skip_after_opening_paren, paren_lnum, paren_col+1)
- let starts_with_closing_paren = getline(a:lnum) =~ '^\s*[])}]'
+ let starts_with_closing_paren = getline(a:lnum) =~# '^\s*[])}]'
if nothing_after_opening_paren
if starts_with_closing_paren
" Search for final colon that is not inside something to be ignored.
while 1
- let curpos = getpos(".")[2]
+ let curpos = getpos('.')[2]
if curpos == 1 | break | endif
- if eval(s:skip_special_chars) || text[curpos-1] =~ '\s'
+ if eval(s:skip_special_chars) || text[curpos-1] =~# '\s'
normal! h
continue
- elseif text[curpos-1] == ':'
+ elseif text[curpos-1] ==# ':'
return base + s:sw()
endif
break
endwhile
- if text =~ '\\$' && !ignore_last_char
+ if text =~# '\\$' && !ignore_last_char
" If this line is the continuation of a control statement
" indent further to distinguish the continuation line
" from the next logical line.
return base + s:sw()
endif
+ let empty = getline(a:lnum) =~# '^\s*$'
+
+ " Current and prev line are empty, next is not -> indent like next.
+ if empty && a:lnum > 1 &&
+ \ (getline(a:lnum - 1) =~# '^\s*$') &&
+ \ !(getline(a:lnum + 1) =~# '^\s*$')
+ return indent(a:lnum + 1)
+ endif
+
" If the previous statement was a stop-execution statement or a pass
if getline(start) =~# s:stop_statement
" Remove one level of indentation if the user hasn't already dedented
- if indent(a:lnum) > base - s:sw()
+ if empty || current > base - s:sw()
return base - s:sw()
endif
" Otherwise, trust the user
return -1
endif
- if s:is_dedented_already(current, base)
+ if !empty && s:is_dedented_already(current, base)
return -1
endif
let cols = a:0 ? type(a:1) != type([]) ? [a:1] : a:1 : range(1, linelen)
for cnum in cols
if match(map(synstack(a:lnum, cnum),
- \ 'synIDattr(v:val,"name")'), 'python\S*String') == -1
+ \ "synIDattr(v:val, 'name')"), 'python\S*String') == -1
return 0
end
endfor
return 0
endif
+ let line = getline(a:lnum)
+ let prevline = getline(a:lnum-1)
+
" Multilinestrings: continous, docstring or starting.
- if s:is_python_string(a:lnum, 1)
- \ && s:is_python_string(a:lnum-1, len(getline(a:lnum-1)))
- " Keep existing indent.
- if match(getline(a:lnum), '\v^\s*\S') != -1
- return -1
+ if s:is_python_string(a:lnum-1, len(prevline))
+ \ && (s:is_python_string(a:lnum, 1)
+ \ || match(line, '^\%("""\|''''''\)') != -1)
+
+ " Indent closing quotes as the line with the opening ones.
+ let match_quotes = match(line, '^\s*\zs\%("""\|''''''\)')
+ if match_quotes != -1
+ " closing multiline string
+ let quotes = line[match_quotes:(match_quotes+2)]
+ let pairpos = searchpairpos(quotes, '', quotes, 'b')
+ if pairpos[0] != 0
+ return indent(pairpos[0])
+ else
+ " TODO: test to cover this!
+ endif
endif
if s:is_python_string(a:lnum-1)
return indent(a:lnum-1)
endif
- if match(getline(a:lnum-1), '^\s*\%("""\|''''''\)') != -1
+ if match(prevline, '^\s*\%("""\|''''''\)') != -1
" docstring.
return indent(a:lnum-1)
endif
let indent_multi = get(b:, 'python_pep8_indent_multiline_string',
\ get(g:, 'python_pep8_indent_multiline_string', 0))
+ if match(prevline, '\v%("""|'''''')$') != -1
+ " Opening multiline string, started in previous line.
+ if (&autoindent && indent(a:lnum) == indent(a:lnum-1))
+ \ || match(line, '\v^\s+$') != -1
+ " <CR> with empty line or to split up 'foo("""bar' into
+ " 'foo("""' and 'bar'.
+ if indent_multi == -2
+ return indent(a:lnum-1) + s:sw()
+ endif
+ return indent_multi
+ endif
+ endif
+
+ " Keep existing indent.
+ if match(line, '\v^\s*\S') != -1
+ return -1
+ endif
+
if indent_multi != -2
return indent_multi
endif
- if match(getline(a:lnum-1), '\v%("""|'''''')$') != -1
- " Opening multiline string, started in previous line.
- return indent(a:lnum-1) + s:sw()
- endif
return s:indent_like_opening_paren(a:lnum)
endif