Tuesday, October 7, 2008

Vim Code Folding

This is the sixth post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

Visual Studio has a feature called "Outlining" which automatically allows you to collapse and expand regions, comments, methods, classes, namespaces, using statement blocks, etc. Ctrl+M, Ctrl+M will expand and collapse the block that your cursor is in. Ctrl+M, Ctrl+O will collapse all methods and summary comments (but not classes and namespaces).

Vim has this same ability built in but calls it Folding. The difference is simply that it has to be turned on if you want it, and that it doesn't understand your code as well as Visual Studio does (though it can be taught!).

In Vim, there are a number of different ways that folding can be done: syntax based, indent based, marker based, and manual. Syntax based looks for folding to be defined in the syntax file for the language being edited. Indent based folds lines that are at the same indent level. Marker based looks for a given character sequence and folders everything between those characters. Manual allows you to define where the folds should be.

I like to use the Syntax folding that's defined in the default Vim C# syntax file. This will fold #region ... #endregion blocks.

To make sure this is always on when I'm editing C# files I added the following to my vimrc:
if !exists("autocommands_loaded")
let autocommands_loaded = 1

" setup folding
autocmd BufNewFile,BufRead *.cs set foldmethod=syntax
endif

Note: if you've setup an autocmd for C# building as in my earlier post make sure you use the same if !exists()... block.

The following commands are used to open and close folds:
zo - open fold under cursor
zc - close fold under cursor
zR - open all folds
zM - close all folds

You can remember the "z" by thinking of those old accordion reams of paper where each sheet was connected to the next and imagining it from the side as you lift and lower the top sheet. From that profile the paper will appear to form a "z" as you fold and unfold it.

See :help fold.txt for more details.

4 comments:

  1. Thanks for all of these posts. I have just started using Vim and I did all my work in Visual Studio up until this point.

    This works great to get regions to fold. However I also enjoy folding brackets. Is there a way to do both at the same time?

    ReplyDelete
  2. Thanks for the comment!

    I don't think there is any way to have Vim use two folding modes at the same time. But I asked on the Vim IRC channel and was directed to this: http://pastebin.com/md0bd305

    Basically, what you can do is define your folding brackets as syntax elements, like what a vim syntax file does. To get this code to execute you'll have to either put it in a file in Vim's "after" directory, or define an autocommand in your vimrc.

    With this, the syntax fold mode should now fold {{{ just like marker mode. But don't hold me to it, I haven't tried it...

    ReplyDelete
  3. Much better folding here that doesn't just depend upon regions and is more VS like:

    " Folding : http://vim.wikia.com/wiki/Syntax-based_folding, see comment by Ostrygen au FileType cs set omnifunc=syntaxcomplete#Complete
    au FileType cs set foldmethod=marker
    au FileType cs set foldmarker={,}
    au FileType cs set foldtext=substitute(getline(v:foldstart),'{.*','{...}',)
    au FileType cs set foldlevelstart=2

    The above stolen from here:
    http://arun.wordpress.com/2009/04/10/c-and-vim/

    ReplyDelete
  4. Ali, thanks for the example
    I've deleted the line
    au FileType cs set foldtext=substitute(getline(v:foldstart),'{.*','{...}',)
    reason:
    When the above line is active, if you had a lines like
    public void myfunc(){
    // some code
    }
    it will fold all of it i.e. you will see
    +-- 3 lines: ------
    when I delete the line it will show
    +-- 3 lines: public void myfunc()----------------------
    which is much better, I think.

    ReplyDelete