I'm trying to set up folding for #pragma region in C/C++, and it kinda works, but I need to edit out #pragma from the cPreProc syntax region, which is definitely not ideal. If I don't edit it out, the regions don't stop at their corresponding endmarker, instead just fold to the last one.

This is the line I'm using in an after/syntax file:

syntax region cPragmaRegion start=/#pragma region/ end=/#pragma endregion/ fold transparent contains=ALL

Edit: This should look like this:

#pragma region Region1
#pragma region Region2
#pragma endregion
#pragma endregion

Should fold into this:

#pragma region Region1
Fold here for Region2
#pragma endregion

Instead it looks like

#pragma region Region1
Fold here for Region 2
  • Welcome to Vi and Vim! It’s a bit unclear (to me at least) what you’re trying to accomplish and what’s wrong. Could you add some examples (text and screenshots, in this case), and maybe provide some more detail/context? For example, you talk about editing the cPreProc region—what do you mean by this? Please edit – D. Ben Knoble Jan 24 at 14:28
  • Edited, the cPreProc is a region defined in the default c.vim syntax file – GorbitGames Jan 24 at 16:59

While using Vim's syntax engine for folding is very powerful and can be very convenient for syntax-aware folding, it's really hard to extend an existing syntax definition with new syntax, since creating new syntax matches and regions tends to affect how other syntax elements are recognized, so it tends to produce ripple effects on existing syntax, which seems to be what you've just experienced.

In cases like yours, it's probably much better to define folding separate from syntax, by using a different fold method.

One quick way to fold your #pragma region is to use those expressions themselves as fold markers. There are a few limitations to that, such as the string will be matched anywhere in the line (not only in the beginning), it requires the whitespace to be exact (so it wouldn't recognize the word pragma indented after a # in the first column) and it won't match a word boundary at the end of the string.

But maybe that's good enough? If this pragmatic solution fits your needs, then all you need is:

setlocal foldmarker=#pragma\ region,#pragma\ endregion
setlocal foldmethod=marker

A better solution is to use a function to implement a fold expression, in which case you can do a full string match using a regular expression to properly recognize all corner cases.

function! FoldPragmaRegion(lnum)
  let l = getline(a:lnum)
  if l =~# '^#\s*pragma\s\+region\>'
    return 'a1'
  elseif l =~# '^#\s*pragma\s\+endregion\>'
    return 's1'
    return -1
setlocal foldexpr=FoldPragmaRegion(v:lnum)
setlocal foldmethod=expr

See :help fold-expr for details on the specific return values for this function. Note that the function is not limited to inspecting the specific line, or the specific line's contents only. You could write loops to find blank lines above or below it, look for other pragmas or directives and even check for syntax groups applied to characters in the current line (which can be really helpful to determine whether a specific region is inside of a comment, for instance.)

Hopefully you'll find these suggestions useful and a good solution to implement the desired folding without having to mess with the syntax rules.

syn region cPragmaRegion start=/#pragma region/ end=/#pragma endregion/ fold transparent keepend extend

Adding keepend and extend options does the trick

(I cannot explain properly why, because I'll probably never understand when and what effects those two options have)

  • what effects those two options have Actually, it would work without any options unless... there's cPreProc that also matches #pragma endregion and prevents cPragmaRegion from ever ending. Only for this reason cPragmaRegion needs keepend to keep line "endregion" for itself. Then extend is easy: without it you got region1-3 and then "keepend" locks line2 inside it. So "extend" actually means "override any keepend and make external region to grow". – Matt May 5 at 21:41

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.