Commenting c++ codes in Vim

2019-05-26 03:50发布

问题:

I want to map \c to comment the current line in vim (add '// ' to before the first non-blank to the line) and \d to delete the '// ' at the beginning of line(uncomment).

I've added these two lines in my vimrc:

imap \c <Esc>:s/^/\/\/ <CR>j$a

imap \d <Esc>:s/^\/\/ /<CR>j$a

but when I call this in this line:

    for (int i = 0; i < n; i++)

then it is converted to:

//    for (int i = 0; i < n; i++)

but I want to convert it to:

    // for (int i = 0; i < n; i++)

one of the reasons I want this is that when I want vim to indent this line, it will add an extra tab at the beginning of the line and convert it to:

    //    for (int i = 0; i < n; i++)

what should I do? I thought that ^ refers to first non-blank character of line but it wasn't true.

P.S: I've found these two commands, but I don't know what are they doing. could you please explain them to me (because I need to remember them and they're easier to remember when I know what are they). if any part of them is unnecessary please tell me:

imap \c <ESC>:s,^\(\s*\)[^/ \t]\@=,\1// ,e<CR>j$a

imap \d <ESC>:s,^\(\s*\)// \s\@!,\1,e<CR>j$a

回答1:

About those commands you found:

imap \c :s,^(\s*)[^# \t]\@=,\1// ,ej$a

Let's start with the pattern match, comparing it with your :s/^/\/\/ <CR>j$a.

  • :s, is exactly equivalent to :s/ - you can choose a nonstandard seperator where it makes the expression more readable, so here using , instead of / means less escaping, and no confusion between the comment // and the seperator
  • ^(\s*) matches the beginning of the line (same as yours) and any leading whitespace, capturing the whitespace so we can reuse it later
  • [^# \t]\@= just requires some character other than space, tab or # before the line end, but doesn't capture it (ie, that character won't be replaced)
  • ,\1// , replaces the matched string with the leading whitespace (\1 is whatever was captured by the (\s*) group) followed by //

For example:

^    void foo();

should match like so: ^(\s*)[^# \t]\@= -> ^( )(v@=)void foo();, ie, the first group matches the leading whitespace, and the next expression matches but doesn't consume the v from void. Then, \1// expands to:

^    // 

and the final substitution result is:

^    // void foo();`

(I've marked the start of line with ^ since the indentation is ambiguous otherwise)



回答2:

Even though the ^ normal mode command goes to the first non-blank, ^ in a pattern (so in the :s, :g, :v, :sort commands) means start of line. See :help /^

Use I to insert at first non-blank, and A to append after last character.

Use:

inoremap \c <c-o>I//<esc>jA
inoremap \d <esc>^2xjA

There are, however, good plugins that do the job. commentary by Tim Pope, or the NERD Commenter. See their documentation.



回答3:

I recommend using the Enhanced Commentify plugin. You can then add this to your ~/.vimrc file:

let g:EnhCommentifyRespectIndent = 'yes'

and it will give you the behaviour you are after. In visual mode, select the area of code that you want to comment and then type \c. To uncomment use \C.