Skip to content

Commit 5b6e92d

Browse files
committed
greatly improved tests; improved folding as a result
1 parent b66198d commit 5b6e92d

34 files changed

+610
-396
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# Deactivated.
22
# This plugin needs a robust test suite.
3+
branches:
4+
only:
5+
# - develop
6+
- dev_imp_test
7+
install: git clone --recursive https://github.com/python-mode/python-mode
8+
script: cd ./tests && bash -x ./test.sh

autoload/pymode/debug.vim

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ endfunction "}}}
4949

5050
" DESC: Define debug folding function.
5151
function! pymode#debug#foldingexpr(lnum) "{{{
52-
let l:get_folding_result = pymode#folding#expr(a:lnum)
52+
let l:get_folding_result = pymode#folding#foldcase(a:lnum)
5353
" NOTE: the 'has folding:' expression is special in the pymode#debug.
54-
call pymode#debug('line ' . a:lnum . ' has folding:' . l:get_folding_result)
55-
return pymode#folding#expr(a:lnum)
54+
call pymode#debug(
55+
\ 'line ' . a:lnum
56+
\ . ' has folding: ' . l:get_folding_result['foldlevel']
57+
\ . ' with foldcase ' . l:get_folding_result['foldcase'])
58+
return l:get_folding_result['foldlevel']
5659
endfunction
5760
" }}}

autoload/pymode/folding.vim

Lines changed: 121 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
k" Python-mode folding function2
21
" Notice that folding is based on single line so complex regular expressions
32
" that take previous line into consideration are not fit for the job.
43

@@ -47,25 +46,44 @@ endfunction "}}}
4746

4847
fun! pymode#folding#expr(lnum) "{{{
4948

49+
return pymode#folding#foldcase(a:lnum)['foldlevel']
50+
51+
endfunction "}}}
52+
53+
fun! pymode#folding#foldcase(lnum) "{{{
54+
" Return a dictionary with a brief description of the foldcase and the
55+
" evaluated foldlevel: {'foldcase': 'case description', 'foldlevel': 1}.
56+
57+
let l:foldcase = 'general'
58+
let l:foldlevel = 0
59+
5060
let line = getline(a:lnum)
5161
let indent = indent(a:lnum)
5262
let prev_line = getline(a:lnum - 1)
5363
let next_line = getline(a:lnum + 1)
5464

5565
" Decorators {{{
5666
if line =~ s:decorator_regex
57-
return ">".(indent / &shiftwidth + 1)
67+
let l:foldcase = 'decorator declaration'
68+
let l:foldlevel = '>'.(indent / &shiftwidth + 1)
69+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
5870
endif "}}}
5971

6072
" Definition {{{
6173
if line =~ s:def_regex
74+
75+
" TODO: obscure case.
6276
" If indent of this line is greater or equal than line below
6377
" and previous non blank line does not end with : (that is, is not a
6478
" definition)
6579
" Keep the same indentation
66-
if indent(a:lnum) >= indent(a:lnum+1) && getline(prevnonblank(a:lnum)) !~ ':\s*$'
67-
return '='
68-
endif
80+
" xxx " if indent(a:lnum) >= indent(a:lnum+1)
81+
" xxx " \ && getline(prevnonblank(a:lnum)) !~ ':\s*$'
82+
" xxx " let l:foldcase = 'definition'
83+
" xxx " let l:foldlevel = '='
84+
" xxx " return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
85+
" xxx " endif
86+
6987
" Check if last decorator is before the last def
7088
let decorated = 0
7189
let lnum = a:lnum - 1
@@ -79,14 +97,13 @@ fun! pymode#folding#expr(lnum) "{{{
7997
let lnum -= 1
8098
endwhile
8199
if decorated
82-
return '='
100+
let l:foldcase = 'decorated function declaration'
101+
let l:foldlevel = '='
83102
else
84-
" The line below may improve folding.
85-
return ">".(indent / &shiftwidth + 1)
86-
" This was the previous rule. It grouped classes definitions
87-
" together (undesired).
88-
" return indent / &shiftwidth + 1
103+
let l:foldcase = 'function declaration'
104+
let l:foldlevel = '>'.(indent / &shiftwidth + 1)
89105
endif
106+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
90107
endif "}}}
91108

92109
" Docstrings {{{
@@ -98,60 +115,105 @@ fun! pymode#folding#expr(lnum) "{{{
98115
" Notice that an effect of this is that other docstring matches will not
99116
" be one liners.
100117
if line =~ s:docstring_line_regex
101-
return "="
118+
let l:foldcase = 'one-liner docstring'
119+
let l:foldlevel = '='
120+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
102121
endif
103-
104122
if line =~ s:docstring_begin_regex
105123
if s:Is_opening_folding(a:lnum)
106-
return ">".(indent / &shiftwidth + 1)
124+
let l:foldcase = 'open multiline docstring'
125+
let l:foldlevel = 'a1'
107126
endif
127+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
108128
endif
109129
if line =~ s:docstring_end_regex
110130
if !s:Is_opening_folding(a:lnum)
111-
return "<".(indent / &shiftwidth + 1)
131+
let l:foldcase = 'close multiline docstring'
132+
let l:foldlevel = 's1'
112133
endif
134+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
113135
endif "}}}
114136

115137
" Blocks. {{{
138+
let line_block_start = s:BlockStart(a:lnum)
139+
let line_block_end = s:BlockEnd(a:lnum)
140+
let prev_line_block_start = s:BlockStart(a:lnum - 1)
116141
let save_cursor = getcurpos()
117142
if line !~ s:blank_regex
118-
let line_block_start = s:BlockStart(a:lnum)
119-
let prev_line_block_start = s:BlockStart(a:lnum - 1)
120143
call setpos('.', save_cursor)
121-
if line_block_start == prev_line_block_start || a:lnum - line_block_start == 1
122-
return '='
144+
if line_block_start == prev_line_block_start
145+
\ || a:lnum - line_block_start == 1
146+
let l:foldcase = 'non blank line; first line of block or part of it'
147+
let l:foldlevel = '='
123148
elseif indent < indent(prevnonblank(a:lnum - 1))
124-
return indent(line_block_start) / &shiftwidth + 1
125-
else
149+
if indent == 0
150+
let l:foldcase = 'non blank line; zero indent'
151+
let l:foldlevel = 0
152+
else
153+
let l:foldcase = 'non blank line; non zero indent'
154+
let l:foldlevel = indent(line_block_start) / &shiftwidth + 1
155+
endif
126156
endif
157+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
127158
endif
128159
" endif " }}}
129160

130161
" Blank Line {{{
162+
" Comments: cases of blank lines:
163+
" 1. After non blank line: gets folded with previous line.
164+
" 1. Just after a block; in this case it gets folded with the block.
165+
" 1. Between docstrings and imports.
166+
" 1. Inside docstrings.
167+
" 2. Inside functions/methods.
168+
" 3. Between functions/methods.
131169
if line =~ s:blank_regex
132-
if prev_line =~ s:blank_regex
133-
if indent(a:lnum + 1) == 0 && next_line !~ s:blank_regex && next_line !~ s:docstring_general_regex
134-
if s:Is_opening_folding(a:lnum)
135-
return "="
136-
else
137-
return 0
138-
endif
139-
endif
140-
return -1
141-
else
142-
return '='
170+
if prev_line !~ s:blank_regex
171+
let l:foldcase = 'blank line after non blank line'
172+
let l:foldlevel = '='
173+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
174+
elseif a:lnum > line_block_start && a:lnum < line_block_end
175+
let l:foldcase = 'blank line inside block'
176+
let l:foldlevel = '='
177+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
143178
endif
179+
" if prev_line =~ s:blank_regex
180+
" if indent(a:lnum + 1) == 0 && next_line !~ s:blank_regex && next_line !~ s:docstring_general_regex
181+
" if s:Is_opening_folding(a:lnum)
182+
" let l:foldcase = 'case 1'
183+
" let l:foldlevel = '='
184+
" return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
185+
" else
186+
" let l:foldcase = 'case 2'
187+
" let l:foldlevel = 0
188+
" return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
189+
" endif
190+
" endif
191+
" let l:foldcase = 'case 3'
192+
" let l:foldlevel = -1
193+
" return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
194+
" else
195+
" let l:foldcase = 'case 4'
196+
" let l:foldlevel = '='
197+
" return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
198+
" endif
144199
endif " }}}
145200

146-
return '='
201+
return {'foldcase': l:foldcase, 'foldlevel': l:foldlevel}
147202

148203
endfunction "}}}
149204

150-
fun! s:BlockStart(line_number) "{{{
205+
fun! s:BlockStart(lnum) "{{{
151206
" Returns the definition statement which encloses the current line.
152207

208+
let line = getline(a:lnum)
209+
if line !~ s:blank_regex
210+
let l:inferred_indent = indent(a:lnum)
211+
else
212+
let l:inferred_indent = prevnonblank(a:lnum)
213+
endif
214+
153215
" Note: Make sure to reset cursor position after using this function.
154-
call cursor(a:line_number, 0)
216+
call cursor(a:lnum, 0)
155217

156218
" In case the end of the block is indented to a higher level than the def
157219
" statement plus one shiftwidth, we need to find the indent level at the
@@ -162,7 +224,9 @@ fun! s:BlockStart(line_number) "{{{
162224
" W: don't Wrap around the end of the file
163225
let previous_definition = searchpos(s:def_regex, 'bnW')
164226
if previous_definition != [0, 0]
165-
while previous_definition != [0, 0] && indent(previous_definition[0]) >= indent(a:line_number)
227+
" Lines that are blank have zero indent.
228+
while previous_definition != [0, 0]
229+
\ && indent(previous_definition[0]) >= l:inferred_indent
166230
let previous_definition = searchpos(s:def_regex, 'bnW')
167231
call cursor(previous_definition[0] - 1, 0)
168232
endwhile
@@ -179,13 +243,15 @@ fun! s:BlockStart(line_number) "{{{
179243

180244
" Now find the class/def one shiftwidth lower than the start of the
181245
" aforementioned indent block.
182-
if next_stmt_at_def_indent && next_stmt_at_def_indent < a:line_number
246+
if next_stmt_at_def_indent && (next_stmt_at_def_indent < a:lnum)
183247
let max_indent = max([indent(next_stmt_at_def_indent) - &shiftwidth, 0])
184248
else
185-
let max_indent = max([indent(prevnonblank(a:line_number)) - &shiftwidth, 0])
249+
let max_indent = max([indent(prevnonblank(a:lnum)) - &shiftwidth, 0])
186250
endif
187251

188-
return searchpos('\v^\s{,'.max_indent.'}(def |class )\w', 'bcnW')[0]
252+
let result = searchpos('\v^\s{,'.max_indent.'}(def |class )\w', 'bcnW')[0]
253+
254+
return result
189255

190256
endfunction "}}}
191257
function! Blockstart(x)
@@ -206,56 +272,55 @@ function! Blockend(lnum)
206272
endfunction
207273

208274
function! s:Is_opening_folding(lnum) "{{{
209-
" Helper function to see if docstring is opening or closing
275+
" Helper function to see if multi line docstring is opening or closing.
210276

211-
" Cache the result so the loop runs only once per change
277+
" Cache the result so the loop runs only once per change.
212278
if get(b:, 'fold_changenr', -1) == changenr()
213-
return b:fold_cache[a:lnum] "If odd then it is an opening
279+
return b:fold_cache[a:lnum - 1] "If odd then it is an opening
214280
else
215281
let b:fold_changenr = changenr()
216282
let b:fold_cache = []
217283
endif
218284

219-
let number_of_folding = 0 " To be analized if odd/even to inform if it is opening or closing.
220-
let has_open_docstring = 0 " To inform is already has an open docstring.
221-
let extra_docstrings = 0 " To help skipping ''' and """ which are not docstrings
285+
" To be analized if odd/even to inform if it is opening or closing.
286+
let fold_odd_even = 0
287+
" To inform is already has an open docstring.
288+
let has_open_docstring = 0
289+
" To help skipping ''' and """ which are not docstrings.
290+
let extra_docstrings = 0
222291

223292
" The idea of this part of the function is to identify real docstrings and
224293
" not just triple quotes (that could be a regular string).
225-
"
294+
226295
" Iterater over all lines from the start until current line (inclusive)
227296
for i in range(1, line('$'))
228-
call add(b:fold_cache, number_of_folding % 2)
229297

230298
let i_line = getline(i)
231299

232-
if i_line =~ s:docstring_line_regex
233-
continue
234-
endif
235-
236300
if i_line =~ s:docstring_begin_regex && ! has_open_docstring
237301
" This causes the loop to continue if there is a triple quote which
238302
" is not a docstring.
239303
if extra_docstrings > 0
240304
let extra_docstrings = extra_docstrings - 1
241-
continue
242305
else
243306
let has_open_docstring = 1
244-
let number_of_folding = number_of_folding + 1
307+
let fold_odd_even = fold_odd_even + 1
245308
endif
246309
" If it is an end doc and has an open docstring.
247310
elseif i_line =~ s:docstring_end_regex && has_open_docstring
248311
let has_open_docstring = 0
249-
let number_of_folding = number_of_folding + 1
312+
let fold_odd_even = fold_odd_even + 1
250313

251314
elseif i_line =~ s:docstring_general_regex
252315
let extra_docstrings = extra_docstrings + 1
253316
endif
254-
endfor
255317

256-
call add(b:fold_cache, number_of_folding % 2)
318+
call add(b:fold_cache, fold_odd_even % 2)
319+
320+
endfor
257321

258322
return b:fold_cache[a:lnum]
323+
259324
endfunction "}}}
260325

261326
" vim: fdm=marker:fdl=0

autoload/pymode/run.vim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ fun! pymode#run#code_run(line1, line2) "{{{
7474

7575
cgetexpr(l:traceback)
7676

77-
" If a range is run (starting other than at line 1), fix the reported error line numbers for
78-
" the current buffer
77+
" If a range is run (starting other than at line 1), fix the reported
78+
" error line numbers for the current buffer
7979
if a:line1 > 1
8080
let qflist = getqflist()
8181
for i in qflist

plugin/pymode.vim

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
" vi: fdl=1
22
let g:pymode_version = "0.9.4"
33

4-
com! PymodeVersion echomsg "Current python-mode version: " . g:pymode_version
5-
64
" Enable pymode by default :)
75
call pymode#default('g:pymode', 1)
86
call pymode#default('g:pymode_debug', 0)
@@ -42,6 +40,7 @@ call pymode#default("g:pymode_folding", 1)
4240
call pymode#default("g:pymode_folding_nest_limit", 1000)
4341
" Change for folding customization (by example enable fold for 'if', 'for')
4442
call pymode#default("g:pymode_folding_regex", '^\s*\%(class\|def\|async\s\+def\) .\+\(:\s\+\w\)\@!')
43+
" call pymode#default("g:pymode_folding_regex", '^\s*\%(class\|def\|async\s\+def\)')
4544

4645
" Enable/disable python motion operators
4746
call pymode#default("g:pymode_motion", 1)
@@ -315,7 +314,6 @@ else
315314

316315
endif
317316

318-
319317
command! PymodeVersion echomsg "Pymode version: " . g:pymode_version . " interpreter: " . g:pymode_python . " lint: " . g:pymode_lint . " rope: " . g:pymode_rope
320318

321319
augroup pymode

tests/old/docs.vim

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)