vim

How do I implement a function to replace C comments from // to /* */ (in uppercase)?


I am trying to write a function to replace comments in C using:

// Comment

into

/* COMMENT */.

This is what I have tried:

function! ANSIC89()
    :%s/\/\/\(.*\)/\/\* \1 \*\//g
endfunction

This replaces:

  7 // Dataset Structure 
  8 typedef struct {
  9     int num_bars;            // Number of bars
 10     int *data;               // Data array
 11     int *x_values;           // X positions of bars 
 12     unsigned long color;     // Bar color 
 13 } Dataset;

Into:

  7 /* Dataset Structure  */
  8 typedef struct {
  9     int num_bars;            /* Number of bars */
 10     int *data;               /* Data array */
 11     int *x_values;           /* X positions of bars  */
 12     unsigned long color;     /* Bar color  */
 13 } Dataset;

But I do not know how to make them uppercase (I am not sure if this can be actually done with regex at all).


Solution

  • Building on M.E.'s answer, there are some points for simplifications and improvements that are beyond the scope (and restrictions) of comments.

    The :substitute command can be further simplified to

    :%s@//\s*\(.*\)@/* \U\1 */@
    

    which uses @ as separator and cuts off any kind of whitespace (space and tabs) using the \s pattern. The comments contents itself is captured using a simple greedy match all .* .

    If you want the result to be really beautiful and make sure there's exactly one space between comment and the closing */, you can use the slightly more complicated

    :%s@//\s*\(.\{-}\)\s*$@/* \U\1 */@
    

    This captures non-greedily using the \{-} multi. It is followed by any number of whitespace \s*, anchored to the end of line $.

    All of the above is explained in :help pattern.

    There's a user-defined function in the question and unless there's a good reason to use one, I'd suggest to use a mapping or a user-defined command. A simple one-liner rarely warrants a function.

    Instead, map e.g. your F2 key:

    :nnoremap <buffer> <F2> :%s@//\s*\(.\{-}\)\s*$@/* \U\1 */@<CR>
    

    Or define a user-command you can call with :ANSIC89:

    :command -buffer -bar -range=% ANSIC89 <line1>,<line2>s@//\s*\(.\{-}\)\s*$@/* \U\1 */@
    

    The above will work on a range of lines, defaulting to the whole buffer. See :help :command-range. The -bar argument allows to follow with another command, e.g. :ANSIC89 | write. See :help user-commands for reference.

    Both the mapping and the command are defined as buffer-local so they exist only when editing C files. You can put them in ~/.vim/after/ftplugin/c.vim.