@@ -76,6 +76,52 @@ fun! pymode#folding#expr(lnum) "{{{
76
76
return " <" .(indent / &shiftwidth + 1 )
77
77
endif
78
78
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
+
79
125
if line = ~ s: blank_regex
80
126
if prev_line = ~ s: blank_regex
81
127
if indent (a: lnum + 1 ) == 0 && getline (a: lnum + 1 ) !~ s: blank_regex
@@ -95,5 +141,36 @@ fun! pymode#folding#expr(lnum) "{{{
95
141
96
142
endfunction " }}}
97
143
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 " }}}
98
175
99
176
" vim: fdm = marker:fdl = 0
0 commit comments