Skip to content

Commit 2c38ff0

Browse files
blueyedhynek
authored andcommitted
Fix keeping indent with 'else' for 'if' after 'try-except' (#52)
Fixes #47.
1 parent e1d10d7 commit 2c38ff0

File tree

2 files changed

+55
-19
lines changed

2 files changed

+55
-19
lines changed

indent/python.vim

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@ setlocal shiftwidth=4
3535
let s:maxoff = 50
3636
let s:block_rules = {
3737
\ '^\s*elif\>': ['if', 'elif'],
38-
\ '^\s*else\>': ['if', 'elif', 'for', 'try', 'except'],
3938
\ '^\s*except\>': ['try', 'except'],
4039
\ '^\s*finally\>': ['try', 'except', 'else']
4140
\ }
41+
let s:block_rules_multiple = {
42+
\ '^\s*else\>': ['if', 'elif', 'for', 'try', 'except'],
43+
\ }
4244
let s:paren_pairs = ['()', '{}', '[]']
4345
if &ft == 'pyrex' || &ft == 'cython'
4446
let b:control_statement = '\v^\s*(class|def|if|while|with|for|except|cdef|cpdef)>'
@@ -136,22 +138,28 @@ function! s:find_start_of_multiline_statement(lnum)
136138
endwhile
137139
endfunction
138140

139-
" Find the block starter that matches the current line
140-
function! s:find_start_of_block(lnum, types)
141+
" Find possible indent(s) of the block starter that matches the current line.
142+
function! s:find_start_of_block(lnum, types, multiple)
143+
let r = []
141144
let re = '\V\^\s\*\('.join(a:types, '\|').'\)\>'
142-
143145
let lnum = a:lnum
144146
let last_indent = indent(lnum) + 1
145147
while lnum > 0 && last_indent > 0
146-
if indent(lnum) < last_indent
148+
let indent = indent(lnum)
149+
if indent < last_indent
147150
if getline(lnum) =~# re
148-
return lnum
151+
if !a:multiple
152+
return [indent]
153+
endif
154+
if !len(r) || index(r, indent) == -1
155+
let r += [indent]
156+
endif
149157
endif
150158
let last_indent = indent(lnum)
151159
endif
152160
let lnum = prevnonblank(lnum - 1)
153161
endwhile
154-
return 0
162+
return r
155163
endfunction
156164

157165
" Is "expr" true for every position in "lnum", beginning at "start"?
@@ -212,20 +220,31 @@ endfunction
212220
" Match indent of first block of this type.
213221
function! s:indent_like_block(lnum)
214222
let text = getline(a:lnum)
223+
for [multiple, block_rules] in [
224+
\ [0, s:block_rules],
225+
\ [1, s:block_rules_multiple]]
226+
for [line_re, blocks] in items(block_rules)
227+
if text !~# line_re
228+
continue
229+
endif
215230

216-
for [line_re, blocks] in items(s:block_rules)
217-
if text !~# line_re
218-
continue
219-
endif
220-
221-
let lnum = s:find_start_of_block(a:lnum - 1, blocks)
222-
if lnum > 0
223-
return indent(lnum)
224-
else
225-
return -1
226-
endif
231+
let indents = s:find_start_of_block(a:lnum - 1, blocks, multiple)
232+
if !len(indents)
233+
return -1
234+
endif
235+
if len(indents) == 1
236+
return indents[0]
237+
endif
238+
" Multiple valid indents, e.g. for 'else' with both try and if.
239+
let indent = indent(a:lnum)
240+
for possible_indent in indents
241+
if indent == possible_indent
242+
return indent
243+
endif
244+
endfor
245+
return -2
246+
endfor
227247
endfor
228-
229248
return -2
230249
endfunction
231250

spec/indent/indent_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,23 @@
353353
end
354354
end
355355

356+
describe "when an 'if' contains a try-except" do
357+
before {
358+
vim.feedkeys 'iif x:\<CR>try:\<CR>pass\<CR>except:\<CR>pass\<CR>'
359+
indent.should == shiftwidth
360+
}
361+
it "an 'else' should be indented to the try" do
362+
vim.feedkeys 'else:'
363+
indent.should == shiftwidth
364+
proposed_indent.should == shiftwidth
365+
end
366+
it "an 'else' should keep the indent of the 'if'" do
367+
vim.feedkeys 'else:\<ESC><<'
368+
indent.should == 0
369+
proposed_indent.should == 0
370+
end
371+
end
372+
356373
describe "when a 'for' is followed by" do
357374
before { vim.feedkeys 'i\<TAB>\<TAB>for x in y:\<CR>' }
358375
it "an 'else', it lines up with the 'for'" do

0 commit comments

Comments
 (0)