Sunday, December 23, 2012

Re: Fold expression called too often

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).

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.

--
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: