@@ -76,6 +76,52 @@ fun! pymode#folding#expr(lnum) "{{{
7676 return " <" .(indent / &shiftwidth + 1 )
7777 endif
7878
79+ " Handle nested defs but only for files shorter than
80+ " g:pymode_folding_nest_limit lines due to performance concerns
81+ if line (' $' ) < g: pymode_folding_nest_limit && indent (prevnonblank (a: lnum ))
82+ let curpos = getcurpos ()
83+ try
84+ let last_block = s: BlockStart (a: lnum )
85+ let last_block_indent = indent (last_block)
86+
87+ " Check if last class/def is not indented and therefore can't be
88+ " nested.
89+ if last_block_indent
90+ call cursor (a: lnum , 0 )
91+ let next_def = searchpos (s: def_regex , ' nW' )[0 ]
92+ let next_def_indent = next_def ? indent (next_def) : -1
93+ let last_block_end = s: BlockEnd (last_block)
94+
95+ " If the next def has greater indent than the previous def, it
96+ " is nested one level deeper and will have its own fold. If
97+ " the class/def containing the current line is on the first
98+ " line it can't be nested, and if this block ends on the last
99+ " line, it contains no trailing code that should not be
100+ " folded. Finally, if the next non-blank line after the end of
101+ " the previous def is less indented than the previous def, it
102+ " is not part of the same fold as that def. Otherwise, we know
103+ " the current line is at the end of a nested def.
104+ if next_def_indent <= last_block_indent && last_block > 1 && last_block_end < line (' $' )
105+ \ && indent (nextnonblank (last_block_end)) >= last_block_indent
106+
107+ " Include up to one blank line in the fold
108+ if getline (last_block_end) = ~ s: blank_regex
109+ let fold_end = min ([prevnonblank (last_block_end - 1 ), last_block_end]) + 1
110+ else
111+ let fold_end = last_block_end
112+ endif
113+ if a: lnum == fold_end
114+ return ' s1'
115+ else
116+ return ' ='
117+ endif
118+ endif
119+ endif
120+ finally
121+ call setpos (' .' , curpos)
122+ endtry
123+ endif
124+
79125 if line = ~ s: blank_regex
80126 if prev_line = ~ s: blank_regex
81127 if indent (a: lnum + 1 ) == 0 && getline (a: lnum + 1 ) !~ s: blank_regex
@@ -95,5 +141,36 @@ fun! pymode#folding#expr(lnum) "{{{
95141
96142endfunction " }}}
97143
144+ fun ! s: BlockStart (lnum) " {{{
145+ " Note: Make sure to reset cursor position after using this function.
146+ call cursor (a: lnum , 0 )
147+
148+ " In case the end of the block is indented to a higher level than the def
149+ " statement plus one shiftwidth, we need to find the indent level at the
150+ " bottom of that if/for/try/while/etc. block.
151+ let last_def = searchpos (s: def_regex , ' bcnW' )[0 ]
152+ if last_def
153+ let last_def_indent = indent (last_def)
154+ call cursor (last_def, 0 )
155+ let next_stmt_at_def_indent = searchpos (' \v^\s{' .last_def_indent.' }[^[:space:]#]' , ' nW' )[0 ]
156+ else
157+ let next_stmt_at_def_indent = -1
158+ endif
159+
160+ " Now find the class/def one shiftwidth lower than the start of the
161+ " aforementioned indent block.
162+ if next_stmt_at_def_indent && next_stmt_at_def_indent < a: lnum
163+ let max_indent = max ([indent (next_stmt_at_def_indent) - &shiftwidth , 0 ])
164+ else
165+ let max_indent = max ([indent (prevnonblank (a: lnum )) - &shiftwidth , 0 ])
166+ endif
167+ return searchpos (' \v^\s{,' .max_indent.' }(def |class )\w' , ' bcnW' )[0 ]
168+ endfunction " }}}
169+
170+ fun ! s: BlockEnd (lnum) " {{{
171+ " Note: Make sure to reset cursor position after using this function.
172+ call cursor (a: lnum , 0 )
173+ return searchpos (' \v^\s{,' .indent (' .' ).' }\S' , ' nW' )[0 ] - 1
174+ endfunction " }}}
98175
99176" vim: fdm = marker:fdl = 0
0 commit comments