1

I think I do not have a very clear idea of the use case for foldmethod=expr, so for folding my C,C++ and Verilog code for which I use use the following indentations:

C,C++

if (a_condition) {
  // a code
} else if ((b_condition) || 
           (c_condition)) {
  // b or c code
} else {
  // code
}

Verilog

if (a_condition) begin
   // a_code
end else if ((b_condition) || 
            (c_condition)) begin
   // b or c code
end else begin
   // code
end

I have written the following functions which seem to fit my needs, given set foldmethod=manual:

C,C++ fold

function! Fold()

   call search('{')
   let l:stline = line('.')+1
   normal! %
   let l:fnline = line('.')-1
   silent! exec ":".l:stline.",".l:fnline."fold"
   silent! exec ":".l:stline
   normal! zz

endfunction

Verilog fold

function! Fold()

   let l:diff = 0
   let l:cLine = line('.')
   let l:itLine = l:cLine
   let l:lastLine = line('$')

   while l:itLine != l:lastLine

      let l:beginCnt = count(getline(l:itLine), 'begin')
      let l:beginIdx = stridx(getline(l:itLine), 'begin')
      let l:endCnt = count(getline(l:itLine), 'end')
      let l:endIdx = stridx(getline(l:itLine), 'end')
      let l:commIdx = stridx(getline(l:itLine), '//')

      " begin
      if l:beginCnt > 0 && l:endCnt == 0
         if (l:commIdx == -1) || (l:beginIdx < l:commIdx)
            let l:diff = l:diff + 1
         end
      " end
      elseif l:endCnt > 0 && l:beginCnt == 0
         if (l:commIdx == -1) || (l:endIdx < l:commIdx)
            let l:diff = l:diff - 1
         end
      " end else begin
      elseif l:beginCnt > 0 && l:endCnt > 0
         if (l:commIdx == -1)
            if l:diff == 1
               let l:diff = l:diff - 1
            endif
         else
            " end else begin //
            if (l:beginIdx < l:commIdx) && (l:endIdx < l:commIdx)
               if l:diff == 1
                  let l:diff = l:diff - 1
               endif
            endif
         endif
      endif

      " echo getline(l:itLine)." --- l:diff = ".l:diff
      if l:diff == 0
         break
      endif
      let l:itLine = l:itLine+1
   endwhile

   if (l:itLine > l:cLine)
      let l:cLine = l:cLine+1
      let l:itLine = l:itLine-1
      " echom ":".l:cLine.",".l:itLine."fold"
      silent! exec ":".l:cLine.",".l:itLine."fold"
   endif

   normal! zz

endfunction

Do these functions can be implemented more efficiently and|or with less code lines using the foldmethod=expr? If so, what is the right way to do it?

3
  • 1
    I’m going to walk-back your edit: I would encourage you to post that information in an answer! (You can retrieve the content from the edit history.)
    – D. Ben Knoble
    Commented Sep 27 at 15:25
  • 1
    RE: foldcolumn, you might like github.com/benknoble/vim-auto-origami
    – D. Ben Knoble
    Commented Sep 27 at 15:28
  • Thanks, it seems that it minimizes the foldcolumn focusing only on what can be folded. I like it!
    – simzz
    Commented Sep 27 at 20:49

2 Answers 2

1

The purpose of foldemethod=expr and foldexpr is not to increase performance but rather to automate the process.

The good think with your foldmethod=manual approach is that you can decide to have:

  • A routine that setup folds
  • Continue to setup folds manual if you like

The problem is that when you edit your code the folds needs to be updated. It seems to me that your code is only adding folds. If you remove some { the corresponding fold will not be removed unless you remove all the folds and re-run your method (but then you lose your manual fold). There are not trivial ways to have both automatic folds constantly updated and manual folds together.

1
  • 1
    Let's say that I don't want automatic folding upon opening buffer, but I prefer to manually fold the blocks. The possible removal of { is not a problem, in that case if there is a syntax error the compiler will advertise it, and if it's not a syntax error the unfolding is straightforward, even if could be nicer having it done automatically in this case, but we cannot have everything in this life.
    – simzz
    Commented Sep 27 at 10:03
1

It turns that playing with these functions has been a waste of time...

The same behavior (except for the cursor position to trigger the folding) can be achieved with:

set foldmethod=indent

and folding with zc in normal mode. So to fold:

if (a_condition) {
    < cursor anywhere here in indented area 
      and hit zc >
    // a code
} else if ((b_condition) || 
           (c_condition)) {
    // b or c code
} else {
    // code
}

The foldcolumn option is AWESOME.

To have all the folds open upon opening a buffer (as I like to be):

autocmd BufEnter,BufRead * normal! zR

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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