Wednesday, January 6, 2010

Re: #ifdef block's color

> > From: vim_use@googlegroups.com [mailto:vim_use@googlegroups.com] On Behalf
> > Of ext Gusman
> > Subject: #ifdef block's color
> >
> > Dear All,
> >
> > Currently I'am working with a big source code in C language which have many
> > #ifdef directives in there. It's so difficult for me to read the code flow
> > while I can't determine which #ifdef is defined or not defined.
> >
> > Is there plugin can make undefined #ifdef code block same as #if 0 code
> > block.

2010/1/6 Marczis, Peter (NSN - HU/Budapest) <peter.marczis@nsn.com>:
> Hi,
> I think you can modify the c syntax file, in $VIMRUNTIME\syntax\c.vim.
> There are more region definition, but you will find the IF 0 definition, you
> should mod, that regexp to match #if  instead...

You'll need to parse your tags file to work out what all the defined
names are (a bit like the way the ctags highlighter works [1]). You
can then generate a list of tags and do something like this (I'll
leave ParseTagsFileForDefines( ) to you for now...):

let list_of_defined_names = ParseTagsFileForDefines()
" Returns a list like ['NDEBUG', 'ANOTHER_DEFINE', 'DEFINED_NAME_2']
let list_of_defined_names = ['NDEBUG', 'ANOTHER_DEFINE', 'DEFINED_NAME_2']

let start_if_regexp = '^\s*\(%:\|#\)\s*ifdef\s\+\('
let start_ifn_regexp = '^\s*\(%:\|#\)\s*ifndef\s\+\('

for item in other_list
let start_if_regexp .= '\<' . item . '\>'
let start_if_regexp .= '\|'

let start_ifn_regexp .= '\<' . item . '\>'
let start_ifn_regexp .= '\|'
endfor

" Strip the trailing | and replace it with )
let start_if_regexp = start_if_regexp[0:len(start_if_regexp)-2] . ')'
let start_ifn_regexp = start_ifn_regexp[0:len(start_ifn_regexp)-2] . ')'

" Add a negative look-ahead and end-of-line catching
let start_if_regexp .= '\@!\(\k\{-}\)\s*$'
let start_ifn_regexp .= '\s*$'

" We now have #ifdef (NDEBUG|ANOTHER_DEFINE|DEFINED_NAME_2)\@!
" and a #ifndef (NDEBUG|ANOTHER_DEFINE|DEFINED_NAME_2)
" with escaped brackets and word protection (\<, \>)

" Make it work
exe 'syn region cCppIFDEFNotDefined start="' . start_if_regexp .
'" end=".\@=\|$" contains=cCppNotDefined2'
exe 'syn region cCppIFNDEFNotDefined start="' . start_ifn_regexp .
'" end=".\@=\|$" contains=cCppNotDefined2'

" Add the catch for the end of the region
syn region cCppNotDefined2 contained start="\k\+\s*$"
end="^\s*\(%:\|#\)\s*\(endif\>\|else\>\|elif\>\)"
contains=cSpaceError,cCppSkip
hi link cCppIFDEFNotDefined Comment
hi link cCppIFNDEFNotDefined Comment
hi link cCppNotDefined2 cCppIFDEFNotDefined

" Optional: if you use rainbow.vim you may need this:
syn cluster cBracketGroup
add=cCppIFDEFNotDefined,cCppIFNDEFNotDefined,cCppNotDefined2
syn cluster cCppBracketGroup
add=cCppIFDEFNotDefined,cCppIFNDEFNotDefined,cCppNotDefined2
syn cluster cCurlyGroup
add=cCppIFDEFNotDefined,cCppIFNDEFNotDefined,cCppNotDefined2
syn cluster cParenGroup
add=cCppIFDEFNotDefined,cCppIFNDEFNotDefined,cCppNotDefined2
syn cluster cCppParenGroup
add=cCppIFDEFNotDefined,cCppIFNDEFNotDefined,cCppNotDefined2


The biggest problem that you'll have is that if there are a lot of
defined names in your tags file, it'll do one of two things:

1) Slow down vim so much that it's unusable (as it'll be a really
complicated regexp)
2) Give an error message due to the pattern being too long.

There may be a better way of doing this (Eclipse can do this after
all, so I'd hope Vim can), but I don't know what it is...

Al

[1] http://sites.google.com/site/abudden/contents/Vim-Scripts/ctags-highlighting

--
http://sites.google.com/site/abudden

No comments: