Thursday, December 27, 2012

Re: Fold expression called too often

On 12/23/12, Ben Fritz <fritzophrenic@gmail.com> wrote:
> On Saturday, December 22, 2012 5:18:39 PM UTC-6, Marco wrote:
>> Hi,
>>
>> I tried to create a custom fold expression for a file type. The
>> folding works as desired, but it makes vim terribly slow. Commands
>> like "gwip" to format the current paragraph take more than ten
>> seconds on a modern machine. Thanks to Drew [1] I heard about the
>> possibility to profile my expression and was surprised that it was
>> called millions of times for a file containing just a few dozen
>> lines.
>>
>> I created a simple test expression and it is also called way more
>> often than I would expect. Here my test case:
>>
>> " file: test
>> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
>> eirmod
>> tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
>> voluptua. At
>> vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
>> gubergren,
>> no sea takimata sanctus est Lorem ipsum dolor sit amet.
>> " endfile
>>
>> " file: myfold.vim
>> function! MyFolds()
>> let thisline = getline(v:lnum)
>>
>> if match(thisline, 'start') >= 0
>> return "a1"
>> elseif match(thisline, 'stop') >= 0
>> return "s1"
>> else
>> return "="
>> endfunction
>>
>> setlocal foldmethod=expr
>> setlocal foldexpr=MyFolds()
>>
>> function! TextManip()
>> normal gwip
>> endfunction
>>
>> call TextManip()
>> " endfile
>>
>>
>> [snip]
>>
>>
>> The test file contains just four lines. Why is it called 52 times?
>>
>> And what can I do about that?
>>
>
> From :help fold-expr:
>
>> Try to avoid the "=", "a" and "s" return values, since Vim often has to
>> search
>> backwards for a line for which the fold level is defined. This can be
>> slow.
>
> The problem is that Vim calls your foldexpr once for every line, but for
> each line using =, a, or s, it must call it recursively on the previous line
> to get the foldlevel of that line, which calls it recursively again to get
> the previous line for its own foldlevel, etc. where the recursion only ends
> when a foldlevel is defined explicitly (at the first line in the file).

I don't think there is anything wrong with the OP's original simple
folding expression. It should not cause recursion because it returns
something for every line. The problem, as Christian noted in another
post, is that "gwip" is performed in many steps and each step triggers
folding update.


> To avoid this you could store foldlevels of previous lines in a lookup table
> internally to your function, and look up the foldlevel from your variable if
> present, or using the foldlevel() function instead of returning =, a, and s
> items. A few of these items are OK as long as Vim doesn't need to scan the
> entire file recursively for every single line.


Out of curiosity, I decided to write a folding expression that does
the same thing without using a1, s1, =.
It's not as easy as it may seem. The problem is that folding update
does not always start on line 1 and ends on the last buffer line. I
posted my solution at
https://gist.github.com/4390083

I am optimistic that it works most of the time. It definitely works
when outline is created for the first time and during wholesale
updates. It's possible that there are some special cases of partial
folding updates during editing when it fails.

If it works, then it has other applications, such as ignoring folds in
fenced regions.

Regards,
Vlad

--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

No comments: