2

I have the following file

#
#
NODE  / 11000001       1009.6809       -878.9679        316.3049
NODE  / 11000001       1009.6809       -878.9679        316.3049
NODE  / 11000001       1009.6809       -878.9679        316.3049
NODE  / 11000001       1009.6809       -878.9679        316.3049

I'd like to fold it using the foldexpr method (I tried syntax, but I have other requirements that for now keep me from pursuing that further). There should be 2 folds, one containing the first 2 lines, a second containing the other. If need be, I'd be ok with a third fold containing the other two, but I'd like it better if this could be avoided.

:h fold-expr refers to :h fold-indent for using foldlevels:

A sequence of lines with the same or higher fold level form a fold, with the lines with a higher level forming a nested fold.

So, as far as I can see, I need to have the first 2 lines the same foldlevel, as well as lines 3-6. But lines 1-2 need a higher foldlevel, so the fold for lines 1-2 fold does not include lines 3-6. I can achieve that in the following way

set foldexpr=GetPamFold(v:lnum)

function! GetPamFold(lnum)
  let linestr = getline(a:lnum)

  if linestr =~ '^NODE'
    return '2'
  elseif linestr =~ '^#'
    return '3'
  endif

  return '0'

I can check the foldlevels via echom foldlevel(1) and such, and it works as expected.

What does not work is the folding itself. I get 2 folds: 1 containing the first 2 lines (good), and a second containing the first fold and lines 3-6. That's bad. Also, both those folds are each contained in another fold that ONLY contains the other fold, i.e. trivially folds the 1 line (e.g. the folded lines 1-2) into one line. Really bad.

To clarify:

  • Fold1 contains lines 1-2
  • Fold2 contains Fold1
  • Fold3 contains Fold2 and lines 3-6
  • Fold4 contains Fold3

As far as I can see, it's not what the docs say what would happen. What am I missing? What can I do to achieve my folds?

I'm using vim 7.4. Thanks for any pointers!

5

I would do it like this:

  • A new fold starts (>1) if the current line starts with one of the keywords and the previous line has no / a different keyword.
  • Else, if the current line starts with one of the keywords, keep the fold level (1, or =), else no fold.

Implementation

set foldexpr=GetPamFold(v:lnum)
function! GetPamFold(lnum)
  let current  = matchstr(getline(a:lnum), '^\(NODE\|#\)')
  let previous = matchstr(getline(a:lnum - 1), '^\(NODE\|#\)')

  return ! empty(current) && current != previous ? '>1' : (empty(current) ? 0 : 1)
endfunction
  • That does work, thank you! I just can't figure out why... everything gets a fold level of 1 in my example, so there should just be one fold containing all the lines, right? Why does it do what I want? – PhilippFrank Apr 16 '15 at 12:41
  • 1
    The trick is the >1, which instructs Vim to start a new fold (even if the level is the same as on the line before). – Ingo Karkat Apr 16 '15 at 13:15
  • Oh ok, I did not see that this is possible in foldexpr. Thanks! – PhilippFrank Apr 16 '15 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.