Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two fold methods at the same time

Tags:

vim

folding

I'd like to set two methods for folding

  1. :set foldmethod=indent and retain all its features
  2. hiding comments with

    :set foldmethod=marker

    :set foldmarker=/*,*/

I found out that this is not possible. Is it possible to achieve the desired folding and set this in .vimrc or to use some script or plugin for this?

like image 402
xralf Avatar asked May 11 '11 20:05

xralf


2 Answers

Syntax-based folding may be a better way to get what you want than the expr-based method I suggested in different answer to your question. Check :h fold-syn for more info. I think there may be some good solutions already out there for c-based folding. Don't know how good it is, but here is a c-syntax file with support for syntax-based folding: http://www.vim.org/scripts/script.php?script_id=234 and another: http://www.vim.org/scripts/script.php?script_id=925

The solutions above are entirely syntax-based, don't involve using indents to determine fold levels. But you could modify syntax-based folding to do the main folding by indented regions if you wanted. If you indent based on syntactical elements the result might be the same anyway.

Here's a tip that shows how to just fold c-style comments (not the actual code) http://vim.wikia.com/wiki/Fold_C-style_comments

like image 55
Herbert Sitz Avatar answered Nov 08 '22 11:11

Herbert Sitz


I have the same requests as yours, here is my not perfect solution

my maker pair is #<=== and #===> (or #region and #endregion as in pycharm)

let b:inBlock=0
let b:lastLineNum=0
let b:lastLevel=0
let b:lastGoodLine=0
let b:lastGoodBlock=0
let b:startFoldingMark='^\s*.\?#<==*\|^\s*.\?#region'
let b:endFoldingMark='^\s*.\?#=*=>\|^\s*.\?#endregion'
function! MyFold(linenum)
    let linetext = getline(a:linenum)
    let level     = indent(a:linenum)   / &shiftwidth
    "the first line have 0 fold level
    if (a:linenum == 1)
        if linetext =~ b:startFoldingMark
            let b:inBlock = 1
            let b:lastLineNum=a:linenum
            let b:lastGoodLine=0
            let b:lastGoodBlock=0
            let b:lastLevel=level
            return level
        endif
        let b:inBlock=0
        let b:lastInBlock=0
        let b:lastLineNum=a:linenum
        let b:lastGoodLine=0
        let b:lastGoodBlock=b:inBlock
        let b:lastLevel=level + b:inBlock
        return level + b:inBlock
    endif

    " not calculate from the mid of text
    if ((b:lastLineNum+1) != a:linenum)
        let level     = indent(a:linenum)   / &shiftwidth
        let lastGoodNum = a:linenum-1
        while (lastGoodNum>1 && getline(lastGoodNum) =~? '\v^\s*$' )
            let lastGoodNum -= 1
        endwhile
        if  (foldlevel(lastGoodNum)==-1)
            let b:inBlock=b:lastGoodBlock
        else
            let lastlevel = indent(lastGoodNum)   / &shiftwidth
            let lastlinetext = getline(lastGoodNum)
            let lastlinelevel = foldlevel(lastGoodNum)
            if lastlinetext =~ b:startFoldingMark
                let b:inBlock = lastlinelevel - lastlevel + 1
            elseif lastlinetext =~ b:endFoldingMark
                let b:inBlock = lastlinelevel - lastlevel - 1
            else
                let b:inBlock = lastlinelevel - lastlevel
            endif
        endif
    endif

    "blank lines have undefined fold level
    if getline(a:linenum) =~? '\v^\s*$'
        let b:lastLineNum=a:linenum
        let b:lastLevel=-1
        return -1
    endif

    "if next line is a start of new marker block, inBlock ++
    if linetext =~ b:startFoldingMark
        let b:lastLineNum=a:linenum
        if (b:lastLevel != -1)
            let b:lastGoodLine=a:linenum
            let b:lastGoodBlock=b:inBlock
        endif
        let b:lastLevel=level + b:inBlock - 1
        return level + b:inBlock - 1
    "if next line is an end of new marker block, inBlock -
    elseif linetext =~ b:endFoldingMark
        let b:inBlock = b:inBlock - 1
        let b:lastLineNum=a:linenum
        let b:lastGoodLine=a:linenum
        let b:lastGoodBlock=b:inBlock
        let b:lastLevel=level + b:inBlock + 1
        return level + b:inBlock + 1
    endif

    let b:lastLineNum=a:linenum
    if (b:lastLevel != -1)
        let b:lastGoodLine=a:linenum
        let b:lastGoodBlock=b:inBlock
    endif
    let b:lastLevel=level + b:inBlock
    return level+b:inBlock
endfunction

now, i can keep all the features when using indent fold method, and i can fold each #<=, #=> marker block, also, the lines' indent folding relations are still kept in each block.

In this function, i avoid using "a1", "s1" and "=" level, which will cause iteration for this function and may be slow for large files. However, when you update lines, the calculation of fold level may be incorrect (because vim may not update all fold level from beginning, and thus have incorrect inBlock value)

you can use zx to update fold levels manually.

see more at https://github.com/Fmajor/configs

like image 33
Major F Avatar answered Nov 08 '22 12:11

Major F