9

I've noticed that vim's fold method affects the efficiency of autocomplete, e.g. C-N is slow, and C-X L is hideously slow in medium sized files with relatively expensive foldexprs.

I can't see the value in having foldexpr consulted while running through auto completes, so would like to disable this somehow so I get usable autocomplete back.

Any suggestions?


EDIT: Test case

A test case: No plugins; and only this, which must be the most minimal foldexpr function possible (and is completely useless, except for counting invocations) in .vimrc:

let g:c = 0 
function! Myfoldexpr() 
   let g:c = 1 + g:c 
   return '0' 
endfunction

Now start vim with a blank document. We'll copy the first 100 lines of Vim's own help file, and then run autocomplete line, choosing the 10th suggestion, then see how many times foldexpr was called.

:help
y100j:q
P:set foldexpr=Myfoldexpr()
:set fdm=expr
O<C-X><C-L><C-L><C-L><C-L><C-L><C-L><C-L><C-L><C-L><C-L><Esc>
:echo g:c
2088

Now that's a 100 line file, with relatively short lines and the foldexpr was called 2088 times (although 100 of these are done when first setting the foldexpr). Efficient foldexpr is obviously good, but we programmers ask a lot of our foldexpr, so they are necessarily non-trivial, and when their execution time is multiplied by several thousand it makes you choose between autocomplete or indent for productivity. Being greedy/lazy I'd like to be able to use both! Beyond attempting to rewrite several pretty well established foldexpr-based folding plugins (I've tried rewriting php-folding and after days of trying to optimise it to a workable state I gave up on foldexpr for php), perhaps there's a way to use a mapping to turn fdm=manual before autocomplete or some such?

artfulrobot
  • 601
  • 5
  • 13
  • Have you considered posting to the vim_dev list? – lcd047 Apr 30 '15 at 10:05
  • I'll post anything useful back here, but here's the vim_dev list posting – artfulrobot May 01 '15 at 13:00
  • I think your test case is wrong. If I make a test file, and add some text (by just doing iHello<Esc>, the g:c variable is also increased to 20, then doing oWorld<Esc> makes it 38 ... So the number of evaluations foldexpr seems unrelated to using completion... Try loading Vim with a minimal vimrc file and see if the problem still occurs, it could be another setting or a plugin. – Martin Tournoij May 01 '15 at 15:56
  • "I can't see the value in having foldexpr consulted while running through auto completes, " well, you're inserting text; so Vim needs to re-calculate which lines to fold. – Martin Tournoij May 01 '15 at 16:10
  • The test case is deliberately stupid, returning =. But just from the order of magnitude you can see something is up. On 2nd comment, Yeah, but I think it should do that at the end of an insert candidate (like it does for p), I think what it's doing is doing it per character of the insert candidate. – artfulrobot May 01 '15 at 16:21
  • @artfulrobot I don't see that "anything is up"? I get similar numbers without using completion... It seems like a feature to me, if I type a { or } (for example), this might influence folding, and you usually want that to happen immediately... If it didn't, we'd have people here complaining about the delay in showing folds ;-) In any case, I suspect the real problem here is that your foldexpr is too slow/complicated; once you've verified there isn't another setting or plugin in the way, you should probably post your foldexpr and a test file, so we can have a look at that... – Martin Tournoij May 01 '15 at 16:27
  • As I suspected: "Right, it's actually worse than that: the entire folding is redone at every key press." From the dev list. Workarounds below look like the way forward! – artfulrobot May 01 '15 at 22:00

2 Answers2

5

I had a problem a while back with syntax folding PHP where typing { would interfere with subsequent folds until I typed the corresponding closing }. I found a suggestion somewhere (I think it was on the Vim Wiki) to temporarily set the foldmethod to manual while in insert mode. I don't know if this is à propos enough to make an answer rather than a comment, but code in comments is discouraged and possibly you can adapt it for your circumstances. Here are the two relevant lines from my .vimrc.

autocmd InsertEnter * if !exists('w:last_fdm') | let w:last_fdm=&foldmethod | setlocal foldmethod=manual | endif
autocmd InsertLeave,WinLeave * if exists('w:last_fdm') | let &l:foldmethod=w:last_fdm | unlet w:last_fdm | endif
jjaderberg
  • 3,489
  • 1
  • 14
  • 19
2

perhaps there's a way to use a mapping to turn fdm=manual before autocomplete or some such?

Well, this does that:

inoremap <C-x> <Esc>:setlocal foldmethod=manual<CR>a<C-x>
autocmd CompleteDone * :setlocal foldmethod=expr
autocmd InsertLeave * :setlocal foldmethod=expr

We remap <C-x> to first set the foldmethod to manual before calling <C-x>, and with the CompleteDone and InsertLeave autocommands we reset it to expr.

I tested this by pressing <C-l> 11 times; my g:c values:

  • After Vim startup: 202
  • With this hack: 408
  • Without this hack: 2130

As I've said in the comments: this hack shouldn't be required. You mentioned "relatively expensive foldexprs", I suspect that this is the real problem; I can't be sure of course, because you didn't post your foldexpr, but I think it's worth asking a new question about this ("How can I make this foldexpr faster?").

Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
  • Thanks, will try this. As for specific foldexpr see https://github.com/tmhedberg/SimpylFold for python, and https://github.com/swekaj/php-foldexpr.vim for php. But yes, we both agree that's another question! – artfulrobot May 01 '15 at 18:32
  • @artfulrobot The Python foldexpr is also quite slow for me... I'm not sure this can be improved on in this specific case, so this work-around might be best here :-/ Not sure why the PHP foldexpr is required? Can't the syntax file do that (this is usually faster) – Martin Tournoij May 01 '15 at 18:59