1

I'm trying to use :'<,'>s!^!// ! to comment out highlighted code in visual mode. Is it possible to edit the regex so that it uncomments the code if it is already commented?

anoncoder
  • 68
  • 4

4 Answers4

1

A dirty but very versatile trick I use is to exploit the :normal command, that will emulate keystroke sequence you give on the given range.

For instance, to comment, select your whole lines in visual mode (using V) and enter the command :

:normal i//

This is quiet self-explanatory : i open edit mode, and // writes it (because you entered edit mode); the command will be applied to every selected line, with the cursor positioned to the beginning of the line (because we selected whole lines with V and not v; it gets tricky otherwise). With the same idea, you can remove the commenting on a visual selection using :

:normal xx

(This does exactly what it says : deletes the first two characters, as you would type on your keyboard).

There is several pros for this approach, including :

  • If you use several different languages with different comment signs ({ , /*, //, #, %) , it's just a matter of changing a single strokes.
  • You can really get creative with the normal command, since you can exploit marks for the command's range, and literally do anything :

    :normal A //Hello world

  • Again, it feels very natural because you are simply feeding a command with the keystroke you would have used on your selection. You can even switch between modes using this trick.

Community
  • 1
  • 1
Bertrand Caron
  • 2,525
  • 2
  • 22
  • 49
1

Some of the other answers mention plugins. I currently use NERD commenter, which provides a ci (comment invert) command that does what you want.

For starters, here are a couple of ways to avoid commenting out lines that are already commented. For simplicity, I will assume that the comment characters are all in the first column. Either one accepts a range, such as the Visual range '<,'> in your question.

:s#^\(// \)\@!#// #
:v#^// #s!^!// !

OK, if you really want a single command that toggles whether a line is commented out, then you have to capture whether the line is initially commented and then replace with an expression:

:%s!^\(// \|\)!\=strpart('// ', strlen(submatch(1)))

 

:help /\(
:help /\@!
:help :g
:help sub-replace-expression
benjifisher
  • 5,054
  • 16
  • 18
  • Thanks, that command does exactly what I want, though I've decided to use a plugin as suggested by several of the answers. – anoncoder Jan 30 '14 at 00:58
0

well, I doubt you can do it using only one regex, and that's why Tim Pope has written an extension exactly for that:

then all you have to do is gc to comment a line or a visual selection, and gc to uncomment it!

zmo
  • 24,463
  • 4
  • 54
  • 90
0

There are several plugins that work to comment and uncomment code across multiple languages. That being said, you would probably want to use two separate regexes in this case. For example, say I have some code...

var x = 5;

// Does stuff 5 times
for ( var i = 0; i < x; i++ ) {
  // stuff
}

When I run said regex on this I don't want the already commented lines to be uncommented. So it's better to do something similar, but in reverse (e.g. :'<,'>s!^// !!).

Also, the \ze and \zs operators can be useful here to preserve whitespace. And :* is a shortcut for :'<,'>. For instance I could do

:*s!^\s*\zs// !!

This will remove only the characters // from lines that start with them or with whitespace before them.

Conner
  • 30,144
  • 8
  • 52
  • 73