views:

207

answers:

1

I'm looking for a way to highlight the code block currently under the cursor while in normal mode.

This would work kinda like the set showmatch config options does, but the detection and highlighting would stretch over the entire block.

Any way to achieve this functionality either with config options or a (preferably existing) script ?

A: 

Short answer: no.

Long answer: there are ways to achieve this, but you'll have to sacrifice a lot of other fairly essential highlighting features.

There is certainly no way to do it with a simple option. The problem that you may come across is that Vim doesn't allow overlapping regions, so if you have rainbow.vim installed or anything else that makes a region in the area of your block, it's lost. It's also difficult (although I'd welcome any corrections) to have multiple highlighted groups, so one that sets the background colour and another that sets the foreground. This is very limiting as you'll see.

However, if fancy playing around, read on.

I'm making the assumption here that you're using C code in the same coding style as me, but this could easily be changed...

Here's a simple function that should help show you what's involved:

function! HighlightBlock()
    " Search backwards and forwards for an opening and closing brace
    " at the start of the line (change this according to your coding
    " style or how you define a block).
    let startmatch = search('^{', 'bcnW')
    let endmatch = search('^}', 'cnW')

    " Search in the other direction for each to catch the situation
    " where we're in between blocks.
    let checkstart = search('^{', 'cnW')
    let checkend = search('^}', 'bcnW')

    " Clear BlockRegion if it exists already (requires Vim 7 probably)
    try
     syn clear BlockRegion
    catch
    endtry

    " If we're not in a block, give up
    if ((startmatch < checkstart) && (endmatch > checkstart))
       \ || ((startmatch < checkend) && (endmatch > checkend))
       \ || (startmatch == 0)
       \ || (endmatch == 0)
     return
    endif

    " Create a new syntax region called "BlockRegion" that starts
    " on the specific lines found above (see :help \%l for more 
    " information).
    exec 'syn region BlockRegion'
       \ 'start=' . '"\%' . startmatch . 'l"'
       \ 'end='   . '"\%' . (endmatch+1)   . 'l"'

    " Add "contains=ALL" onto the end for a different way of 
    " highlighting, but it's not much better...

    " Define the colours - not an ideal place to do this,
    " but good for an example
    if &background == 'light'
     hi default BlockRegion guibg='#AAAAAA'
    else
     hi default BlockRegion guibg='#333333'
    endif

endfunction

To use the function, source it from somewhere and then create an autocmd to call it whenever something changes, e.g.

au CursorMoved *.c call HighlightBlock()

See the following for some autocommands you may want to consider:

:help CursorHold
:help CursorHoldI
:help CursorMoved
:help CursorMovedI
Al
Good writeup, i get the idea even if your code doesn't quite work with my style (doing js).
julien
Aha: I couldn't work that out from your question. I believe that js uses braces, so if you don't mind it only highlighting inner blocks when you're inside one, you could probably just get rid of the `^` and `$` in the four search lines... probably academic though, given the problems I highlighted (pun intended).
Al