let s:maxoff = 50
let s:block_rules = {
\ '^\s*elif\>': ['if', 'elif'],
- \ '^\s*else\>': ['if', 'elif', 'for', 'try', 'except'],
\ '^\s*except\>': ['try', 'except'],
\ '^\s*finally\>': ['try', 'except', 'else']
\ }
+let s:block_rules_multiple = {
+ \ '^\s*else\>': ['if', 'elif', 'for', 'try', 'except'],
+ \ }
let s:paren_pairs = ['()', '{}', '[]']
if &ft == 'pyrex' || &ft == 'cython'
let b:control_statement = '\v^\s*(class|def|if|while|with|for|except|cdef|cpdef)>'
endwhile
endfunction
-" Find the block starter that matches the current line
-function! s:find_start_of_block(lnum, types)
+" Find possible indent(s) of the block starter that matches the current line.
+function! s:find_start_of_block(lnum, types, multiple)
+ let r = []
let re = '\V\^\s\*\('.join(a:types, '\|').'\)\>'
-
let lnum = a:lnum
let last_indent = indent(lnum) + 1
while lnum > 0 && last_indent > 0
- if indent(lnum) < last_indent
+ let indent = indent(lnum)
+ if indent < last_indent
if getline(lnum) =~# re
- return lnum
+ if !a:multiple
+ return [indent]
+ endif
+ if !len(r) || index(r, indent) == -1
+ let r += [indent]
+ endif
endif
let last_indent = indent(lnum)
endif
let lnum = prevnonblank(lnum - 1)
endwhile
- return 0
+ return r
endfunction
" Is "expr" true for every position in "lnum", beginning at "start"?
" Match indent of first block of this type.
function! s:indent_like_block(lnum)
let text = getline(a:lnum)
+ for [multiple, block_rules] in [
+ \ [0, s:block_rules],
+ \ [1, s:block_rules_multiple]]
+ for [line_re, blocks] in items(block_rules)
+ if text !~# line_re
+ continue
+ endif
- for [line_re, blocks] in items(s:block_rules)
- if text !~# line_re
- continue
- endif
-
- let lnum = s:find_start_of_block(a:lnum - 1, blocks)
- if lnum > 0
- return indent(lnum)
- else
- return -1
- endif
+ let indents = s:find_start_of_block(a:lnum - 1, blocks, multiple)
+ if !len(indents)
+ return -1
+ endif
+ if len(indents) == 1
+ return indents[0]
+ endif
+ " Multiple valid indents, e.g. for 'else' with both try and if.
+ let indent = indent(a:lnum)
+ for possible_indent in indents
+ if indent == possible_indent
+ return indent
+ endif
+ endfor
+ return -2
+ endfor
endfor
-
return -2
endfunction
end
end
+ describe "when an 'if' contains a try-except" do
+ before {
+ vim.feedkeys 'iif x:\<CR>try:\<CR>pass\<CR>except:\<CR>pass\<CR>'
+ indent.should == shiftwidth
+ }
+ it "an 'else' should be indented to the try" do
+ vim.feedkeys 'else:'
+ indent.should == shiftwidth
+ proposed_indent.should == shiftwidth
+ end
+ it "an 'else' should keep the indent of the 'if'" do
+ vim.feedkeys 'else:\<ESC><<'
+ indent.should == 0
+ proposed_indent.should == 0
+ end
+ end
+
describe "when a 'for' is followed by" do
before { vim.feedkeys 'i\<TAB>\<TAB>for x in y:\<CR>' }
it "an 'else', it lines up with the 'for'" do