Wikia

Vim Tips Wiki

Changes: Automatic Commenting of Preprocessor Directives in C

Edit

Back to page

(Adjust previous/next navigation)
(Change <tt> to <code>, perhaps also minor tweak.)
 
Line 3: Line 3:
 
|previous=1536
 
|previous=1536
 
|next=1539
 
|next=1539
|created=December 5, 2007
+
|created=2007
 
|complexity=intermediate
 
|complexity=intermediate
 
|author=A. S. Budden
 
|author=A. S. Budden
Line 11: Line 11:
 
|category2=C
 
|category2=C
 
}}
 
}}
When the preprocessor directives <tt>#if</tt>, <tt>#ifdef</tt>, <tt>#elif</tt>, <tt>#else</tt> and <tt>#endif</tt> are used extensively in source code, it can be extremely valuable to have comments on the <tt>#else</tt> and <tt>#endif</tt> lines to make the code clearer.
+
When the preprocessor directives <code>#if</code>, <code>#ifdef</code>, <code>#elif</code>, <code>#else</code> and <code>#endif</code> are used extensively in source code, it can be extremely valuable to have comments on the <code>#else</code> and <code>#endif</code> lines to make the code clearer.
   
 
For example:
 
For example:
Line 21: Line 21:
 
</pre>
 
</pre>
   
With multiple levels of <tt>#if</tt>s, this can simplify the code considerably (particularly with the addition of comments on the <tt>#else</tt> lines. The function below can be used to automate this process. It will also highlight (with a comment containing 'XXX') any inaccurate comments (for example a <tt>/* def DEBUG */</tt> linked to a <tt>#ifndef DEBUG</tt>).
+
With multiple levels of <code>#if</code>s, this can simplify the code considerably (particularly with the addition of comments on the <code>#else</code> lines. The function below can be used to automate this process. It will also highlight (with a comment containing 'XXX') any inaccurate comments (for example a <code>/* def DEBUG */</code> linked to a <code>#ifndef DEBUG</code>).
   
 
A more advanced version of this code, with a (slightly buggy) Brace Commenter as well, is available as a plugin from http://sites.google.com/site/abudden/Vim-Scripts/smart-brace--preprocessor-commenting
 
A more advanced version of this code, with a (slightly buggy) Brace Commenter as well, is available as a plugin from http://sites.google.com/site/abudden/Vim-Scripts/smart-brace--preprocessor-commenting

Latest revision as of 06:31, July 13, 2012

Tip 1538 Printable Monobook Previous Next

created 2007 · complexity intermediate · author A. S. Budden · version 7.0


When the preprocessor directives #if, #ifdef, #elif, #else and #endif are used extensively in source code, it can be extremely valuable to have comments on the #else and #endif lines to make the code clearer.

For example:

#ifdef DEBUG
    /* Only execute this if debugging */
    printf("Example debug output\n");
#endif /* def DEBUG */

With multiple levels of #ifs, this can simplify the code considerably (particularly with the addition of comments on the #else lines. The function below can be used to automate this process. It will also highlight (with a comment containing 'XXX') any inaccurate comments (for example a /* def DEBUG */ linked to a #ifndef DEBUG).

A more advanced version of this code, with a (slightly buggy) Brace Commenter as well, is available as a plugin from http://sites.google.com/site/abudden/Vim-Scripts/smart-brace--preprocessor-commenting

" Commenting of #endifs etc
" Author: Ben Schmidt, minor modifications by A. S. Budden.
command SmartPreProcCommenter call SmartPreProcCommenter()

function! SmartPreProcCommenter()
  mark y
  let saved_wrapscan=&wrapscan
  set nowrapscan
  let elsecomment=""
  let endcomment=""
  try
    " Find the last #if in the buffer
    $?^\s*#if
    while 1
      " Build the comments for later use, based on current line
      let content=getline('.')
      let elsecomment=BuildElseComment(content,elsecomment)
      let endcomment=BuildEndComment(content,endcomment)
      " Change # into ## so we know we've already processed this one
      " and don't find it again
      s/^\s*\zs#/##
      " Find the next #else, #elif, #endif which must belong to this #if
      /^\s*#\(elif\|else\|endif\)
      let content=getline('.')
      if match(content,'^\s*#elif') != -1
        " For #elif, treat the same as #if, i.e. build new comments
        continue
      elseif match(content,'^\s*#else') != -1
        " For #else, add/replace the comment
        call setline('.',ReplaceComment(content,elsecomment))
        s/^\s*\zs#/##
        " Find the #endif
        /^\s*#endif
      endif
      " We should be at the #endif now; add/replace the comment
      call setline('.',ReplaceComment(getline('.'),endcomment))
      s/^\s*\zs#/##
      " Find the previous #if
      ?^\s*#if
    endwhile
  catch /search hit TOP/
    " Once we have an error (pattern not found, i.e. no more left)
    " Change all our ## markers back to #
    silent! %s/^\s*\zs##/#
  endtry
  let &wrapscan=saved_wrapscan
  normal `y
endfunc

let s:PreProcCommentMatcher = '#\a\+\s\+\zs.\{-}\ze\(\s*\/\*.\{-}\*\/\)\?\s*$'

function! BuildElseComment(content,previous)
  let expression=escape(matchstr(a:content,s:PreProcCommentMatcher), '\~&')
  if match(a:content,'#ifdef') != -1
    return "/* NOT def ".expression." */"
  elseif match(a:content,'#ifndef') != -1
    return "/* def ".expression." */"
  elseif match(a:content,'#if') != -1
    return "/* NOT ".expression." */"
  elseif match(a:content,'#elif') != -1
    return substitute(a:previous,' \*/',', '.expression.' */','')
  else
    return ""
  endif
endfunc

function! BuildEndComment(content,previous)
  let expression=escape(matchstr(a:content,s:PreProcCommentMatcher), '\~&')
  if match(a:content,'#ifdef') != -1
    return "/* def ".expression." */"
  elseif match(a:content,'#ifndef') != -1
    return "/* NOT def ".expression." */"
  elseif match(a:content,'#if') != -1
    return "/* ".expression." */"
  elseif match(a:content,'#elif') != -1
    return substitute(a:previous,' \*/',', '.expression.' */','')
  else
    return ""
  endif
endfunc

function! ReplaceComment(content,comment)
  let existing=escape(matchstr(a:content,'#\a\+\s\+\zs.\{-}\s*$'), '\~&')
  if existing == ""
    return substitute(a:content,'^\s*#\a\+\zs.*'," ".a:comment,'')
  elseif existing != a:comment && match(existing,'XXX') == -1
    return a:content." /* XXX */"
  else
    return a:content
  endif
endfunc

CommentsEdit

Around Wikia's network

Random Wiki