Slow
Closed this issue · 7 comments
Even opening moderately small files can cause up to a second lag.
Here's the timings for opening the file "seaborn/categorical.py" from the popular Python plotting package Seaborn. Per the documentation (:help profile), the "self" time will be wrong since SimpylFold is called recursively.
FUNCTION SimpylFold()
Called 6982 times
Total time: 0.809100
Self time: 0.360778
count total (s) self (s)
" If we are starting a new sweep of the buffer (i.e. the current line
" being folded comes before the previous line that was folded), initialize
" the cache of results of calls to `s:NumContainingDefs`
6982 0.016330 if !exists('b:last_folded_line') || b:last_folded_line > a:lnum
50 0.000235 let b:cache_NumContainingDefs = {}
50 0.000052 let b:in_docstring = 0
50 0.000013 endif
6982 0.008365 let b:last_folded_line = a:lnum
" If this line is blank, its fold level is equal to the minimum of its
" neighbors' fold levels, but if the next line begins a definition, then
" this line should fold at one level below the next
6982 0.010268 let line = getline(a:lnum)
6982 0.024489 if line =~ s:blank_regex
1944 0.003536 let next_line = nextnonblank(a:lnum)
1944 0.001479 if next_line == 0
return 0
elseif getline(next_line) =~# s:def_regex
168 0.000292 return SimpylFold(next_line) - 1
else
1776 0.001048 return -1
endif
endif
5038 0.013018 let fold_docstrings = !exists('g:SimpylFold_fold_docstring') || g:SimpylFold_fold_docstring
5038 0.031019 let docstring_match = matchlist(line, s:docstring_start_regex)
5038 0.009477 let prev_line = getline(a:lnum - 1)
5038 0.033692 if !b:in_docstring && ( prev_line =~# s:def_regex || prev_line =~ s:multiline_def_end_regex ) && len(docstring_match)
4 0.000179 0.000013 let this_fl = s:NumContainingDefs(a:lnum) + fold_docstrings
4 0.000004 let b:in_docstring = 1
4 0.000006 if docstring_match[1] == '"""'
4 0.000008 let b:docstring_end_regex = s:docstring_end_double_regex
4 0.000001 else
let b:docstring_end_regex = s:docstring_end_single_regex
endif
4 0.000003 elseif b:in_docstring
10 0.000444 0.000036 let this_fl = s:NumContainingDefs(a:lnum) + fold_docstrings
10 0.000036 if line =~ b:docstring_end_regex
4 0.000006 let b:in_docstring = 0
4 0.000002 endif
10 0.000005 else
" Otherwise, its fold level is equal to its number of containing
" definitions, plus 1, if this line starts a definition of its own
5024 0.385522 0.035029 let this_fl = s:NumContainingDefs(a:lnum) + (line =~# s:def_regex)
5024 0.002473 endif
" If the very next line starts a definition with the same fold level as
" this one, explicitly indicate that a fold ends here
5038 0.024561 if getline(a:lnum + 1) =~# s:def_regex && SimpylFold(a:lnum + 1) == this_fl
return '<' . this_fl
else
5038 0.003546 return this_fl
endif
FUNCTION <SNR>103_NumContainingDefs()
Called 6380 times
Total time: 0.356571
Self time: 0.351067
count total (s) self (s)
" Recall memoized result if it exists in the cache
6380 0.011093 if has_key(b:cache_NumContainingDefs, a:lnum)
1382 0.001994 return b:cache_NumContainingDefs[a:lnum]
endif
4998 0.007690 let this_ind = indent(a:lnum)
4998 0.003350 if this_ind == 0
250 0.000129 return 0
endif
" Walk backwards to the previous non-blank line with a lower indent level
" than this line
4748 0.005298 let i = a:lnum - 1
15716 0.006771 while 1
15716 0.060302 if getline(i) !~ s:blank_regex
11524 0.014986 let i_ind = indent(i)
11524 0.008927 if i_ind < this_ind
1342 0.002669 let ncd = s:NumContainingDefs(i) + (getline(i) =~# s:def_regex)
1342 0.000836 break
elseif i_ind == this_ind && has_key(b:cache_NumContainingDefs, i)
3406 0.005980 let ncd = b:cache_NumContainingDefs[i]
3406 0.001698 break
endif
6776 0.002618 endif
10968 0.008147 let i -= 1
" If we hit the beginning of the buffer before finding a line with a
" lower indent level, there must be no definitions containing this
" line. This explicit check is required to prevent infinite looping in
" the syntactically invalid pathological case in which the first line
" or lines has an indent level greater than 0.
10968 0.005700 if i <= 1
let ncd = getline(1) =~# s:def_regex
break
endif
10968 0.004633 endwhile
" Memoize the return value to avoid duplication of effort on subsequent
" lines
4748 0.010655 let b:cache_NumContainingDefs[a:lnum] = ncd
4748 0.003551 return ncd
Recently i was working with long multi-line lists (3000+ lines) in python files, search and replacing, adding deleting. Working with text blocks of this size while having SimpylFold makes undo
unusable. In a "normal" workflow this goes unnoticed and it took me a while to narrow it down.
it is very easy to reproduce:
- copy
print "test"
3000x :%s/$/ "other string"/
u
- wait wait wait
I confirm that it is very slow with long python file
The current work-around solution for me, while editing the file, is to disable folding.
With a 100 line file if I toggle all the lines to comments MacVim will hang for nearly 10 seconds.
I corroborate the slowness remarks, but honestly I've had the same problem with other folding plugin (for other languages) I've come across and have come to expect it as inherent. Have you ever seen really fast folding in vim?
What I ended up doing is using Pathogen to install SimpylFold then run vim without folding when I'm editing (VIMBLACKLIST=SimpylFold vim
) and with folding when I'm browsing/reading... not ideal but practical.
The built-in indent foldmethod is pretty quick even for large files:
autocmd BufEnter * :if line('$') > 1000 | set foldmethod=indent | endif
This prevents the hanging when loading/entering a large buffer, while still providing some form of folding.
foldmethod=indent foldlevel=1 foldnestmax=2
works rather well and it's quick.
perhaps not as nice as SimpylFold, but no lags and got used to it very quickly.