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
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)
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.
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
.